diff options
| author | Jenkins <jenkins@review.openstack.org> | 2013-02-05 01:26:25 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2013-02-05 01:26:25 +0000 |
| commit | f9eb7ca2ad7828c9b5a0790718d48a69b829658a (patch) | |
| tree | 713f0cb05a126aa9b017227199156167e21d8aa0 | |
| parent | 9fbc5688dcbb2cad6258a38ecd54fe0462af2fb4 (diff) | |
| parent | 064fefb810eab07d4ddde3dd50537a6236567423 (diff) | |
| download | nova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.tar.gz nova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.tar.xz nova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.zip | |
Merge "Adds evacuate method to compute.api"
| -rw-r--r-- | nova/compute/api.py | 33 | ||||
| -rw-r--r-- | nova/compute/cells_api.py | 7 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute.py | 101 | ||||
| -rw-r--r-- | nova/tests/compute/test_compute_cells.py | 3 |
4 files changed, 144 insertions, 0 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index 034b875a6..7ce0a74b8 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -2320,6 +2320,39 @@ class API(base.Base): self.scheduler_rpcapi.live_migration(context, block_migration, disk_over_commit, instance, host_name) + @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED], + task_state=[None]) + def evacuate(self, context, instance, host, on_shared_storage, + admin_password=None): + """Running evacuate to target host. + + Checking vm compute host state, if the host not in expected_state, + raising an exception. + """ + LOG.debug(_('vm evacuation scheduled')) + host = instance['host'] + service = self.db.service_get_by_compute_host(context, host) + if self.servicegroup_api.service_is_up(service): + msg = (_('Instance compute service state on %(host)s ' + 'expected to be down, but it was up.' + ) % locals()) + LOG.error(msg) + raise exception.ComputeServiceUnavailable(msg) + + instance = self.update(context, instance, expected_task_state=None, + task_state=task_states.REBUILDING) + return self.compute_rpcapi.rebuild_instance(context, + instance=instance, + new_pass=admin_password, + injected_files=None, + image_ref=None, + orig_image_ref=None, + orig_sys_metadata=None, + bdms=None, + recreate=True, + on_shared_storage=on_shared_storage, + host=host) + class HostAPI(base.Base): """Sub-set of the Compute Manager API for managing host operations.""" diff --git a/nova/compute/cells_api.py b/nova/compute/cells_api.py index d5427a04b..f3a6fb1af 100644 --- a/nova/compute/cells_api.py +++ b/nova/compute/cells_api.py @@ -278,6 +278,13 @@ class ComputeCellsAPI(compute_api.API): **kwargs) self._cast_to_cells(context, instance, 'rebuild', *args, **kwargs) + @validate_cell + def evacuate(self, context, instance, *args, **kwargs): + """Evacuate the given instance with the provided attributes.""" + super(ComputeCellsAPI, self).evacuate(context, instance, *args, + **kwargs) + self._cast_to_cells(context, instance, 'evacuate', *args, **kwargs) + @check_instance_state(vm_state=[vm_states.RESIZED]) @validate_cell def revert_resize(self, context, instance): diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index b5a8b91a2..a745a8874 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -5933,6 +5933,107 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, instance['uuid']) + def test_evacuate(self): + instance = jsonutils.to_primitive(self._create_fake_instance()) + instance_uuid = instance['uuid'] + instance = db.instance_get_by_uuid(self.context, instance_uuid) + self.assertEqual(instance['task_state'], None) + + def fake_service_is_up(*args, **kwargs): + return False + + self.stubs.Set(self.compute_api.servicegroup_api, 'service_is_up', + fake_service_is_up) + self.compute_api.evacuate(self.context.elevated(), + instance, + host='fake_dest_host', + on_shared_storage=True, + admin_password=None) + + instance = db.instance_get_by_uuid(self.context, instance_uuid) + self.assertEqual(instance['task_state'], task_states.REBUILDING) + + db.instance_destroy(self.context, instance['uuid']) + + def test_fail_evacuate_from_non_existing_host(self): + inst = {} + inst['vm_state'] = vm_states.ACTIVE + inst['image_ref'] = FAKE_IMAGE_REF + inst['reservation_id'] = 'r-fakeres' + inst['launch_time'] = '10' + inst['user_id'] = self.user_id + inst['project_id'] = self.project_id + inst['host'] = 'fake_host' + inst['node'] = NODENAME + type_id = instance_types.get_instance_type_by_name('m1.tiny')['id'] + inst['instance_type_id'] = type_id + inst['ami_launch_index'] = 0 + inst['memory_mb'] = 0 + inst['vcpus'] = 0 + inst['root_gb'] = 0 + inst['ephemeral_gb'] = 0 + inst['architecture'] = 'x86_64' + inst['os_type'] = 'Linux' + + instance = jsonutils.to_primitive(db.instance_create(self.context, + inst)) + instance_uuid = instance['uuid'] + instance = db.instance_get_by_uuid(self.context, instance_uuid) + self.assertEqual(instance['task_state'], None) + + self.assertRaises(exception.ComputeHostNotFound, + self.compute_api.evacuate, self.context.elevated(), instance, + host='fake_dest_host', on_shared_storage=True, + admin_password=None) + + db.instance_destroy(self.context, instance['uuid']) + + def test_fail_evacuate_from_running_host(self): + instance = jsonutils.to_primitive(self._create_fake_instance()) + instance_uuid = instance['uuid'] + instance = db.instance_get_by_uuid(self.context, instance_uuid) + self.assertEqual(instance['task_state'], None) + + def fake_service_is_up(*args, **kwargs): + return True + + self.stubs.Set(self.compute_api.servicegroup_api, 'service_is_up', + fake_service_is_up) + + self.assertRaises(exception.ComputeServiceUnavailable, + self.compute_api.evacuate, self.context.elevated(), instance, + host='fake_dest_host', on_shared_storage=True, + admin_password=None) + + db.instance_destroy(self.context, instance['uuid']) + + def test_fail_evacuate_instance_in_wrong_state(self): + instances = [ + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.BUILDING})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.PAUSED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.SUSPENDED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.RESCUED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.RESIZED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.SOFT_DELETED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.DELETED})), + jsonutils.to_primitive(self._create_fake_instance( + {'vm_state': vm_states.ERROR})) + ] + + for instance in instances: + self.assertRaises(exception.InstanceInvalidState, + self.compute_api.evacuate, self.context, instance, + host='fake_dest_host', on_shared_storage=True, + admin_password=None) + db.instance_destroy(self.context, instance['uuid']) + def fake_rpc_method(context, topic, msg, do_cast=True): pass diff --git a/nova/tests/compute/test_compute_cells.py b/nova/tests/compute/test_compute_cells.py index df78c37f3..8ba35e033 100644 --- a/nova/tests/compute/test_compute_cells.py +++ b/nova/tests/compute/test_compute_cells.py @@ -168,6 +168,9 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase): self.skipTest("This test is failing due to TypeError: " "detach_volume() takes exactly 3 arguments (4 given).") + def test_evacuate(self): + self.skipTest("Test is incompatible with cells.") + class CellsComputePolicyTestCase(test_compute.ComputePolicyTestCase): def setUp(self): |
