diff --git a/nova/compute/manager.py b/nova/compute/manager.py index df2ebde07a13..2739069ead1a 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -4751,7 +4751,11 @@ class ComputeManager(manager.Manager): expected_state = shelving_state_map[expected_state] instance.task_state = task_state instance.save(expected_task_state=expected_state) - + # Do not attempt a clean shutdown of a paused guest since some + # hypervisors will fail the clean shutdown if the guest is not + # running. + if instance.power_state == power_state.PAUSED: + clean_shutdown = False self._power_off_instance(context, instance, clean_shutdown) self.driver.snapshot(context, instance, image_id, update_task_state) diff --git a/nova/tests/unit/compute/test_shelve.py b/nova/tests/unit/compute/test_shelve.py index f41b2f47a2a1..ff3f059a2cbb 100644 --- a/nova/tests/unit/compute/test_shelve.py +++ b/nova/tests/unit/compute/test_shelve.py @@ -16,6 +16,7 @@ from oslo_utils import timeutils from nova.compute import claims from nova.compute import instance_actions +from nova.compute import power_state from nova.compute import task_states from nova.compute import utils as compute_utils from nova.compute import vm_states @@ -59,12 +60,14 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase): def _shelve_instance(self, shelved_offload_time, mock_notify, mock_notify_instance_usage, mock_get_power_state, mock_snapshot, mock_power_off, mock_terminate, - mock_get_bdms, clean_shutdown=True): + mock_get_bdms, clean_shutdown=True, + guest_power_state=power_state.RUNNING): mock_get_power_state.return_value = 123 CONF.set_override('shelved_offload_time', shelved_offload_time) host = 'fake-mini' - instance = self._create_fake_instance_obj(params={'host': host}) + instance = self._create_fake_instance_obj( + params={'host': host, 'power_state': guest_power_state}) image_id = 'fake_image_id' host = 'fake-mini' self.useFixture(utils_fixture.TimeFixture()) @@ -139,9 +142,12 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase): mock_cleanup_call_list = [] if clean_shutdown: - mock_power_off_call_list.append( - mock.call(instance, CONF.shutdown_timeout, - CONF.compute.shutdown_retry_interval)) + if guest_power_state == power_state.PAUSED: + mock_power_off_call_list.append(mock.call(instance, 0, 0)) + else: + mock_power_off_call_list.append( + mock.call(instance, CONF.shutdown_timeout, + CONF.compute.shutdown_retry_interval)) else: mock_power_off_call_list.append(mock.call(instance, 0, 0)) @@ -179,6 +185,9 @@ class ShelveComputeManagerTestCase(test_compute.BaseTestCase): def test_shelve_and_offload(self): self._shelve_instance(0) + def test_shelve_paused_instance(self): + self._shelve_instance(-1, guest_power_state=power_state.PAUSED) + @mock.patch.object(nova.virt.fake.SmallFakeDriver, 'power_off') def test_shelve_offload(self, mock_power_off): instance = self._shelve_offload()