Xenapi: Attempt clean shutdown when deleting instance
A guest should be given the chance to shut down cleanly even when being deleted in case there is a volume attached. The volume might be re-used later so we should minimize the risk of filesystem corruption. Change-Id: I449fa7f2ab0ef34d0d0d4e2bd648c628737faaa8
This commit is contained in:
parent
1e41005f5a
commit
2363fd18ba
@ -63,6 +63,8 @@ class VMOpsTestCase(VMOpsTestBase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(VMOpsTestCase, self).setUp()
|
super(VMOpsTestCase, self).setUp()
|
||||||
self._setup_mock_vmops()
|
self._setup_mock_vmops()
|
||||||
|
self.context = context.RequestContext('user', 'project')
|
||||||
|
self.instance = fake_instance.fake_instance_obj(self.context)
|
||||||
|
|
||||||
def _setup_mock_vmops(self, product_brand=None, product_version=None):
|
def _setup_mock_vmops(self, product_brand=None, product_version=None):
|
||||||
self._session = self._get_mock_session(product_brand, product_version)
|
self._session = self._get_mock_session(product_brand, product_version)
|
||||||
@ -141,6 +143,44 @@ class VMOpsTestCase(VMOpsTestBase):
|
|||||||
self.assertRaises(exception.InstanceNotFound,
|
self.assertRaises(exception.InstanceNotFound,
|
||||||
self._vmops._get_vm_opaque_ref, instance)
|
self._vmops._get_vm_opaque_ref, instance)
|
||||||
|
|
||||||
|
@mock.patch.object(vm_utils, 'destroy_vm')
|
||||||
|
@mock.patch.object(vm_utils, 'clean_shutdown_vm')
|
||||||
|
@mock.patch.object(vm_utils, 'hard_shutdown_vm')
|
||||||
|
def test_clean_shutdown_no_bdm_on_destroy(self, hard_shutdown_vm,
|
||||||
|
clean_shutdown_vm, destroy_vm):
|
||||||
|
vm_ref = 'vm_ref'
|
||||||
|
self._vmops._destroy(self.instance, vm_ref, destroy_disks=False)
|
||||||
|
hard_shutdown_vm.assert_called_once_with(self._vmops._session,
|
||||||
|
self.instance, vm_ref)
|
||||||
|
self.assertEqual(0, clean_shutdown_vm.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(vm_utils, 'destroy_vm')
|
||||||
|
@mock.patch.object(vm_utils, 'clean_shutdown_vm')
|
||||||
|
@mock.patch.object(vm_utils, 'hard_shutdown_vm')
|
||||||
|
def test_clean_shutdown_with_bdm_on_destroy(self, hard_shutdown_vm,
|
||||||
|
clean_shutdown_vm, destroy_vm):
|
||||||
|
vm_ref = 'vm_ref'
|
||||||
|
block_device_info = {'block_device_mapping': ['fake']}
|
||||||
|
self._vmops._destroy(self.instance, vm_ref, destroy_disks=False,
|
||||||
|
block_device_info=block_device_info)
|
||||||
|
clean_shutdown_vm.assert_called_once_with(self._vmops._session,
|
||||||
|
self.instance, vm_ref)
|
||||||
|
self.assertEqual(0, hard_shutdown_vm.call_count)
|
||||||
|
|
||||||
|
@mock.patch.object(vm_utils, 'destroy_vm')
|
||||||
|
@mock.patch.object(vm_utils, 'clean_shutdown_vm', return_value=False)
|
||||||
|
@mock.patch.object(vm_utils, 'hard_shutdown_vm')
|
||||||
|
def test_clean_shutdown_with_bdm_failed_on_destroy(self, hard_shutdown_vm,
|
||||||
|
clean_shutdown_vm, destroy_vm):
|
||||||
|
vm_ref = 'vm_ref'
|
||||||
|
block_device_info = {'block_device_mapping': ['fake']}
|
||||||
|
self._vmops._destroy(self.instance, vm_ref, destroy_disks=False,
|
||||||
|
block_device_info=block_device_info)
|
||||||
|
clean_shutdown_vm.assert_called_once_with(self._vmops._session,
|
||||||
|
self.instance, vm_ref)
|
||||||
|
hard_shutdown_vm.assert_called_once_with(self._vmops._session,
|
||||||
|
self.instance, vm_ref)
|
||||||
|
|
||||||
|
|
||||||
class InjectAutoDiskConfigTestCase(VMOpsTestBase):
|
class InjectAutoDiskConfigTestCase(VMOpsTestBase):
|
||||||
def test_inject_auto_disk_config_when_present(self):
|
def test_inject_auto_disk_config_when_present(self):
|
||||||
|
@ -1472,11 +1472,11 @@ class VMOps(object):
|
|||||||
if rescue_vm_ref:
|
if rescue_vm_ref:
|
||||||
self._destroy_rescue_instance(rescue_vm_ref, vm_ref)
|
self._destroy_rescue_instance(rescue_vm_ref, vm_ref)
|
||||||
|
|
||||||
# NOTE(sirp): `block_device_info` is not used, information about which
|
# NOTE(sirp): information about which volumes should be detached is
|
||||||
# volumes should be detached is determined by the
|
# determined by the VBD.other_config['osvol'] attribute
|
||||||
# VBD.other_config['osvol'] attribute
|
# NOTE(alaski): `block_device_info` is used to efficiently determine if
|
||||||
# NOTE(alaski): `block_device_info` is used to determine if there's a
|
# there's a volume attached, or which volumes to cleanup if there is
|
||||||
# volume still attached if the VM is not present.
|
# no VM present.
|
||||||
return self._destroy(instance, vm_ref, network_info=network_info,
|
return self._destroy(instance, vm_ref, network_info=network_info,
|
||||||
destroy_disks=destroy_disks,
|
destroy_disks=destroy_disks,
|
||||||
block_device_info=block_device_info)
|
block_device_info=block_device_info)
|
||||||
@ -1524,6 +1524,14 @@ class VMOps(object):
|
|||||||
volume_id, instance=instance)
|
volume_id, instance=instance)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# NOTE(alaski): Attempt clean shutdown first if there's an attached
|
||||||
|
# volume to reduce the risk of corruption.
|
||||||
|
if block_device_info and block_device_info['block_device_mapping']:
|
||||||
|
if not vm_utils.clean_shutdown_vm(self._session, instance, vm_ref):
|
||||||
|
LOG.debug("Clean shutdown did not complete successfully, "
|
||||||
|
"trying hard shutdown.", instance=instance)
|
||||||
|
vm_utils.hard_shutdown_vm(self._session, instance, vm_ref)
|
||||||
|
else:
|
||||||
vm_utils.hard_shutdown_vm(self._session, instance, vm_ref)
|
vm_utils.hard_shutdown_vm(self._session, instance, vm_ref)
|
||||||
|
|
||||||
if destroy_disks:
|
if destroy_disks:
|
||||||
|
Loading…
Reference in New Issue
Block a user