diff --git a/nova/compute/api.py b/nova/compute/api.py index 853866346aee..7f337b82d358 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -2229,23 +2229,25 @@ class API(base.Base): instance_uuid=instance['uuid'], state=instance['vm_state'], method='soft reboot') - if ((reboot_type == 'SOFT' and - instance['task_state'] in - (task_states.REBOOTING, task_states.REBOOTING_HARD, - task_states.REBOOT_PENDING, task_states.REBOOT_STARTED)) or - (reboot_type == 'HARD' and - instance['task_state'] == task_states.REBOOTING_HARD)): + if reboot_type == 'SOFT' and instance['task_state'] is not None: raise exception.InstanceInvalidState( attr='task_state', instance_uuid=instance['uuid'], state=instance['task_state'], method='reboot') + expected_task_state = [None] + if reboot_type == 'HARD': + expected_task_state.extend([task_states.REBOOTING, + task_states.REBOOT_PENDING, + task_states.REBOOT_STARTED, + task_states.REBOOTING_HARD, + task_states.RESUMING, + task_states.UNPAUSING, + task_states.SUSPENDING]) state = {'SOFT': task_states.REBOOTING, 'HARD': task_states.REBOOTING_HARD}[reboot_type] instance.task_state = state - instance.save(expected_task_state=[None, task_states.REBOOTING, - task_states.REBOOT_PENDING, - task_states.REBOOT_STARTED]) + instance.save(expected_task_state=expected_task_state) self._record_action_start(context, instance, instance_actions.REBOOT) diff --git a/nova/tests/unit/api/openstack/compute/plugins/v3/test_server_actions.py b/nova/tests/unit/api/openstack/compute/plugins/v3/test_server_actions.py index 0bfe0eb2d4ca..0887a04d1347 100644 --- a/nova/tests/unit/api/openstack/compute/plugins/v3/test_server_actions.py +++ b/nova/tests/unit/api/openstack/compute/plugins/v3/test_server_actions.py @@ -246,15 +246,13 @@ class ServerActionsControllerTest(test.TestCase): task_state=task_states.REBOOTING)) self.controller._action_reboot(req, FAKE_UUID, body) - def test_reboot_hard_with_hard_in_progress_raises_conflict(self): + def test_reboot_hard_with_hard_in_progress(self): body = dict(reboot=dict(type="HARD")) req = fakes.HTTPRequestV3.blank(self.url) self.stubs.Set(db, 'instance_get_by_uuid', fakes.fake_instance_get(vm_state=vm_states.ACTIVE, task_state=task_states.REBOOTING_HARD)) - self.assertRaises(webob.exc.HTTPConflict, - self.controller._action_reboot, - req, FAKE_UUID, body) + self.controller._action_reboot(req, FAKE_UUID, body) def test_rebuild_accepted_minimum(self): return_server = fakes.fake_instance_get(image_ref='2', diff --git a/nova/tests/unit/api/openstack/compute/test_server_actions.py b/nova/tests/unit/api/openstack/compute/test_server_actions.py index 16f8ce14bf38..6864230a851c 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_actions.py +++ b/nova/tests/unit/api/openstack/compute/test_server_actions.py @@ -310,15 +310,13 @@ class ServerActionsControllerTest(test.TestCase): task_state=task_states.REBOOTING)) self.controller._action_reboot(req, FAKE_UUID, body) - def test_reboot_hard_with_hard_in_progress_raises_conflict(self): + def test_reboot_hard_with_hard_in_progress(self): body = dict(reboot=dict(type="HARD")) req = fakes.HTTPRequest.blank(self.url) self.stubs.Set(db, 'instance_get_by_uuid', fakes.fake_instance_get(vm_state=vm_states.ACTIVE, task_state=task_states.REBOOTING_HARD)) - self.assertRaises(webob.exc.HTTPConflict, - self.controller._action_reboot, - req, FAKE_UUID, body) + self.controller._action_reboot(req, FAKE_UUID, body) def test_rebuild_preserve_ephemeral_is_ignored_when_ext_not_loaded(self): return_server = fakes.fake_instance_get(image_ref='2', diff --git a/nova/tests/unit/compute/test_compute_api.py b/nova/tests/unit/compute/test_compute_api.py index 10ac29d3dd09..8cb73846a40c 100644 --- a/nova/tests/unit/compute/test_compute_api.py +++ b/nova/tests/unit/compute/test_compute_api.py @@ -421,9 +421,16 @@ class _ComputeAPIUnitTestMixIn(object): self.mox.StubOutWithMock(self.compute_api, '_record_action_start') self.mox.StubOutWithMock(self.compute_api, 'update') self.mox.StubOutWithMock(inst, 'save') - inst.save(expected_task_state=[None, task_states.REBOOTING, - task_states.REBOOT_PENDING, - task_states.REBOOT_STARTED]) + expected_task_state = [None] + if reboot_type == 'HARD': + expected_task_state.extend([task_states.REBOOTING, + task_states.REBOOT_PENDING, + task_states.REBOOT_STARTED, + task_states.REBOOTING_HARD, + task_states.RESUMING, + task_states.UNPAUSING, + task_states.SUSPENDING]) + inst.save(expected_task_state=expected_task_state) self.compute_api._record_action_start(self.context, inst, instance_actions.REBOOT) @@ -469,6 +476,22 @@ class _ComputeAPIUnitTestMixIn(object): def test_reboot_hard_rescued(self): self._test_reboot_type_fails('HARD', vm_state=vm_states.RESCUED) + def test_reboot_hard_resuming(self): + self._test_reboot_type(vm_states.ACTIVE, + 'HARD', task_state=task_states.RESUMING) + + def test_reboot_hard_pausing(self): + self._test_reboot_type(vm_states.ACTIVE, + 'HARD', task_state=task_states.PAUSING) + + def test_reboot_hard_unpausing(self): + self._test_reboot_type(vm_states.ACTIVE, + 'HARD', task_state=task_states.UNPAUSING) + + def test_reboot_hard_suspending(self): + self._test_reboot_type(vm_states.ACTIVE, + 'HARD', task_state=task_states.SUSPENDING) + def test_reboot_hard_error_not_launched(self): self._test_reboot_type_fails('HARD', vm_state=vm_states.ERROR, launched_at=None) @@ -510,6 +533,18 @@ class _ComputeAPIUnitTestMixIn(object): self._test_reboot_type_fails('SOFT', vm_state=vm_states.ERROR, launched_at=None) + def test_reboot_soft_resuming(self): + self._test_reboot_type_fails('SOFT', task_state=task_states.RESUMING) + + def test_reboot_soft_pausing(self): + self._test_reboot_type_fails('SOFT', task_state=task_states.PAUSING) + + def test_reboot_soft_unpausing(self): + self._test_reboot_type_fails('SOFT', task_state=task_states.UNPAUSING) + + def test_reboot_soft_suspending(self): + self._test_reboot_type_fails('SOFT', task_state=task_states.SUSPENDING) + def _test_delete_resizing_part(self, inst, deltas): fake_db_migration = test_migration.fake_db_migration() migration = objects.Migration._from_db_object(