Fix image-defined numa claims during evacuate

When evacuating, the API does not send the image_ref
to the compute so currently the compute manager
rebuild_instance() method will just pass an empty
dict for image_meta to the rebuild_claim, which means
if the server was originally created with an image that
has numa-related constraints, like hw_numa_nodes, those
constraints would not be applied to the destination host
during the evacuate.

This change simply checks for evacuate if image_ref is
not provided and pulls the image_meta off the instance
which was stashed in the instance.system_metadata during
server create (see get_system_metadata_from_image usage
in the compute API).

This fix was ported from the starlingx-staging/stx-nova
repo commit 71acfeae0.

Change-Id: If548fa3436174b1eae08cdcf6578020cc0c7b81f
Closes-Bug: #1785318
This commit is contained in:
Matt Riedemann 2018-08-03 16:54:49 -04:00
parent 9d546732c8
commit 665ba461f3
3 changed files with 22 additions and 4 deletions

View File

@ -2984,6 +2984,12 @@ class ComputeManager(manager.Manager):
image_meta = {}
if image_ref:
image_meta = self.image_api.get(context, image_ref)
elif evacuate:
# For evacuate the API does not send down the image_ref since the
# image does not change so just get it from what was stashed in
# the instance system_metadata when the instance was created (or
# last rebuilt). This also works for volume-backed instances.
image_meta = instance.image_meta
# NOTE(mriedem): On an evacuate, we need to update
# the instance's host and node properties to reflect it's

View File

@ -12661,6 +12661,7 @@ class EvacuateHostTestCase(BaseTestCase):
super(EvacuateHostTestCase, self).setUp()
self.inst = self._create_fake_instance_obj(
{'host': 'fake_host_2', 'node': 'fakenode2'})
self.inst.system_metadata = {}
self.inst.task_state = task_states.REBUILDING
self.inst.save()
@ -12941,10 +12942,8 @@ class EvacuateHostTestCase(BaseTestCase):
block_device_info=mock.ANY)
@mock.patch.object(fake.FakeDriver, 'spawn')
@mock.patch('nova.objects.Instance.image_meta',
new_callable=mock.PropertyMock)
def test_on_shared_storage_not_provided_host_with_shared_storage(self,
mock_image_meta, mock_spawn):
mock_spawn):
self.stub_out('nova.virt.fake.FakeDriver.instance_on_disk',
lambda *a, **ka: True)
@ -12953,7 +12952,7 @@ class EvacuateHostTestCase(BaseTestCase):
mock_spawn.assert_called_once_with(
test.MatchType(context.RequestContext),
test.MatchType(objects.Instance),
mock_image_meta.return_value,
test.MatchType(objects.ImageMeta),
mock.ANY, 'newpass', mock.ANY,
network_info=mock.ANY,
block_device_info=mock.ANY)

View File

@ -4150,6 +4150,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
mock_elevated):
mock_elevated.return_value = self.context
instance = fake_instance.fake_instance_obj(self.context)
instance.system_metadata = {}
ex = test.TestingException('foo')
with mock.patch.object(self.compute, '_get_resource_tracker') as mrt:
self.assertRaises(test.TestingException,
@ -4223,6 +4224,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
mock_instance_fault):
instance = fake_instance.fake_instance_obj(self.context)
instance.info_cache = None
instance.system_metadata = {}
elevated_context = mock.Mock()
mock_context_elevated.return_value = elevated_context
request_spec = objects.RequestSpec()
@ -4266,8 +4268,10 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
def test_rebuild_node_updated_if_recreate(self):
dead_node = uuidutils.generate_uuid()
img_sys_meta = {'image_hw_numa_nodes': 1}
instance = fake_instance.fake_instance_obj(self.context,
node=dead_node)
instance.system_metadata = img_sys_meta
instance.migration_context = None
with test.nested(
mock.patch.object(self.compute, '_get_resource_tracker'),
@ -4284,6 +4288,15 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
self.assertEqual('new-node', instance.node)
mock_set.assert_called_once_with(None, 'done')
mock_rt.assert_called_once_with()
# Make sure the rebuild_claim was called with the proper image_meta
# from the instance.
mock_rebuild_claim = mock_rt.return_value.rebuild_claim
mock_rebuild_claim.assert_called_once()
self.assertIn('image_meta', mock_rebuild_claim.call_args[1])
actual_image_meta = mock_rebuild_claim.call_args[1][
'image_meta'].properties
self.assertIn('hw_numa_nodes', actual_image_meta)
self.assertEqual(1, actual_image_meta.hw_numa_nodes)
@mock.patch.object(compute_utils, 'notify_about_instance_rebuild')
@mock.patch.object(compute_utils, 'notify_usage_exists')