summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-02-05 01:26:25 +0000
committerGerrit Code Review <review@openstack.org>2013-02-05 01:26:25 +0000
commitf9eb7ca2ad7828c9b5a0790718d48a69b829658a (patch)
tree713f0cb05a126aa9b017227199156167e21d8aa0
parent9fbc5688dcbb2cad6258a38ecd54fe0462af2fb4 (diff)
parent064fefb810eab07d4ddde3dd50537a6236567423 (diff)
downloadnova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.tar.gz
nova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.tar.xz
nova-f9eb7ca2ad7828c9b5a0790718d48a69b829658a.zip
Merge "Adds evacuate method to compute.api"
-rw-r--r--nova/compute/api.py33
-rw-r--r--nova/compute/cells_api.py7
-rw-r--r--nova/tests/compute/test_compute.py101
-rw-r--r--nova/tests/compute/test_compute_cells.py3
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):