diff options
| author | Jenkins <jenkins@review.openstack.org> | 2013-06-25 16:28:46 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2013-06-25 16:28:46 +0000 |
| commit | 9331c5c1115c7d8cc5bcab71b1100eeea1ce72fe (patch) | |
| tree | bfde7e32a3ef66a5ebb8f81b916b2643da3b5b68 /nova/tests | |
| parent | 24129187ed642f99e6085f8bd44da5a9eb39034f (diff) | |
| parent | 2d7beddc0bb7830c2a8bf893b9221c0de568c55d (diff) | |
Merge "Extract live-migration scheduler logic from the scheduler driver"
Diffstat (limited to 'nova/tests')
| -rw-r--r-- | nova/tests/conductor/tasks/__init__.py | 11 | ||||
| -rw-r--r-- | nova/tests/conductor/tasks/test_live_migrate.py | 311 | ||||
| -rw-r--r-- | nova/tests/integrated/test_api_samples.py | 22 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_filter_scheduler.py | 139 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_scheduler.py | 506 |
5 files changed, 346 insertions, 643 deletions
diff --git a/nova/tests/conductor/tasks/__init__.py b/nova/tests/conductor/tasks/__init__.py new file mode 100644 index 000000000..94e731d20 --- /dev/null +++ b/nova/tests/conductor/tasks/__init__.py @@ -0,0 +1,11 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. diff --git a/nova/tests/conductor/tasks/test_live_migrate.py b/nova/tests/conductor/tasks/test_live_migrate.py new file mode 100644 index 000000000..c54e53b1a --- /dev/null +++ b/nova/tests/conductor/tasks/test_live_migrate.py @@ -0,0 +1,311 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.compute import flavors +from nova.compute import power_state +from nova.conductor.tasks import live_migrate +from nova import db +from nova import exception +from nova import test + + +class LiveMigrationTaskTestCase(test.TestCase): + def setUp(self): + super(LiveMigrationTaskTestCase, self).setUp() + self.context = "context" + self.instance_host = "host" + self.instance_uuid = "uuid" + self.instance_image = "image_ref" + self.instance = { + "host": self.instance_host, + "uuid": self.instance_uuid, + "power_state": power_state.RUNNING, + "memory_mb": 512, + "image_ref": self.instance_image} + self.destination = "destination" + self.block_migration = "bm" + self.disk_over_commit = "doc" + self.select_hosts_callback = self._select_hosts_callback + 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.select_hosts_callback) + + def _select_hosts_callback(self, *args): + return ["host1"] + + def test_execute_with_destination(self): + self.mox.StubOutWithMock(self.task, '_check_host_is_up') + self.mox.StubOutWithMock(self.task, '_check_requested_destination') + self.mox.StubOutWithMock(self.task.compute_rpcapi, 'live_migration') + + self.task._check_host_is_up(self.instance_host) + self.task._check_requested_destination() + self.task.compute_rpcapi.live_migration(self.context, + host=self.instance_host, + instance=self.instance, + dest=self.destination, + block_migration=self.block_migration, + migrate_data=None).AndReturn("bob") + + self.mox.ReplayAll() + self.assertEqual("bob", self.task.execute()) + + def test_execute_without_destination(self): + self.destination = None + self._generate_task() + self.assertEqual(None, self.task.destination) + + self.mox.StubOutWithMock(self.task, '_check_host_is_up') + self.mox.StubOutWithMock(self.task, '_find_destination') + self.mox.StubOutWithMock(self.task.compute_rpcapi, 'live_migration') + + self.task._check_host_is_up(self.instance_host) + self.task._find_destination().AndReturn("found_host") + self.task.compute_rpcapi.live_migration(self.context, + host=self.instance_host, + instance=self.instance, + dest="found_host", + block_migration=self.block_migration, + migrate_data=None).AndReturn("bob") + + self.mox.ReplayAll() + self.assertEqual("bob", self.task.execute()) + + def test_check_instance_is_running_passes(self): + self.task._check_instance_is_running() + + def test_check_instance_is_running_fails_when_shutdown(self): + self.task.instance['power_state'] = power_state.SHUTDOWN + self.assertRaises(exception.InstanceNotRunning, + self.task._check_instance_is_running) + + def test_check_instance_host_is_up(self): + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + self.mox.StubOutWithMock(self.task.servicegroup_api, 'service_is_up') + + db.service_get_by_compute_host(self.context, + "host").AndReturn("service") + self.task.servicegroup_api.service_is_up("service").AndReturn(True) + + self.mox.ReplayAll() + self.task._check_host_is_up("host") + + def test_check_instance_host_is_up_fails_if_not_up(self): + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + self.mox.StubOutWithMock(self.task.servicegroup_api, 'service_is_up') + + db.service_get_by_compute_host(self.context, + "host").AndReturn("service") + self.task.servicegroup_api.service_is_up("service").AndReturn(False) + + self.mox.ReplayAll() + self.assertRaises(exception.ComputeServiceUnavailable, + self.task._check_host_is_up, "host") + + def test_check_instance_host_is_up_fails_if_not_found(self): + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + + db.service_get_by_compute_host(self.context, + "host").AndRaise(exception.NotFound) + + self.mox.ReplayAll() + self.assertRaises(exception.ComputeServiceUnavailable, + self.task._check_host_is_up, "host") + + def test_check_requested_destination(self): + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + self.mox.StubOutWithMock(self.task, '_get_compute_info') + self.mox.StubOutWithMock(self.task.servicegroup_api, 'service_is_up') + self.mox.StubOutWithMock(self.task.compute_rpcapi, + 'check_can_live_migrate_destination') + + db.service_get_by_compute_host(self.context, + self.destination).AndReturn("service") + self.task.servicegroup_api.service_is_up("service").AndReturn(True) + hypervisor_details = { + "hypervisor_type": "a", + "hypervisor_version": 6.1, + "free_ram_mb": 513 + } + self.task._get_compute_info(self.destination)\ + .AndReturn(hypervisor_details) + self.task._get_compute_info(self.instance_host)\ + .AndReturn(hypervisor_details) + self.task._get_compute_info(self.destination)\ + .AndReturn(hypervisor_details) + + self.task.compute_rpcapi.check_can_live_migrate_destination( + self.context, self.instance, self.destination, + self.block_migration, self.disk_over_commit).AndReturn( + "migrate_data") + + self.mox.ReplayAll() + self.task._check_requested_destination() + self.assertEqual("migrate_data", self.task.migrate_data) + + def test_check_requested_destination_fails_with_same_dest(self): + self.task.destination = "same" + self.task.source = "same" + self.assertRaises(exception.UnableToMigrateToSelf, + self.task._check_requested_destination) + + def test_check_requested_destination_fails_when_destination_is_up(self): + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + + db.service_get_by_compute_host(self.context, + self.destination).AndRaise(exception.NotFound) + + self.mox.ReplayAll() + self.assertRaises(exception.ComputeServiceUnavailable, + self.task._check_requested_destination) + + def test_check_requested_destination_fails_with_not_enough_memory(self): + self.mox.StubOutWithMock(self.task, '_check_host_is_up') + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + + self.task._check_host_is_up(self.destination) + db.service_get_by_compute_host(self.context, + self.destination).AndReturn({ + "compute_node": [{"free_ram_mb": 511}] + }) + + self.mox.ReplayAll() + self.assertRaises(exception.MigrationPreCheckError, + self.task._check_requested_destination) + + def test_check_requested_destination_fails_with_hypervisor_diff(self): + self.mox.StubOutWithMock(self.task, '_check_host_is_up') + self.mox.StubOutWithMock(self.task, + '_check_destination_has_enough_memory') + self.mox.StubOutWithMock(self.task, '_get_compute_info') + + self.task._check_host_is_up(self.destination) + self.task._check_destination_has_enough_memory() + self.task._get_compute_info(self.instance_host).AndReturn({ + "hypervisor_type": "b" + }) + self.task._get_compute_info(self.destination).AndReturn({ + "hypervisor_type": "a" + }) + + self.mox.ReplayAll() + self.assertRaises(exception.InvalidHypervisorType, + self.task._check_requested_destination) + + def test_check_requested_destination_fails_with_hypervisor_too_old(self): + self.mox.StubOutWithMock(self.task, '_check_host_is_up') + self.mox.StubOutWithMock(self.task, + '_check_destination_has_enough_memory') + self.mox.StubOutWithMock(self.task, '_get_compute_info') + + self.task._check_host_is_up(self.destination) + self.task._check_destination_has_enough_memory() + self.task._get_compute_info(self.instance_host).AndReturn({ + "hypervisor_type": "a", + "hypervisor_version": 7 + }) + self.task._get_compute_info(self.destination).AndReturn({ + "hypervisor_type": "a", + "hypervisor_version": 6 + }) + + self.mox.ReplayAll() + self.assertRaises(exception.DestinationHypervisorTooOld, + self.task._check_requested_destination) + + def test_find_destination_works(self): + self.mox.StubOutWithMock(self.task.image_service, 'show') + self.mox.StubOutWithMock(flavors, 'extract_flavor') + self.mox.StubOutWithMock(self.task, + '_check_compatible_with_source_hypervisor') + self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') + + self.task.image_service.show(self.context, + self.instance_image).AndReturn("image") + flavors.extract_flavor(self.instance).AndReturn("inst_type") + self.task._check_compatible_with_source_hypervisor("host1") + self.task._call_livem_checks_on_host("host1") + + self.mox.ReplayAll() + self.assertEqual("host1", self.task._find_destination()) + + def _test_find_destination_retry_hypervisor_raises(self, error): + self.mox.StubOutWithMock(self.task.image_service, 'show') + self.mox.StubOutWithMock(flavors, 'extract_flavor') + self.mox.StubOutWithMock(self.task, + '_check_compatible_with_source_hypervisor') + self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') + + self.task.image_service.show(self.context, + self.instance_image).AndReturn("image") + flavors.extract_flavor(self.instance).AndReturn("inst_type") + self.task._check_compatible_with_source_hypervisor("host1")\ + .AndRaise(error) + + self.task._check_compatible_with_source_hypervisor("host1") + self.task._call_livem_checks_on_host("host1") + + self.mox.ReplayAll() + self.assertEqual("host1", self.task._find_destination()) + + def test_find_destination_retry_with_old_hypervisor(self): + self._test_find_destination_retry_hypervisor_raises( + exception.DestinationHypervisorTooOld) + + def test_find_destination_retry_with_invalid_hypervisor_type(self): + self._test_find_destination_retry_hypervisor_raises( + exception.InvalidHypervisorType) + + def test_find_destination_retry_with_invalid_livem_checks(self): + self.mox.StubOutWithMock(self.task.image_service, 'show') + self.mox.StubOutWithMock(flavors, 'extract_flavor') + self.mox.StubOutWithMock(self.task, + '_check_compatible_with_source_hypervisor') + self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') + + self.task.image_service.show(self.context, + self.instance_image).AndReturn("image") + flavors.extract_flavor(self.instance).AndReturn("inst_type") + self.task._check_compatible_with_source_hypervisor("host1") + self.task._call_livem_checks_on_host("host1")\ + .AndRaise(exception.Invalid) + + self.task._check_compatible_with_source_hypervisor("host1") + self.task._call_livem_checks_on_host("host1") + + self.mox.ReplayAll() + self.assertEqual("host1", self.task._find_destination()) + + def test_find_destination_retry_exceeds_max(self): + self.flags(scheduler_max_attempts=1) + self.mox.StubOutWithMock(self.task.image_service, 'show') + self.mox.StubOutWithMock(flavors, 'extract_flavor') + self.mox.StubOutWithMock(self.task, + '_check_compatible_with_source_hypervisor') + self.mox.StubOutWithMock(self.task, '_call_livem_checks_on_host') + + self.task.image_service.show(self.context, + self.instance_image).AndReturn("image") + flavors.extract_flavor(self.instance).AndReturn("inst_type") + self.task._check_compatible_with_source_hypervisor("host1")\ + .AndRaise(exception.DestinationHypervisorTooOld) + + self.mox.ReplayAll() + self.assertRaises(exception.NoValidHost, self.task._find_destination) + + def test_not_implemented_rollback(self): + self.assertRaises(NotImplementedError, self.task.rollback) diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 87ed6c6ce..380b69079 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -47,7 +47,7 @@ from nova.openstack.common import jsonutils from nova.openstack.common import log as logging from nova.openstack.common import timeutils import nova.quota -from nova.scheduler import driver +from nova.scheduler import manager as scheduler_manager from nova.servicegroup import api as service_group_api from nova import test from nova.tests.api.openstack.compute.contrib import test_coverage_ext @@ -2213,23 +2213,13 @@ class AdminActionsSamplesJsonTest(ServersSampleBase): def test_post_live_migrate_server(self): # Get api samples to server live migrate request. - def fake_live_migration_src_check(self, context, instance_ref): - """Skip live migration scheduler checks.""" + def fake_live_migration(self, context, instance, dest, + block_migration, disk_over_commit): return - def fake_live_migration_dest_check(self, context, instance_ref, dest): - """Skip live migration scheduler checks.""" - return dest - - def fake_live_migration_common(self, context, instance_ref, dest): - """Skip live migration scheduler checks.""" - return - self.stubs.Set(driver.Scheduler, '_live_migration_src_check', - fake_live_migration_src_check) - self.stubs.Set(driver.Scheduler, '_live_migration_dest_check', - fake_live_migration_dest_check) - self.stubs.Set(driver.Scheduler, '_live_migration_common_check', - fake_live_migration_common) + self.stubs.Set(scheduler_manager.SchedulerManager, + 'live_migration', + fake_live_migration) def fake_get_compute(context, host): service = dict(host=host, diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py index d6cc7808e..ac2e73ec7 100644 --- a/nova/tests/scheduler/test_filter_scheduler.py +++ b/nova/tests/scheduler/test_filter_scheduler.py @@ -25,12 +25,10 @@ from nova.conductor import api as conductor_api from nova import context from nova import db from nova import exception -from nova.openstack.common import rpc from nova.scheduler import driver from nova.scheduler import filter_scheduler from nova.scheduler import host_manager from nova.scheduler import weights -from nova import servicegroup from nova.tests.scheduler import fakes from nova.tests.scheduler import test_scheduler @@ -393,143 +391,6 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase): self.assertEqual([['host', 'node']], filter_properties['retry']['hosts']) - def test_live_migration_dest_check_service_memory_overcommit(self): - instance = self._live_migration_instance() - - # Live-migration should work since default is to overcommit memory. - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - self.mox.StubOutWithMock(self.driver, '_get_compute_info') - self.mox.StubOutWithMock(self.driver, '_live_migration_common_check') - self.mox.StubOutWithMock(rpc, 'call') - self.mox.StubOutWithMock(self.driver.compute_rpcapi, 'live_migration') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - - self.driver._live_migration_src_check(self.context, instance) - db.service_get_by_compute_host(self.context, - dest).AndReturn('fake_service3') - self.servicegroup_api.service_is_up('fake_service3').AndReturn(True) - - self.driver._get_compute_info(self.context, dest).AndReturn( - {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': 512, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None}) - - self.driver._live_migration_common_check(self.context, instance, dest) - - rpc.call(self.context, "compute.fake_host2", - {"method": 'check_can_live_migrate_destination', - "namespace": None, - "args": {'instance': instance, - 'block_migration': block_migration, - 'disk_over_commit': disk_over_commit}, - "version": compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION}, - None).AndReturn({}) - - self.driver.compute_rpcapi.live_migration(self.context, - host=instance['host'], instance=instance, dest=dest, - block_migration=block_migration, migrate_data={}) - - self.mox.ReplayAll() - result = self.driver.schedule_live_migration(self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - self.assertEqual(result, None) - - def test_live_migration_assert_memory_no_overcommit(self): - # Test that memory check passes with no memory overcommit. - def fake_get(context, host): - return {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': 1024, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None} - - self.stubs.Set(self.driver, '_get_compute_info', fake_get) - - self.flags(ram_allocation_ratio=1.0) - instance = self._live_migration_instance() - dest = 'fake_host2' - result = self.driver._assert_compute_node_has_enough_memory( - self.context, instance, dest) - self.assertEqual(result, None) - - def test_live_migration_assert_memory_no_overcommit_lack_memory(self): - # Test that memory check fails with no memory overcommit. - def fake_get(context, host): - return {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': 1023, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None} - - self.stubs.Set(self.driver, '_get_compute_info', fake_get) - - self.flags(ram_allocation_ratio=1.0) - instance = self._live_migration_instance() - dest = 'fake_host2' - self.assertRaises(exception.MigrationError, - self.driver._assert_compute_node_has_enough_memory, - context, instance, dest) - - def test_live_migration_assert_memory_overcommit(self): - # Test that memory check passes with memory overcommit. - def fake_get(context, host): - return {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': -1024, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None} - - self.stubs.Set(self.driver, '_get_compute_info', fake_get) - - self.flags(ram_allocation_ratio=2.0) - instance = self._live_migration_instance() - dest = 'fake_host2' - result = self.driver._assert_compute_node_has_enough_memory( - self.context, instance, dest) - self.assertEqual(result, None) - - def test_live_migration_assert_memory_overcommit_lack_memory(self): - # Test that memory check fails with memory overcommit. - def fake_get(context, host): - return {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': -1025, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None} - - self.stubs.Set(self.driver, '_get_compute_info', fake_get) - - self.flags(ram_allocation_ratio=2.0) - instance = self._live_migration_instance() - dest = 'fake_host2' - self.assertRaises(exception.MigrationError, - self.driver._assert_compute_node_has_enough_memory, - self.context, instance, dest) - def test_basic_schedule_run_instances_anti_affinity(self): filter_properties = {'scheduler_hints': {'group': 'cats'}} diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 0574f6d2e..99de672c4 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -22,20 +22,16 @@ Tests For Scheduler import mox from nova.compute import api as compute_api -from nova.compute import flavors -from nova.compute import power_state -from nova.compute import rpcapi as compute_rpcapi from nova.compute import task_states from nova.compute import utils as compute_utils from nova.compute import vm_states from nova.conductor import api as conductor_api +from nova.conductor.tasks import live_migrate from nova import context from nova import db from nova import exception from nova.image import glance -from nova.openstack.common import jsonutils from nova.openstack.common.notifier import api as notifier -from nova.openstack.common import rpc from nova.openstack.common.rpc import common as rpc_common from nova.scheduler import driver from nova.scheduler import manager @@ -45,7 +41,6 @@ from nova.tests import fake_instance_actions from nova.tests.image import fake as fake_image from nova.tests import matchers from nova.tests.scheduler import fakes -from nova import utils class SchedulerManagerTestCase(test.NoDBTestCase): @@ -220,11 +215,11 @@ class SchedulerManagerTestCase(test.NoDBTestCase): block_migration = False disk_over_commit = False - self._mox_schedule_method_helper('schedule_live_migration') + self.mox.StubOutWithMock(self.manager, '_schedule_live_migration') self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc') self.mox.StubOutWithMock(db, 'instance_update_and_get_original') - self.manager.driver.schedule_live_migration(self.context, + self.manager._schedule_live_migration(self.context, inst, dest, block_migration, disk_over_commit).AndRaise( exception.NoValidHost(reason="")) db.instance_update_and_get_original(self.context, inst["uuid"], @@ -253,11 +248,11 @@ class SchedulerManagerTestCase(test.NoDBTestCase): block_migration = False disk_over_commit = False - self._mox_schedule_method_helper('schedule_live_migration') + self.mox.StubOutWithMock(self.manager, '_schedule_live_migration') self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc') self.mox.StubOutWithMock(db, 'instance_update_and_get_original') - self.manager.driver.schedule_live_migration(self.context, + self.manager._schedule_live_migration(self.context, inst, dest, block_migration, disk_over_commit).AndRaise( exception.ComputeServiceUnavailable(host="src")) db.instance_update_and_get_original(self.context, inst["uuid"], @@ -277,6 +272,17 @@ class SchedulerManagerTestCase(test.NoDBTestCase): self.context, inst, dest, block_migration, disk_over_commit) + def test_live_migrate(self): + instance = {'host': 'h'} + self.mox.StubOutClassWithMocks(live_migrate, "LiveMigrationTask") + task = live_migrate.LiveMigrationTask(self.context, instance, + "dest", "bm", "doc", self.manager.driver.select_hosts) + task.execute() + + self.mox.ReplayAll() + self.manager.live_migration(self.context, instance, "dest", + "bm", "doc") + def test_live_migration_set_vmstate_error(self): inst = {"uuid": "fake-instance-id", "vm_state": vm_states.ACTIVE, } @@ -285,11 +291,11 @@ class SchedulerManagerTestCase(test.NoDBTestCase): block_migration = False disk_over_commit = False - self._mox_schedule_method_helper('schedule_live_migration') + self.mox.StubOutWithMock(self.manager, '_schedule_live_migration') self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc') self.mox.StubOutWithMock(db, 'instance_update_and_get_original') - self.manager.driver.schedule_live_migration(self.context, + self.manager._schedule_live_migration(self.context, inst, dest, block_migration, disk_over_commit).AndRaise( ValueError) db.instance_update_and_get_original(self.context, inst["uuid"], @@ -464,482 +470,6 @@ class SchedulerTestCase(test.NoDBTestCase): result = self.driver.hosts_up(self.context, self.topic) self.assertEqual(result, ['host2']) - def _live_migration_instance(self): - inst_type = {'memory_mb': 1024, 'root_gb': 40, 'deleted_at': None, - 'name': u'm1.medium', 'deleted': 0, 'created_at': None, - 'ephemeral_gb': 0, 'updated_at': None, 'disabled': False, - 'vcpus': 2, 'extra_specs': {}, 'swap': 0, - 'rxtx_factor': 1.0, 'is_public': True, 'flavorid': u'3', - 'vcpu_weight': None, 'id': 1} - - sys_meta = utils.dict_to_metadata( - flavors.save_flavor_info({}, inst_type)) - return {'id': 31337, - 'uuid': 'fake_uuid', - 'name': 'fake-instance', - 'host': 'fake_host1', - 'power_state': power_state.RUNNING, - 'memory_mb': 1024, - 'root_gb': 1024, - 'ephemeral_gb': 0, - 'vm_state': '', - 'task_state': '', - 'instance_type_id': inst_type['id'], - 'image_ref': 'fake-image-ref', - 'system_metadata': sys_meta} - - def test_live_migration_basic(self): - # Test basic schedule_live_migration functionality. - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(self.driver, '_live_migration_dest_check') - self.mox.StubOutWithMock(self.driver, '_live_migration_common_check') - self.mox.StubOutWithMock(self.driver.compute_rpcapi, - 'check_can_live_migrate_destination') - self.mox.StubOutWithMock(self.driver.compute_rpcapi, - 'live_migration') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = jsonutils.to_primitive(self._live_migration_instance()) - - self.driver._live_migration_src_check(self.context, instance) - self.driver._live_migration_dest_check(self.context, instance, - dest).AndReturn(dest) - self.driver._live_migration_common_check(self.context, instance, - dest) - self.driver.compute_rpcapi.check_can_live_migrate_destination( - self.context, instance, dest, block_migration, - disk_over_commit).AndReturn({}) - self.driver.compute_rpcapi.live_migration(self.context, - host=instance['host'], instance=instance, dest=dest, - block_migration=block_migration, migrate_data={}) - - self.mox.ReplayAll() - self.driver.schedule_live_migration(self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_all_checks_pass(self): - # Test live migration when all checks pass. - - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - self.mox.StubOutWithMock(rpc, 'call') - self.mox.StubOutWithMock(self.driver.compute_rpcapi, - 'live_migration') - - dest = 'fake_host2' - block_migration = True - disk_over_commit = True - instance = jsonutils.to_primitive(self._live_migration_instance()) - - # Source checks - db.service_get_by_compute_host(self.context, - instance['host']).AndReturn('fake_service2') - self.servicegroup_api.service_is_up('fake_service2').AndReturn(True) - - # Destination checks (compute is up, enough memory, disk) - db.service_get_by_compute_host(self.context, - dest).AndReturn('fake_service3') - self.servicegroup_api.service_is_up('fake_service3').AndReturn(True) - # assert_compute_node_has_enough_memory() - db.service_get_by_compute_host(self.context, dest).AndReturn( - {'compute_node': [{'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': 1280, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None, - 'hypervisor_version': 1}]}) - - # Common checks (same hypervisor, etc) - db.service_get_by_compute_host(self.context, dest).AndReturn( - {'compute_node': [{'hypervisor_type': 'xen', - 'hypervisor_version': 1}]}) - db.service_get_by_compute_host(self.context, - instance['host']).AndReturn( - {'compute_node': [{'hypervisor_type': 'xen', - 'hypervisor_version': 1, - 'cpu_info': 'fake_cpu_info'}]}) - - rpc.call(self.context, "compute.fake_host2", - {"method": 'check_can_live_migrate_destination', - "namespace": None, - "args": {'instance': instance, - 'block_migration': block_migration, - 'disk_over_commit': disk_over_commit}, - "version": compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION}, - None).AndReturn({}) - - self.driver.compute_rpcapi.live_migration(self.context, - host=instance['host'], instance=instance, dest=dest, - block_migration=block_migration, migrate_data={}) - - self.mox.ReplayAll() - result = self.driver.schedule_live_migration(self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - self.assertEqual(result, None) - - def test_live_migration_instance_not_running(self): - # The instance given by instance_id is not running. - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - instance['power_state'] = power_state.NOSTATE - - self.assertRaises(exception.InstanceNotRunning, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_compute_src_not_exist(self): - # Raise exception when src compute node is does not exist. - - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - # Compute down - db.service_get_by_compute_host(self.context, - instance['host']).AndRaise( - exception.ComputeHostNotFound(host='fake')) - - self.mox.ReplayAll() - self.assertRaises(exception.ComputeServiceUnavailable, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_compute_src_not_alive(self): - # Raise exception when src compute node is not alive. - - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - # Compute down - db.service_get_by_compute_host(self.context, - instance['host']).AndReturn('fake_service2') - self.servicegroup_api.service_is_up('fake_service2').AndReturn(False) - - self.mox.ReplayAll() - self.assertRaises(exception.ComputeServiceUnavailable, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_compute_dest_not_exist(self): - # Raise exception when dest compute node does not exist. - - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - self.driver._live_migration_src_check(self.context, instance) - # Compute down - db.service_get_by_compute_host(self.context, - dest).AndRaise(exception.NotFound()) - - self.mox.ReplayAll() - self.assertRaises(exception.ComputeServiceUnavailable, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_compute_dest_not_alive(self): - # Raise exception when dest compute node is not alive. - - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - self.driver._live_migration_src_check(self.context, instance) - db.service_get_by_compute_host(self.context, - dest).AndReturn('fake_service3') - # Compute is down - self.servicegroup_api.service_is_up('fake_service3').AndReturn(False) - - self.mox.ReplayAll() - self.assertRaises(exception.ComputeServiceUnavailable, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_dest_check_service_same_host(self): - # Confirms exception raises in case dest and src is same host. - - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - block_migration = False - instance = self._live_migration_instance() - # make dest same as src - dest = instance['host'] - - self.driver._live_migration_src_check(self.context, instance) - - self.mox.ReplayAll() - self.assertRaises(exception.UnableToMigrateToSelf, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=False) - - def test_live_migration_dest_check_service_lack_memory(self): - # Confirms exception raises when dest doesn't have enough memory. - - # Flag needed to make FilterScheduler test hit memory limit since the - # default for it is to allow memory overcommit by a factor of 1.5. - self.flags(ram_allocation_ratio=1.0) - - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - self.mox.StubOutWithMock(servicegroup.API, 'service_is_up') - self.mox.StubOutWithMock(self.driver, '_get_compute_info') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - self.driver._live_migration_src_check(self.context, instance) - db.service_get_by_compute_host(self.context, - dest).AndReturn('fake_service3') - self.servicegroup_api.service_is_up('fake_service3').AndReturn(True) - - self.driver._get_compute_info(self.context, dest).AndReturn( - {'memory_mb': 2048, - 'free_disk_gb': 512, - 'local_gb_used': 512, - 'free_ram_mb': 512, - 'local_gb': 1024, - 'vcpus': 4, - 'vcpus_used': 2, - 'updated_at': None}) - - self.mox.ReplayAll() - self.assertRaises(exception.MigrationError, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_different_hypervisor_type_raises(self): - # Confirm live_migration to hypervisor of different type raises. - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(self.driver, '_live_migration_dest_check') - self.mox.StubOutWithMock(rpc, 'queue_get_for') - self.mox.StubOutWithMock(rpc, 'call') - self.mox.StubOutWithMock(rpc, 'cast') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - self.driver._live_migration_src_check(self.context, instance) - self.driver._live_migration_dest_check(self.context, instance, - dest).AndReturn(dest) - - db.service_get_by_compute_host(self.context, dest).AndReturn( - {'compute_node': [{'hypervisor_type': 'xen', - 'hypervisor_version': 1}]}) - db.service_get_by_compute_host(self.context, - instance['host']).AndReturn( - {'compute_node': [{'hypervisor_type': 'not-xen', - 'hypervisor_version': 1}]}) - - self.mox.ReplayAll() - self.assertRaises(exception.InvalidHypervisorType, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_dest_hypervisor_version_older_raises(self): - # Confirm live migration to older hypervisor raises. - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(self.driver, '_live_migration_dest_check') - self.mox.StubOutWithMock(rpc, 'queue_get_for') - self.mox.StubOutWithMock(rpc, 'call') - self.mox.StubOutWithMock(rpc, 'cast') - self.mox.StubOutWithMock(db, 'service_get_by_compute_host') - - dest = 'fake_host2' - block_migration = False - disk_over_commit = False - instance = self._live_migration_instance() - - self.driver._live_migration_src_check(self.context, instance) - self.driver._live_migration_dest_check(self.context, instance, - dest).AndReturn(dest) - - db.service_get_by_compute_host(self.context, dest).AndReturn( - {'compute_node': [{'hypervisor_type': 'xen', - 'hypervisor_version': 1}]}) - db.service_get_by_compute_host(self.context, - instance['host']).AndReturn( - {'compute_node': [{'hypervisor_type': 'xen', - 'hypervisor_version': 2}]}) - self.mox.ReplayAll() - self.assertRaises(exception.DestinationHypervisorTooOld, - self.driver.schedule_live_migration, self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - - def test_live_migration_dest_check_auto_set_host(self): - instance = self._live_migration_instance() - - # Confirm dest is picked by scheduler if not set. - self.mox.StubOutWithMock(self.driver, 'select_hosts') - self.mox.StubOutWithMock(flavors, 'extract_flavor') - - request_spec = {'instance_properties': instance, - 'instance_type': {}, - 'instance_uuids': [instance['uuid']], - 'image': self.image_service.show(self.context, - instance['image_ref']) - } - ignore_hosts = [instance['host']] - filter_properties = {'ignore_hosts': ignore_hosts} - - flavors.extract_flavor(instance).AndReturn({}) - self.driver.select_hosts(self.context, request_spec, - filter_properties).AndReturn(['fake_host2']) - - self.mox.ReplayAll() - result = self.driver._live_migration_dest_check(self.context, instance, - None, ignore_hosts) - self.assertEqual('fake_host2', result) - - def test_live_migration_dest_check_no_image(self): - instance = self._live_migration_instance() - instance['image_ref'] = '' - - # Confirm dest is picked by scheduler if not set. - self.mox.StubOutWithMock(self.driver, 'select_hosts') - self.mox.StubOutWithMock(flavors, 'extract_flavor') - - request_spec = {'instance_properties': instance, - 'instance_type': {}, - 'instance_uuids': [instance['uuid']], - 'image': None - } - ignore_hosts = [instance['host']] - filter_properties = {'ignore_hosts': ignore_hosts} - - flavors.extract_flavor(instance).AndReturn({}) - self.driver.select_hosts(self.context, request_spec, - filter_properties).AndReturn(['fake_host2']) - - self.mox.ReplayAll() - result = self.driver._live_migration_dest_check(self.context, instance, - None, ignore_hosts) - self.assertEqual('fake_host2', result) - - def test_live_migration_auto_set_dest(self): - instance = self._live_migration_instance() - - # Confirm scheduler picks target host if none given. - self.mox.StubOutWithMock(flavors, 'extract_flavor') - self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') - self.mox.StubOutWithMock(self.driver, 'select_hosts') - self.mox.StubOutWithMock(self.driver, '_live_migration_common_check') - self.mox.StubOutWithMock(rpc, 'call') - self.mox.StubOutWithMock(self.driver.compute_rpcapi, 'live_migration') - - dest = None - block_migration = False - disk_over_commit = False - request_spec = {'instance_properties': instance, - 'instance_type': {}, - 'instance_uuids': [instance['uuid']], - 'image': self.image_service.show(self.context, - instance['image_ref']) - } - - self.driver._live_migration_src_check(self.context, instance) - - flavors.extract_flavor( - instance).MultipleTimes().AndReturn({}) - - # First selected host raises exception.InvalidHypervisorType - self.driver.select_hosts(self.context, request_spec, - {'ignore_hosts': [instance['host']]}).AndReturn(['fake_host2']) - self.driver._live_migration_common_check(self.context, instance, - 'fake_host2').AndRaise(exception.InvalidHypervisorType()) - - # Second selected host raises exception.InvalidCPUInfo - self.driver.select_hosts(self.context, request_spec, - {'ignore_hosts': [instance['host'], - 'fake_host2']}).AndReturn(['fake_host3']) - self.driver._live_migration_common_check(self.context, instance, - 'fake_host3') - rpc.call(self.context, "compute.fake_host3", - {"method": 'check_can_live_migrate_destination', - "namespace": None, - "args": {'instance': instance, - 'block_migration': block_migration, - 'disk_over_commit': disk_over_commit}, - "version": compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION}, - None).AndRaise(exception.InvalidCPUInfo(reason="")) - - # Third selected host pass all checks - self.driver.select_hosts(self.context, request_spec, - {'ignore_hosts': [instance['host'], - 'fake_host2', - 'fake_host3']}).AndReturn(['fake_host4']) - self.driver._live_migration_common_check(self.context, instance, - 'fake_host4') - rpc.call(self.context, "compute.fake_host4", - {"method": 'check_can_live_migrate_destination', - "namespace": None, - "args": {'instance': instance, - 'block_migration': block_migration, - 'disk_over_commit': disk_over_commit}, - "version": compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION}, - None).AndReturn({}) - self.driver.compute_rpcapi.live_migration(self.context, - host=instance['host'], instance=instance, dest='fake_host4', - block_migration=block_migration, migrate_data={}) - - self.mox.ReplayAll() - result = self.driver.schedule_live_migration(self.context, - instance=instance, dest=dest, - block_migration=block_migration, - disk_over_commit=disk_over_commit) - self.assertEqual(result, None) - def test_handle_schedule_error_adds_instance_fault(self): instance = {'uuid': 'fake-uuid'} self.mox.StubOutWithMock(db, 'instance_update_and_get_original') |
