From 111a852e79f0d9e54228d8e2724dc4183f737397 Mon Sep 17 00:00:00 2001 From: Sylvain Bauza Date: Tue, 9 Feb 2016 12:43:38 +0100 Subject: [PATCH] Provide ReqSpec to live-migrate conductor task Since the RequestSpec object is now persisted in the API layer every time that we start an instance, we can now fetch it from the API DB and pass it thru the ComputeTask API to the conductor so it can directly call the scheduler with it. Partially-Implements: blueprint check-destination-on-migrations Change-Id: I9d6472220b941072eb3f998c949755c967fb71f6 --- nova/compute/api.py | 11 +- nova/conductor/api.py | 10 +- nova/conductor/manager.py | 16 +- nova/conductor/rpcapi.py | 12 +- nova/conductor/tasks/live_migrate.py | 33 ++-- .../api_sample_tests/test_migrate_server.py | 2 +- nova/tests/unit/compute/test_compute.py | 32 ++-- nova/tests/unit/compute/test_compute_api.py | 8 +- nova/tests/unit/compute/test_compute_cells.py | 3 +- .../unit/conductor/tasks/test_live_migrate.py | 154 +++++++----------- 10 files changed, 147 insertions(+), 134 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index c3bf0c1ea5ac..145e675b5824 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -3283,10 +3283,17 @@ class API(base.Base): self._record_action_start(context, instance, instance_actions.LIVE_MIGRATION) - + try: + request_spec = objects.RequestSpec.get_by_instance_uuid( + context, instance.uuid) + except exception.RequestSpecNotFound: + # Some old instances can still have no RequestSpec object attached + # to them, we need to support the old way + request_spec = None self.compute_task_api.live_migrate_instance(context, instance, host_name, block_migration=block_migration, - disk_over_commit=disk_over_commit) + disk_over_commit=disk_over_commit, + request_spec=request_spec) @check_instance_lock @check_instance_cell diff --git a/nova/conductor/api.py b/nova/conductor/api.py index ceca53459fcf..b9be88204a3f 100644 --- a/nova/conductor/api.py +++ b/nova/conductor/api.py @@ -75,11 +75,12 @@ class LocalComputeTaskAPI(object): reservations=reservations, clean_shutdown=clean_shutdown) def live_migrate_instance(self, context, instance, host_name, - block_migration, disk_over_commit): + block_migration, disk_over_commit, + request_spec=None): scheduler_hint = {'host': host_name} self._manager.migrate_server( context, instance, scheduler_hint, True, False, None, - block_migration, disk_over_commit, None) + block_migration, disk_over_commit, None, request_spec=request_spec) def build_instances(self, context, instances, image, filter_properties, admin_password, injected_files, @@ -185,11 +186,12 @@ class ComputeTaskAPI(object): reservations=reservations, clean_shutdown=clean_shutdown) def live_migrate_instance(self, context, instance, host_name, - block_migration, disk_over_commit): + block_migration, disk_over_commit, + request_spec=None): scheduler_hint = {'host': host_name} self.conductor_compute_rpcapi.migrate_server( context, instance, scheduler_hint, True, False, None, - block_migration, disk_over_commit, None) + block_migration, disk_over_commit, None, request_spec=request_spec) def build_instances(self, context, instances, image, filter_properties, admin_password, injected_files, requested_networks, diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index 1bdb97e4c8dc..7eb2aad0d079 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -144,7 +144,7 @@ class ComputeTaskManager(base.Base): may involve coordinating activities on multiple compute nodes. """ - target = messaging.Target(namespace='compute_task', version='1.12') + target = messaging.Target(namespace='compute_task', version='1.13') def __init__(self): super(ComputeTaskManager, self).__init__() @@ -175,7 +175,7 @@ class ComputeTaskManager(base.Base): exception.UnsupportedPolicyException) def migrate_server(self, context, instance, scheduler_hint, live, rebuild, flavor, block_migration, disk_over_commit, reservations=None, - clean_shutdown=True): + clean_shutdown=True, request_spec=None): if instance and not isinstance(instance, nova_object.NovaObject): # NOTE(danms): Until v2 of the RPC API, we need to tolerate # old-world instance objects here @@ -191,7 +191,7 @@ class ComputeTaskManager(base.Base): flavor = objects.Flavor.get_by_id(context, flavor['id']) if live and not rebuild and not flavor: self._live_migrate(context, instance, scheduler_hint, - block_migration, disk_over_commit) + block_migration, disk_over_commit, request_spec) elif not live and not rebuild and flavor: instance_uuid = instance.uuid with compute_utils.EventReporter(context, 'cold_migrate', @@ -272,7 +272,7 @@ class ComputeTaskManager(base.Base): pass def _live_migrate(self, context, instance, scheduler_hint, - block_migration, disk_over_commit): + block_migration, disk_over_commit, request_spec): destination = scheduler_hint.get("host") def _set_vm_state(context, instance, ex, vm_state=None, @@ -304,7 +304,7 @@ class ComputeTaskManager(base.Base): task = self._build_live_migrate_task(context, instance, destination, block_migration, disk_over_commit, - migration) + migration, request_spec) try: task.execute() except (exception.NoValidHost, @@ -337,13 +337,15 @@ class ComputeTaskManager(base.Base): raise exception.MigrationError(reason=six.text_type(ex)) def _build_live_migrate_task(self, context, instance, destination, - block_migration, disk_over_commit, migration): + block_migration, disk_over_commit, migration, + request_spec=None): return live_migrate.LiveMigrationTask(context, instance, destination, block_migration, disk_over_commit, migration, self.compute_rpcapi, self.servicegroup_api, - self.scheduler_client) + self.scheduler_client, + request_spec) def _build_cold_migrate_task(self, context, instance, flavor, filter_properties, request_spec, reservations, diff --git a/nova/conductor/rpcapi.py b/nova/conductor/rpcapi.py index dd502001a72a..5e818a66735b 100644 --- a/nova/conductor/rpcapi.py +++ b/nova/conductor/rpcapi.py @@ -268,6 +268,7 @@ class ComputeTaskAPI(object): 1.10 - Made migrate_server() and build_instances() send flavor objects 1.11 - Added clean_shutdown to migrate_server() 1.12 - Added request_spec to rebuild_instance() + 1.13 - Added request_spec to migrate_server() """ def __init__(self): @@ -280,14 +281,19 @@ class ComputeTaskAPI(object): def migrate_server(self, context, instance, scheduler_hint, live, rebuild, flavor, block_migration, disk_over_commit, - reservations=None, clean_shutdown=True): + reservations=None, clean_shutdown=True, request_spec=None): kw = {'instance': instance, 'scheduler_hint': scheduler_hint, 'live': live, 'rebuild': rebuild, 'flavor': flavor, 'block_migration': block_migration, 'disk_over_commit': disk_over_commit, 'reservations': reservations, - 'clean_shutdown': clean_shutdown} - version = '1.11' + 'clean_shutdown': clean_shutdown, + 'request_spec': request_spec, + } + version = '1.13' + if not self.client.can_send_version(version): + del kw['request_spec'] + version = '1.11' if not self.client.can_send_version(version): del kw['clean_shutdown'] version = '1.10' diff --git a/nova/conductor/tasks/live_migrate.py b/nova/conductor/tasks/live_migrate.py index 9065de278314..93560c2347c2 100644 --- a/nova/conductor/tasks/live_migrate.py +++ b/nova/conductor/tasks/live_migrate.py @@ -38,7 +38,7 @@ CONF.register_opt(migrate_opt) class LiveMigrationTask(base.TaskBase): def __init__(self, context, instance, destination, block_migration, disk_over_commit, migration, compute_rpcapi, - servicegroup_api, scheduler_client): + servicegroup_api, scheduler_client, request_spec=None): super(LiveMigrationTask, self).__init__(context, instance) self.destination = destination self.block_migration = block_migration @@ -50,6 +50,7 @@ class LiveMigrationTask(base.TaskBase): self.compute_rpcapi = compute_rpcapi self.servicegroup_api = servicegroup_api self.scheduler_client = scheduler_client + self.request_spec = request_spec def _execute(self): self._check_instance_is_active() @@ -165,22 +166,32 @@ class LiveMigrationTask(base.TaskBase): attempted_hosts = [self.source] image = utils.get_image_from_system_metadata( self.instance.system_metadata) - request_spec = scheduler_utils.build_request_spec(self.context, image, - [self.instance]) + filter_properties = {'ignore_hosts': attempted_hosts} + # TODO(sbauza): Remove that once setup_instance_group() accepts a + # RequestSpec object + request_spec = {'instance_properties': {'uuid': self.instance.uuid}} + scheduler_utils.setup_instance_group(self.context, request_spec, + filter_properties) + if not self.request_spec: + # NOTE(sbauza): We were unable to find an original RequestSpec + # object - probably because the instance is old. + # We need to mock that the old way + request_spec = objects.RequestSpec.from_components( + self.context, self.instance.uuid, image, + self.instance.flavor, self.instance.numa_topology, + self.instance.pci_requests, + filter_properties, None, self.instance.availability_zone + ) + else: + request_spec = self.request_spec host = None while host is None: self._check_not_over_max_retries(attempted_hosts) - filter_properties = {'ignore_hosts': attempted_hosts} - scheduler_utils.setup_instance_group(self.context, request_spec, - filter_properties) - # TODO(sbauza): Hydrate here the object until we modify the - # scheduler.utils methods to directly use the RequestSpec object - spec_obj = objects.RequestSpec.from_primitives( - self.context, request_spec, filter_properties) + request_spec.ignore_hosts = attempted_hosts try: host = self.scheduler_client.select_destinations(self.context, - spec_obj)[0]['host'] + request_spec)[0]['host'] except messaging.RemoteError as ex: # TODO(ShaoHe Feng) There maybe multi-scheduler, and the # scheduling algorithm is R-R, we can let other scheduler try. diff --git a/nova/tests/functional/api_sample_tests/test_migrate_server.py b/nova/tests/functional/api_sample_tests/test_migrate_server.py index 5a2c6854a0e5..3cb32894d8e9 100644 --- a/nova/tests/functional/api_sample_tests/test_migrate_server.py +++ b/nova/tests/functional/api_sample_tests/test_migrate_server.py @@ -53,7 +53,7 @@ class MigrateServerSamplesJsonTest(test_servers.ServersSampleBase): def test_post_live_migrate_server(self): # Get api samples to server live migrate request. def fake_live_migrate(_self, context, instance, scheduler_hint, - block_migration, disk_over_commit): + block_migration, disk_over_commit, request_spec): self.assertEqual(self.uuid, instance["uuid"]) host = scheduler_hint["host"] self.assertEqual(self.compute.host, host) diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index cc8515cf3183..db7e37ef93da 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -10052,21 +10052,29 @@ class ComputeAPITestCase(BaseTestCase): instance, instance_uuid = self._run_instance() rpcapi = self.compute_api.compute_task_api - self.mox.StubOutWithMock(self.compute_api, '_record_action_start') - self.mox.StubOutWithMock(rpcapi, 'live_migrate_instance') - self.compute_api._record_action_start(self.context, instance, - 'live-migration') - rpcapi.live_migrate_instance(self.context, instance, 'fake_dest_host', - block_migration=True, - disk_over_commit=True) + fake_spec = objects.RequestSpec() - self.mox.ReplayAll() + @mock.patch.object(rpcapi, 'live_migrate_instance') + @mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid') + @mock.patch.object(self.compute_api, '_record_action_start') + def do_test(record_action_start, get_by_instance_uuid, + live_migrate_instance): + get_by_instance_uuid.return_value = fake_spec - self.compute_api.live_migrate(self.context, instance, - block_migration=True, - disk_over_commit=True, - host_name='fake_dest_host') + self.compute_api.live_migrate(self.context, instance, + block_migration=True, + disk_over_commit=True, + host_name='fake_dest_host') + record_action_start.assert_called_once_with(self.context, instance, + 'live-migration') + live_migrate_instance.assert_called_once_with( + self.context, instance, 'fake_dest_host', + block_migration=True, + disk_over_commit=True, + request_spec=fake_spec) + + do_test() instance.refresh() self.assertEqual(instance['task_state'], task_states.MIGRATING) diff --git a/nova/tests/unit/compute/test_compute_api.py b/nova/tests/unit/compute/test_compute_api.py index d5d95bec6def..701dcca359d3 100644 --- a/nova/tests/unit/compute/test_compute_api.py +++ b/nova/tests/unit/compute/test_compute_api.py @@ -1788,9 +1788,10 @@ class _ComputeAPIUnitTestMixIn(object): instance = self._create_instance_obj(params=paused_state) self._live_migrate_instance(instance) + @mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid') @mock.patch.object(objects.Instance, 'save') @mock.patch.object(objects.InstanceAction, 'action_start') - def _live_migrate_instance(self, instance, _save, _action): + def _live_migrate_instance(self, instance, _save, _action, get_spec): # TODO(gilliard): This logic is upside-down (different # behaviour depending on which class this method is mixed-into. Once # we have cellsv2 we can remove this kind of logic from this test @@ -1798,6 +1799,8 @@ class _ComputeAPIUnitTestMixIn(object): api = self.compute_api.cells_rpcapi else: api = conductor.api.ComputeTaskAPI + fake_spec = objects.RequestSpec() + get_spec.return_value = fake_spec with mock.patch.object(api, 'live_migrate_instance') as task: self.compute_api.live_migrate(self.context, instance, block_migration=True, @@ -1807,7 +1810,8 @@ class _ComputeAPIUnitTestMixIn(object): task.assert_called_once_with(self.context, instance, 'fake_dest_host', block_migration=True, - disk_over_commit=True) + disk_over_commit=True, + request_spec=fake_spec) def test_swap_volume_volume_api_usage(self): # This test ensures that volume_id arguments are passed to volume_api diff --git a/nova/tests/unit/compute/test_compute_cells.py b/nova/tests/unit/compute/test_compute_cells.py index e4376cce7a22..7d98576af499 100644 --- a/nova/tests/unit/compute/test_compute_cells.py +++ b/nova/tests/unit/compute/test_compute_cells.py @@ -370,9 +370,10 @@ class CellsConductorAPIRPCRedirect(test.NoDBTestCase): self.compute_api.resize(self.context, instance) self.assertTrue(self.cells_rpcapi.resize_instance.called) + @mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid') @mock.patch.object(compute_api.API, '_record_action_start') @mock.patch.object(objects.Instance, 'save') - def test_live_migrate_instance(self, instance_save, _record): + def test_live_migrate_instance(self, instance_save, _record, _get_spec): orig_system_metadata = {} instance = fake_instance.fake_instance_obj(self.context, vm_state=vm_states.ACTIVE, cell_name='fake-cell', diff --git a/nova/tests/unit/conductor/tasks/test_live_migrate.py b/nova/tests/unit/conductor/tasks/test_live_migrate.py index a6c399d37024..ff48f98c4279 100644 --- a/nova/tests/unit/conductor/tasks/test_live_migrate.py +++ b/nova/tests/unit/conductor/tasks/test_live_migrate.py @@ -11,7 +11,6 @@ # under the License. import mock -from mox3 import mox import oslo_messaging as messaging from nova.compute import power_state @@ -49,13 +48,15 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): self.block_migration = "bm" self.disk_over_commit = "doc" self.migration = objects.Migration() + self.fake_spec = objects.RequestSpec() self._generate_task() def _generate_task(self): self.task = live_migrate.LiveMigrationTask(self.context, self.instance, self.destination, self.block_migration, self.disk_over_commit, self.migration, compute_rpcapi.ComputeAPI(), - servicegroup.API(), scheduler_client.SchedulerClient()) + servicegroup.API(), scheduler_client.SchedulerClient(), + self.fake_spec) def test_execute_with_destination(self): self.mox.StubOutWithMock(self.task, '_check_host_is_up') @@ -252,9 +253,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def test_find_destination_works(self): self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, @@ -263,16 +262,11 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations( - self.context, fake_spec).AndReturn( + self.context, self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1") self.task._call_livem_checks_on_host("host1") @@ -280,30 +274,57 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): self.mox.ReplayAll() self.assertEqual("host1", self.task._find_destination()) + def test_find_destination_works_with_no_request_spec(self): + task = live_migrate.LiveMigrationTask( + self.context, self.instance, self.destination, + self.block_migration, self.disk_over_commit, self.migration, + compute_rpcapi.ComputeAPI(), servicegroup.API(), + scheduler_client.SchedulerClient(), request_spec=None) + another_spec = objects.RequestSpec() + self.instance.flavor = objects.Flavor() + self.instance.numa_topology = None + self.instance.pci_requests = None + + @mock.patch.object(task, '_call_livem_checks_on_host') + @mock.patch.object(task, '_check_compatible_with_source_hypervisor') + @mock.patch.object(task.scheduler_client, 'select_destinations') + @mock.patch.object(objects.RequestSpec, 'from_components') + @mock.patch.object(scheduler_utils, 'setup_instance_group') + @mock.patch.object(utils, 'get_image_from_system_metadata') + def do_test(get_image, setup_ig, from_components, select_dest, + check_compat, call_livem_checks): + get_image.return_value = "image" + from_components.return_value = another_spec + select_dest.return_value = [{'host': 'host1'}] + + self.assertEqual("host1", task._find_destination()) + + get_image.assert_called_once_with(self.instance.system_metadata) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} + setup_ig.assert_called_once_with( + self.context, fake_props, + {'ignore_hosts': [self.instance_host]} + ) + select_dest.assert_called_once_with(self.context, another_spec) + check_compat.assert_called_once_with("host1") + call_livem_checks.assert_called_once_with("host1") + do_test() + def test_find_destination_no_image_works(self): self.instance['image_ref'] = '' - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, '_check_compatible_with_source_hypervisor') self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') - scheduler_utils.build_request_spec( - self.context, - {'properties': {'hw_disk_bus': 'scsi'}}, - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1") self.task._call_livem_checks_on_host("host1") @@ -313,9 +334,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def _test_find_destination_retry_hypervisor_raises(self, error): self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, @@ -324,25 +343,17 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, {}, mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1")\ .AndRaise(error) - scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host, "host1"]}) - objects.RequestSpec.from_primitives( - self.context, {}, mox.IgnoreArg()).AndReturn(fake_spec) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host2'}]) self.task._check_compatible_with_source_hypervisor("host2") self.task._call_livem_checks_on_host("host2") @@ -361,9 +372,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def test_find_destination_retry_with_invalid_livem_checks(self): self.flags(migrate_max_retries=1) self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, @@ -372,28 +381,18 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1") self.task._call_livem_checks_on_host("host1")\ .AndRaise(exception.Invalid) - scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host, "host1"]}) - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host2'}]) self.task._check_compatible_with_source_hypervisor("host2") self.task._call_livem_checks_on_host("host2") @@ -404,9 +403,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def test_find_destination_retry_with_failed_migration_pre_checks(self): self.flags(migrate_max_retries=1) self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, @@ -415,29 +412,18 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1") self.task._call_livem_checks_on_host("host1")\ .AndRaise(exception.MigrationPreCheckError("reason")) - scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host, "host1"]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host2'}]) self.task._check_compatible_with_source_hypervisor("host2") self.task._call_livem_checks_on_host("host2") @@ -448,9 +434,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def test_find_destination_retry_exceeds_max(self): self.flags(migrate_max_retries=0) self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') self.mox.StubOutWithMock(self.task, @@ -458,16 +442,11 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndReturn( + self.fake_spec).AndReturn( [{'host': 'host1'}]) self.task._check_compatible_with_source_hypervisor("host1")\ .AndRaise(exception.DestinationHypervisorTooOld) @@ -481,23 +460,16 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase): def test_find_destination_when_runs_out_of_hosts(self): self.mox.StubOutWithMock(utils, 'get_image_from_system_metadata') - self.mox.StubOutWithMock(scheduler_utils, 'build_request_spec') self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') - self.mox.StubOutWithMock(objects.RequestSpec, 'from_primitives') self.mox.StubOutWithMock(self.task.scheduler_client, 'select_destinations') utils.get_image_from_system_metadata( self.instance.system_metadata).AndReturn("image") - scheduler_utils.build_request_spec(self.context, mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn({}) + fake_props = {'instance_properties': {'uuid': self.instance_uuid}} scheduler_utils.setup_instance_group( - self.context, {}, {'ignore_hosts': [self.instance_host]}) - fake_spec = objects.RequestSpec() - objects.RequestSpec.from_primitives( - self.context, - mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(fake_spec) + self.context, fake_props, {'ignore_hosts': [self.instance_host]}) self.task.scheduler_client.select_destinations(self.context, - fake_spec).AndRaise( + self.fake_spec).AndRaise( exception.NoValidHost(reason="")) self.mox.ReplayAll()