Fix shelving a paused instance

It is possible to shelve a paused instance, but in that case the
guest is already shutdown, and some hypervisors will fail when
trying to perform a clean shutdown of a non-running guest. For
example, attempting to shelve a paused libvirt instance will
result in this error:

  libvirtError: Requested operation is not valid: domain is not running

Therefore, if the instance is paused, we don't attempt a clean
shutdown while shelving.

Related Tempest test: https://review.openstack.org/564127/

Closes-Bug: #1745529
Change-Id: I8ca25d9847d50001fbe8513a6c1dba8b697c24e4
(cherry picked from commit d5901f613c)
This commit is contained in:
LeopardMa 2018-02-07 10:21:08 +08:00 committed by Ghanshyam Mann
parent 7365232f56
commit e0534442b5
2 changed files with 19 additions and 6 deletions

View File

@ -4323,7 +4323,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)

View File

@ -16,6 +16,7 @@ from oslo_utils import fixture as utils_fixture
from oslo_utils import timeutils
from nova.compute import claims
from nova.compute import power_state
from nova.compute import task_states
from nova.compute import vm_states
import nova.conf
@ -55,12 +56,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,
clean_shutdown=True):
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())
@ -130,9 +133,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,
self.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,
self.compute.SHUTDOWN_RETRY_INTERVAL))
else:
mock_power_off_call_list.append(mock.call(instance, 0, 0))
@ -170,6 +176,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()