compute: migrate/resize paths properly handle stashed numa_topology

This patch makes the migrate and resize code paths in the compute
service take advantage of the now stashed data in the context_migration
field of the instance to apply the claimed NUMA topology to the instance
and provision it (and to potentially revert back to the old one on the
source host)

Change-Id: Ib91f211e87c1770c1997b3b8ff01d55092c896bf
Partial-bug: #1417667
Related-blueprint: migration-fix-resource-tracking
This commit is contained in:
Nikola Dipanov 2015-08-28 23:23:02 +01:00
parent c458921729
commit a298455398
3 changed files with 50 additions and 3 deletions

View File

@ -3448,6 +3448,16 @@ class ComputeManager(manager.Manager):
with migration.obj_as_admin():
migration.save()
# NOTE(ndipanov): We need to do this here because dropping the
# claim means we lose the migration_context data. We really should
# fix this by moving the drop_move_claim call to the
# finish_revert_resize method as this is racy (revert is dropped,
# but instance resources will be tracked with the new flavor until
# it gets rolled back in finish_revert_resize, which is
# potentially wrong for a period of time).
instance.revert_migration_context()
instance.save()
rt = self._get_resource_tracker(instance.node)
rt.drop_move_claim(context, instance)
@ -3788,6 +3798,7 @@ class ComputeManager(manager.Manager):
if old_instance_type[key] != instance_type[key]:
resize_instance = True
break
instance.apply_migration_context()
# NOTE(tr3buchet): setup networks on destination host
self.network_api.setup_networks_on_host(context, instance,

View File

@ -84,6 +84,7 @@ from nova.tests.unit import fake_server_actions
from nova.tests.unit.image import fake as fake_image
from nova.tests.unit import matchers
from nova.tests.unit.objects import test_flavor
from nova.tests.unit.objects import test_instance_numa_topology
from nova.tests.unit.objects import test_migration
from nova.tests.unit import utils as test_utils
from nova import utils
@ -5148,7 +5149,7 @@ class ComputeTestCase(BaseTestCase):
def test_resize_instance_forced_shutdown(self):
self._test_resize_instance(clean_shutdown=False)
def _test_confirm_resize(self, power_on):
def _test_confirm_resize(self, power_on, numa_topology=None):
# Common test case method for confirm_resize
def fake(*args, **kwargs):
pass
@ -5188,6 +5189,7 @@ class ComputeTestCase(BaseTestCase):
instance.vm_state = old_vm_state
instance.power_state = p_state
instance.numa_topology = numa_topology
instance.save()
new_instance_type_ref = flavors.get_flavor_by_flavor_id(3)
@ -5200,6 +5202,11 @@ class ComputeTestCase(BaseTestCase):
migration = objects.Migration.get_by_instance_and_status(
self.context.elevated(),
instance.uuid, 'pre-migrating')
migration_context = objects.MigrationContext.get_by_instance_uuid(
self.context.elevated(), instance.uuid)
self.assertIsInstance(migration_context.old_numa_topology,
numa_topology.__class__)
self.assertIsNone(migration_context.new_numa_topology)
# NOTE(mriedem): ensure prep_resize set old_vm_state in system_metadata
sys_meta = instance.system_metadata
@ -5220,6 +5227,9 @@ class ComputeTestCase(BaseTestCase):
instance_type_ref = db.flavor_get(self.context,
instance.instance_type_id)
self.assertEqual(instance_type_ref['flavorid'], '3')
# Prove that the NUMA topology has also been updated to that of the new
# flavor - meaning None
self.assertIsNone(instance.numa_topology)
# Finally, confirm the resize and verify the new flavor is applied
instance.task_state = None
@ -5236,6 +5246,7 @@ class ComputeTestCase(BaseTestCase):
self.assertEqual('fake-mini', migration.source_compute)
self.assertEqual(old_vm_state, instance.vm_state)
self.assertIsNone(instance.task_state)
self.assertIsNone(instance.migration_context)
self.assertEqual(p_state, instance.power_state)
self.compute.terminate_instance(self.context, instance, [], [])
@ -5245,8 +5256,15 @@ class ComputeTestCase(BaseTestCase):
def test_confirm_resize_from_stopped(self):
self._test_confirm_resize(power_on=False)
def test_confirm_resize_with_migration_context(self):
numa_topology = (
test_instance_numa_topology.get_fake_obj_numa_topology(
self.context))
self._test_confirm_resize(power_on=True, numa_topology=numa_topology)
def _test_finish_revert_resize(self, power_on,
remove_old_vm_state=False):
remove_old_vm_state=False,
numa_topology=None):
"""Convenience method that does most of the work for the
test_finish_revert_resize tests.
:param power_on -- True if testing resize from ACTIVE state, False if
@ -5291,6 +5309,7 @@ class ComputeTestCase(BaseTestCase):
instance.host = 'foo'
instance.vm_state = old_vm_state
instance.numa_topology = numa_topology
instance.save()
new_instance_type_ref = flavors.get_flavor_by_flavor_id(3)
@ -5304,6 +5323,10 @@ class ComputeTestCase(BaseTestCase):
migration = objects.Migration.get_by_instance_and_status(
self.context.elevated(),
instance.uuid, 'pre-migrating')
migration_context = objects.MigrationContext.get_by_instance_uuid(
self.context.elevated(), instance.uuid)
self.assertIsInstance(migration_context.old_numa_topology,
numa_topology.__class__)
# NOTE(mriedem): ensure prep_resize set old_vm_state in system_metadata
sys_meta = instance.system_metadata
@ -5323,6 +5346,9 @@ class ComputeTestCase(BaseTestCase):
# Prove that the instance size is now the new size
instance_type_ref = flavors.get_flavor_by_flavor_id(3)
self.assertEqual(instance_type_ref['flavorid'], '3')
# Prove that the NUMA topology has also been updated to that of the new
# flavor - meaning None
self.assertIsNone(instance.numa_topology)
instance.task_state = task_states.RESIZE_REVERTING
instance.save()
@ -5352,6 +5378,7 @@ class ComputeTestCase(BaseTestCase):
self.assertEqual(instance_type_ref['flavorid'], '1')
self.assertEqual(instance.host, migration.source_compute)
self.assertEqual(migration.dest_compute, migration.source_compute)
self.assertIsInstance(instance.numa_topology, numa_topology.__class__)
if remove_old_vm_state:
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
@ -5371,6 +5398,13 @@ class ComputeTestCase(BaseTestCase):
self._test_finish_revert_resize(power_on=False,
remove_old_vm_state=True)
def test_finish_revert_resize_migration_context(self):
numa_topology = (
test_instance_numa_topology.get_fake_obj_numa_topology(
self.context))
self._test_finish_revert_resize(power_on=True,
numa_topology=numa_topology)
def _test_cleanup_stored_instance_types(self, old, new, revert=False):
instance = self._create_fake_instance_obj()
instance.system_metadata = dict(instance_type_id=old)

View File

@ -3972,6 +3972,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
# revert_resize() and the return value is passed to driver.destroy().
# Otherwise we could regress this.
@mock.patch.object(self.instance, 'revert_migration_context')
@mock.patch.object(self.compute.network_api, 'get_instance_nw_info')
@mock.patch.object(self.compute, '_is_instance_storage_shared')
@mock.patch.object(self.compute, 'finish_revert_resize')
@ -3994,7 +3995,8 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
_instance_update,
finish_revert_resize,
_is_instance_storage_shared,
get_instance_nw_info):
get_instance_nw_info,
revert_migration_context):
self.migration.source_compute = self.instance['host']