diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 943cf85f0a30..f6f261af9c5b 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -7443,35 +7443,6 @@ class ComputeAPITestCase(BaseTestCase): self.compute.terminate_instance(self.context, self._objectify(inst_ref), [], []) - def test_rescue_unrescue(self): - instance = jsonutils.to_primitive(self._create_fake_instance()) - instance_uuid = instance['uuid'] - self.compute.run_instance(self.context, instance, {}, {}, None, None, - None, True, None, False) - - instance = db.instance_get_by_uuid(self.context, instance_uuid) - self.assertEqual(instance['vm_state'], vm_states.ACTIVE) - self.assertIsNone(instance['task_state']) - - self.compute_api.rescue(self.context, self._objectify(instance)) - - instance = db.instance_get_by_uuid(self.context, instance_uuid) - self.assertEqual(instance['vm_state'], vm_states.ACTIVE) - self.assertEqual(instance['task_state'], task_states.RESCUING) - - params = {'vm_state': vm_states.RESCUED, 'task_state': None} - db.instance_update(self.context, instance_uuid, params) - - instance = db.instance_get_by_uuid(self.context, instance_uuid) - self.compute_api.unrescue(self.context, self._objectify(instance)) - - instance = db.instance_get_by_uuid(self.context, instance_uuid) - self.assertEqual(instance['vm_state'], vm_states.RESCUED) - self.assertEqual(instance['task_state'], task_states.UNRESCUING) - - self.compute.terminate_instance(self.context, - self._objectify(instance), [], []) - def _fake_rescue_block_devices(self, instance, status="in-use"): fake_bdms = block_device_obj.block_device_make_list(self.context, [fake_block_device.FakeDbBlockDeviceDict( diff --git a/nova/tests/compute/test_compute_api.py b/nova/tests/compute/test_compute_api.py index 9c977078841b..168aeb48c46a 100644 --- a/nova/tests/compute/test_compute_api.py +++ b/nova/tests/compute/test_compute_api.py @@ -13,6 +13,7 @@ """Unit tests for compute API.""" +import contextlib import copy import datetime import iso8601 @@ -2004,6 +2005,67 @@ class _ComputeAPIUnitTestMixIn(object): fake_index) destroy.assert_called_once_with(self.context) + def _test_rescue(self, vm_state): + instance = self._create_instance_obj(params={'vm_state': vm_state}) + bdms = [] + with contextlib.nested( + mock.patch.object(block_device_obj.BlockDeviceMappingList, + 'get_by_instance_uuid', return_value=bdms), + mock.patch.object(self.compute_api, 'is_volume_backed_instance', + return_value=False), + mock.patch.object(self.compute_api, 'update'), + mock.patch.object(self.compute_api, '_record_action_start'), + mock.patch.object(self.compute_api.compute_rpcapi, + 'rescue_instance') + ) as ( + bdm_get_by_instance_uuid, volume_backed_inst, compute_api_update, + record_action_start, rpcapi_rescue_instance + ): + self.compute_api.rescue(self.context, instance) + # assert our mock calls + bdm_get_by_instance_uuid.assert_called_once_with( + self.context, instance.uuid) + volume_backed_inst.assert_called_once_with( + self.context, instance, bdms) + compute_api_update.assert_called_once_with( + self.context, instance, task_state=task_states.RESCUING, + expected_task_state=[None]) + record_action_start.assert_called_once_with( + self.context, instance, instance_actions.RESCUE) + rpcapi_rescue_instance.assert_called_once_with( + self.context, instance=instance, rescue_password=None, + rescue_image_ref=None) + + def test_rescue_active(self): + self._test_rescue(vm_state=vm_states.ACTIVE) + + def test_rescue_stopped(self): + self._test_rescue(vm_state=vm_states.STOPPED) + + def test_rescue_error(self): + self._test_rescue(vm_state=vm_states.ERROR) + + def test_unrescue(self): + instance = self._create_instance_obj( + params={'vm_state': vm_states.RESCUED}) + with contextlib.nested( + mock.patch.object(self.compute_api, 'update'), + mock.patch.object(self.compute_api, '_record_action_start'), + mock.patch.object(self.compute_api.compute_rpcapi, + 'unrescue_instance') + ) as ( + compute_api_update, record_action_start, rpcapi_unrescue_instance + ): + self.compute_api.unrescue(self.context, instance) + # assert our mock calls + compute_api_update.assert_called_once_with( + self.context, instance, task_state=task_states.UNRESCUING, + expected_task_state=[None]) + record_action_start.assert_called_once_with( + self.context, instance, instance_actions.UNRESCUE) + rpcapi_unrescue_instance.assert_called_once_with( + self.context, instance=instance) + class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase): def setUp(self): diff --git a/nova/tests/compute/test_compute_mgr.py b/nova/tests/compute/test_compute_mgr.py index 43169a82fa98..8a678f96ad33 100644 --- a/nova/tests/compute/test_compute_mgr.py +++ b/nova/tests/compute/test_compute_mgr.py @@ -1211,6 +1211,116 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): {'uuid': 'fake-inst'}) detach.assert_called_once_with(self.context, inst_obj, bdm) + def test_rescue(self): + instance = fake_instance.fake_instance_obj( + self.context, vm_state=vm_states.ACTIVE) + fake_nw_info = network_model.NetworkInfo() + rescue_image_meta = {'id': 'fake', 'name': 'fake'} + with contextlib.nested( + mock.patch.object(instance_action_obj.InstanceActionEvent, + 'event_start'), + mock.patch.object(instance_action_obj.InstanceActionEvent, + 'event_finish_with_failure'), + mock.patch.object(self.context, 'elevated', + return_value=self.context), + mock.patch.object(self.compute, '_get_instance_nw_info', + return_value=fake_nw_info), + mock.patch.object(self.compute, '_get_rescue_image', + return_value=rescue_image_meta), + mock.patch.object(self.compute, '_notify_about_instance_usage'), + mock.patch.object(self.compute.driver, 'rescue'), + mock.patch.object(self.compute.conductor_api, + 'notify_usage_exists'), + mock.patch.object(self.compute, '_get_power_state', + return_value=power_state.RUNNING), + mock.patch.object(instance, 'save') + ) as ( + event_start, event_finish, elevated_context, get_nw_info, + get_rescue_image, notify_instance_usage, driver_rescue, + notify_usage_exists, get_power_state, instance_save + ): + self.compute.rescue_instance( + self.context, instance, rescue_password='verybadpass', + rescue_image_ref=None) + + # assert the field values on the instance object + self.assertEqual(vm_states.RESCUED, instance.vm_state) + self.assertIsNone(instance.task_state) + self.assertEqual(power_state.RUNNING, instance.power_state) + self.assertIsNotNone(instance.launched_at) + + # assert our mock calls + get_nw_info.assert_called_once_with(self.context, instance) + get_rescue_image.assert_called_once_with( + self.context, instance, None) + + extra_usage_info = {'rescue_image_name': 'fake'} + notify_calls = [ + mock.call(self.context, instance, "rescue.start", + extra_usage_info=extra_usage_info, + network_info=fake_nw_info), + mock.call(self.context, instance, "rescue.end", + extra_usage_info=extra_usage_info, + network_info=fake_nw_info) + ] + notify_instance_usage.assert_has_calls(notify_calls) + + driver_rescue.assert_called_once_with( + self.context, instance, fake_nw_info, rescue_image_meta, + 'verybadpass') + + notify_usage_exists.assert_called_once_with( + self.context, instance, current_period=True) + + instance_save.assert_called_once_with( + expected_task_state=task_states.RESCUING) + + def test_unrescue(self): + instance = fake_instance.fake_instance_obj( + self.context, vm_state=vm_states.RESCUED) + fake_nw_info = network_model.NetworkInfo() + with contextlib.nested( + mock.patch.object(instance_action_obj.InstanceActionEvent, + 'event_start'), + mock.patch.object(instance_action_obj.InstanceActionEvent, + 'event_finish_with_failure'), + mock.patch.object(self.context, 'elevated', + return_value=self.context), + mock.patch.object(self.compute, '_get_instance_nw_info', + return_value=fake_nw_info), + mock.patch.object(self.compute, '_notify_about_instance_usage'), + mock.patch.object(self.compute.driver, 'unrescue'), + mock.patch.object(self.compute, '_get_power_state', + return_value=power_state.RUNNING), + mock.patch.object(instance, 'save') + ) as ( + event_start, event_finish, elevated_context, get_nw_info, + notify_instance_usage, driver_unrescue, get_power_state, + instance_save + ): + self.compute.unrescue_instance(self.context, instance) + + # assert the field values on the instance object + self.assertEqual(vm_states.ACTIVE, instance.vm_state) + self.assertIsNone(instance.task_state) + self.assertEqual(power_state.RUNNING, instance.power_state) + + # assert our mock calls + get_nw_info.assert_called_once_with(self.context, instance) + + notify_calls = [ + mock.call(self.context, instance, "unrescue.start", + network_info=fake_nw_info), + mock.call(self.context, instance, "unrescue.end", + network_info=fake_nw_info) + ] + notify_instance_usage.assert_has_calls(notify_calls) + + driver_unrescue.assert_called_once_with(instance, fake_nw_info) + + instance_save.assert_called_once_with( + expected_task_state=task_states.UNRESCUING) + class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase): def setUp(self):