From 76fc08e52dfe92b90c8ad47aee25b9d1d34f1cee Mon Sep 17 00:00:00 2001 From: jichenjc Date: Sun, 2 Mar 2014 03:17:39 +0800 Subject: [PATCH] Revert pause/unpause state when host restart Give following scenario for instance task state 1) start to pause an active instance 2) the nova-compute died because of unexpected situation 3) when nova-compute start again , it's task state is pausing it should be changed to None because host restarted Also ,for the paused instance and its state is unpausing, we need to unpase the instance. Change-Id: If72a36dafd894ac47c0b255d701a3f9965ff2590 Closes-Bug: #1290639 --- nova/compute/manager.py | 36 ++++++++++++---- nova/tests/unit/compute/test_compute_mgr.py | 46 +++++++++++++++++++++ 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 3a0206f8303c..3f376ee33d5c 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -936,17 +936,37 @@ class ComputeManager(manager.Manager): return elif (current_power_state == power_state.RUNNING and - instance.task_state in [task_states.REBOOT_STARTED, - task_states.REBOOT_STARTED_HARD]): - LOG.warning(_("Instance in transitional state " - "(%(task_state)s) at start-up and power state " - "is (%(power_state)s), clearing task state"), - {'task_state': instance['task_state'], - 'power_state': current_power_state}, - instance=instance) + instance.task_state in [task_states.REBOOT_STARTED, + task_states.REBOOT_STARTED_HARD, + task_states.PAUSING, + task_states.UNPAUSING]): + LOG.warn(_LW("Instance in transitional state " + "(%(task_state)s) at start-up and power state " + "is (%(power_state)s), clearing task state"), + {'task_state': instance.task_state, + 'power_state': current_power_state}, + instance=instance) instance.task_state = None instance.vm_state = vm_states.ACTIVE instance.save() + elif (current_power_state == power_state.PAUSED and + instance.task_state == task_states.UNPAUSING): + LOG.warn(_LW("Instance in transitional state " + "(%(task_state)s) at start-up and power state " + "is (%(power_state)s), clearing task state " + "and unpausing the instance"), + {'task_state': instance.task_state, + 'power_state': current_power_state}, + instance=instance) + try: + self.unpause_instance(context, instance) + except NotImplementedError: + # Some virt driver didn't support pause and unpause + pass + except Exception: + LOG.exception(_LE('Failed to unpause instance'), + instance=instance) + return if instance.task_state == task_states.POWERING_OFF: try: diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 04b9f6bdc6ab..707ebcd1426d 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -598,6 +598,23 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): assert_called_once_with(self.context, instance) self.assertIsNone(instance.task_state) + @mock.patch('nova.compute.manager.ComputeManager._get_power_state', + return_value=power_state.RUNNING) + @mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid') + def _test_init_instance_cleans_task_states(self, powerstate, state, + mock_get_uuid, mock_get_power_state): + instance = objects.Instance(self.context) + instance.uuid = 'fake-uuid' + instance.info_cache = None + instance.power_state = power_state.RUNNING + instance.vm_state = vm_states.ACTIVE + instance.task_state = state + mock_get_power_state.return_value = powerstate + + self.compute._init_instance(self.context, instance) + + return instance + def test_init_instance_cleans_image_state_pending_upload(self): instance = objects.Instance(self.context) instance.uuid = 'foo' @@ -626,6 +643,35 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): instance.task_state = task_states.IMAGE_SNAPSHOT_PENDING self._test_init_instance_cleans_image_states(instance) + @mock.patch.object(objects.Instance, 'save') + def test_init_instance_cleans_running_pausing(self, mock_save): + instance = self._test_init_instance_cleans_task_states( + power_state.RUNNING, task_states.PAUSING) + mock_save.assert_called_once_with() + self.assertEqual(vm_states.ACTIVE, instance.vm_state) + self.assertIsNone(instance.task_state) + + @mock.patch.object(objects.Instance, 'save') + def test_init_instance_cleans_running_unpausing(self, mock_save): + instance = self._test_init_instance_cleans_task_states( + power_state.RUNNING, task_states.UNPAUSING) + mock_save.assert_called_once_with() + self.assertEqual(vm_states.ACTIVE, instance.vm_state) + self.assertIsNone(instance.task_state) + + @mock.patch('nova.compute.manager.ComputeManager.unpause_instance') + def test_init_instance_cleans_paused_unpausing(self, mock_unpause): + + def fake_unpause(context, instance): + instance.task_state = None + + mock_unpause.side_effect = fake_unpause + instance = self._test_init_instance_cleans_task_states( + power_state.PAUSED, task_states.UNPAUSING) + mock_unpause.assert_called_once_with(self.context, instance) + self.assertEqual(vm_states.ACTIVE, instance.vm_state) + self.assertIsNone(instance.task_state) + def test_init_instance_errors_when_not_migrating(self): instance = objects.Instance(self.context) instance.uuid = 'foo'