From 879db352773c9d17fdf6895865e84cbeb2bbbbec Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 11 Jul 2018 10:58:31 +1000 Subject: [PATCH] Always set a hardware architecture on uploaded images In a multiarch environment if we have an image that doesn't have an hw_architecture it can be scheduled on any node registered with ironic. So this means that nova could schedule an x86_64 image on a ppc64le node (clearly a bad thing). Avoid that by always setting a hw_architecture image property matching the kernel of the running system. This is safe as in a single arch environment, by definition all nodes are the same ;P and in a multiarch we're being explict, which may result in NoValidHost exceptions which is a much clearer error case than scheduling wrong ISA images. Blueprint: multiarch-support Change-Id: I082dfe34cf192f76f87e348aecb67e984e0c8ae9 --- .../overcloud_image/test_overcloud_image.py | 36 ++++++++++++------- tripleoclient/v1/overcloud_image.py | 3 ++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/tripleoclient/tests/v1/overcloud_image/test_overcloud_image.py b/tripleoclient/tests/v1/overcloud_image/test_overcloud_image.py index 635ab3b95..80c5ef448 100644 --- a/tripleoclient/tests/v1/overcloud_image/test_overcloud_image.py +++ b/tripleoclient/tests/v1/overcloud_image/test_overcloud_image.py @@ -17,6 +17,7 @@ import mock import os from osc_lib import exceptions +import tripleo_common.arch from tripleoclient.tests.v1.test_plugin import TestPluginV1 from tripleoclient.v1 import overcloud_image @@ -120,9 +121,11 @@ class TestUploadOvercloudImage(TestPluginV1): self.cmd = overcloud_image.UploadOvercloudImage(self.app, None) self.app.client_manager.image = mock.Mock() self.app.client_manager.image.version = 2.0 + self._arch = tripleo_common.arch.kernel_arch() self.app.client_manager.image.images.create.return_value = ( - mock.Mock(id=10, name='imgname', properties={'kernel_id': 10, - 'ramdisk_id': 10}, + mock.Mock(id=10, name='imgname', + properties={'kernel_id': 10, 'ramdisk_id': 10, + 'hw_architecture': self._arch}, created_at='2015-07-31T14:37:22.000000')) self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA') self.cmd._check_file_exists = mock.Mock(return_value=True) @@ -286,28 +289,29 @@ class TestUploadOvercloudImage(TestPluginV1): self.app.client_manager.image.images.create.call_count ) self.app.client_manager.image.images.create.assert_has_calls([ - mock.call(properties={}, + mock.call(properties={'hw_architecture': self._arch}, data=b'IMGDATA', name='overcloud-full-vmlinuz', disk_format='aki', is_public=True), - mock.call(properties={}, + mock.call(properties={'hw_architecture': self._arch}, data=b'IMGDATA', name='overcloud-full-initrd', disk_format='ari', is_public=True), - mock.call(properties={'kernel_id': 10, 'ramdisk_id': 10}, + mock.call(properties={'kernel_id': 10, 'ramdisk_id': 10, + 'hw_architecture': self._arch}, name='overcloud-full', data=b'IMGDATA', container_format='bare', disk_format='qcow2', is_public=True), - mock.call(properties={}, + mock.call(properties={'hw_architecture': self._arch}, data=b'IMGDATA', name='bm-deploy-kernel', disk_format='aki', is_public=True), - mock.call(properties={}, + mock.call(properties={'hw_architecture': self._arch}, data=b'IMGDATA', name='bm-deploy-ramdisk', disk_format='ari', @@ -454,7 +458,7 @@ class TestUploadOvercloudImage(TestPluginV1): self.app.client_manager.image.images.create.call_count ) self.assertEqual( - 6, + 10, # 5 for new uploads, 5 updating the existsing self.app.client_manager.image.images.update.call_count ) self.assertEqual(mock_subprocess_call.call_count, 2) @@ -468,8 +472,10 @@ class TestUploadOvercloudImageFull(TestPluginV1): self.cmd = overcloud_image.UploadOvercloudImage(self.app, None) self.app.client_manager.image = mock.Mock() self.app.client_manager.image.version = 2.0 + self._arch = tripleo_common.arch.kernel_arch() self.app.client_manager.image.images.create.return_value = ( - mock.Mock(id=10, name='imgname', properties={}, + mock.Mock(id=10, name='imgname', + properties={'hw_architecture': self._arch}, created_at='2015-07-31T14:37:22.000000')) self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA') self.cmd._check_file_exists = mock.Mock(return_value=True) @@ -508,6 +514,12 @@ class TestUploadOvercloudImageFull(TestPluginV1): container_format='bare', visibility='public') ]) + # properties are set by updating the image + self.app.client_manager.image.images.update.assert_has_calls([ + mock.call(mock.ANY, hw_architecture='x86_64'), + mock.call(mock.ANY, hw_architecture='x86_64'), + mock.call(mock.ANY, hw_architecture='x86_64'), + ]) self.assertEqual(mock_subprocess_call.call_count, 2) mock_subprocess_call.assert_has_calls([ @@ -576,7 +588,7 @@ class TestUploadOvercloudImageFull(TestPluginV1): self.cmd._files_changed = mock.Mock(return_value=True) existing_image = mock.Mock(id=10, name='imgname', - properties={}) + properties={'hw_architecture': self._arch}) self.cmd._get_image = mock.Mock(return_value=existing_image) self.cmd._image_changed = mock.Mock(return_value=True) @@ -604,7 +616,7 @@ class TestUploadOvercloudImageFull(TestPluginV1): self.cmd._files_changed = mock.Mock(return_value=True) existing_image = mock.Mock(id=10, name='imgname', - properties={}, + properties={'hw_architecture': self._arch}, created_at='2015-07-31T14:37:22.000000') self.cmd._get_image = mock.Mock(return_value=existing_image) self.cmd._image_changed = mock.Mock(return_value=True) @@ -622,7 +634,7 @@ class TestUploadOvercloudImageFull(TestPluginV1): self.app.client_manager.image.images.create.call_count ) self.assertEqual( - 3, + 6, # update 3 images *and* add properties to 3 images self.app.client_manager.image.images.update.call_count ) self.assertEqual(mock_subprocess_call.call_count, 2) diff --git a/tripleoclient/v1/overcloud_image.py b/tripleoclient/v1/overcloud_image.py index 2959e782b..ad78ee17d 100644 --- a/tripleoclient/v1/overcloud_image.py +++ b/tripleoclient/v1/overcloud_image.py @@ -25,6 +25,7 @@ from osc_lib import exceptions from osc_lib.i18n import _ from osc_lib import utils from prettytable import PrettyTable +import tripleo_common.arch from tripleo_common.image import build from tripleoclient import command @@ -328,6 +329,8 @@ class UploadOvercloudImage(command.Command): arch = parsed_args.architecture if arch: properties['hw_architecture'] = arch + else: + properties['hw_architecture'] = tripleo_common.arch.kernel_arch() platform = parsed_args.platform if platform: properties['tripleo_platform'] = platform