Merge "VMware: detach cinder volume when instance destroyed"
This commit is contained in:
commit
e354ad9608
|
@ -39,6 +39,7 @@ from nova import block_device
|
|||
from nova.compute import api as compute_api
|
||||
from nova.compute import power_state
|
||||
from nova.compute import task_states
|
||||
from nova.compute import vm_states
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova.image import glance
|
||||
|
@ -662,6 +663,49 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
self._create_vm()
|
||||
self.assertTrue(self.cd_attach_called)
|
||||
|
||||
@mock.patch.object(vmops.VMwareVMOps, 'power_off')
|
||||
@mock.patch.object(driver.VMwareVCDriver, 'detach_volume')
|
||||
@mock.patch.object(vmops.VMwareVMOps, 'destroy')
|
||||
def test_destroy_with_attached_volumes(self,
|
||||
mock_destroy,
|
||||
mock_detach_volume,
|
||||
mock_power_off):
|
||||
self._create_vm()
|
||||
connection_info = {'data': 'fake-data', 'serial': 'volume-fake-id'}
|
||||
bdm = [{'connection_info': connection_info,
|
||||
'disk_bus': 'fake-bus',
|
||||
'device_name': 'fake-name',
|
||||
'mount_device': '/dev/sdb'}]
|
||||
bdi = {'block_device_mapping': bdm, 'root_device_name': '/dev/sda'}
|
||||
self.assertNotEqual(vm_states.STOPPED, self.instance.vm_state)
|
||||
self.conn.destroy(self.context, self.instance, self.network_info,
|
||||
block_device_info=bdi)
|
||||
mock_power_off.assert_called_once_with(self.instance)
|
||||
self.assertEqual(vm_states.STOPPED, self.instance.vm_state)
|
||||
mock_detach_volume.assert_called_once_with(
|
||||
connection_info, self.instance, 'fake-name')
|
||||
mock_destroy.assert_called_once_with(self.instance, True)
|
||||
|
||||
@mock.patch.object(driver.VMwareVCDriver, 'detach_volume',
|
||||
side_effect=exception.StorageError(reason='oh man'))
|
||||
@mock.patch.object(vmops.VMwareVMOps, 'destroy')
|
||||
def test_destroy_with_attached_volumes_with_exception(self,
|
||||
mock_destroy,
|
||||
mock_detach_volume):
|
||||
self._create_vm()
|
||||
connection_info = {'data': 'fake-data', 'serial': 'volume-fake-id'}
|
||||
bdm = [{'connection_info': connection_info,
|
||||
'disk_bus': 'fake-bus',
|
||||
'device_name': 'fake-name',
|
||||
'mount_device': '/dev/sdb'}]
|
||||
bdi = {'block_device_mapping': bdm, 'root_device_name': '/dev/sda'}
|
||||
self.assertRaises(exception.StorageError,
|
||||
self.conn.destroy, self.context, self.instance,
|
||||
self.network_info, block_device_info=bdi)
|
||||
mock_detach_volume.assert_called_once_with(
|
||||
connection_info, self.instance, 'fake-name')
|
||||
self.assertFalse(mock_destroy.called)
|
||||
|
||||
def test_spawn(self):
|
||||
self._create_vm()
|
||||
info = self._get_info()
|
||||
|
|
|
@ -25,6 +25,7 @@ from oslo_config import cfg
|
|||
from oslo_log import log as logging
|
||||
from oslo_log import versionutils
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import excutils
|
||||
from oslo_vmware import api
|
||||
from oslo_vmware import exceptions as vexc
|
||||
from oslo_vmware import pbm
|
||||
|
@ -32,9 +33,11 @@ from oslo_vmware import vim
|
|||
from oslo_vmware import vim_util
|
||||
import six
|
||||
|
||||
from nova.compute import task_states
|
||||
from nova.compute import vm_states
|
||||
from nova import exception
|
||||
from nova import utils
|
||||
from nova.i18n import _, _LI, _LW
|
||||
from nova.i18n import _, _LI, _LE, _LW
|
||||
from nova.virt import driver
|
||||
from nova.virt.vmwareapi import constants
|
||||
from nova.virt.vmwareapi import error_util
|
||||
|
@ -578,6 +581,36 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
if not instance.node:
|
||||
return
|
||||
|
||||
# A resize uses the same instance on the VC. We do not delete that
|
||||
# VM in the event of a revert
|
||||
if instance.task_state == task_states.RESIZE_REVERTING:
|
||||
return
|
||||
|
||||
# We need to detach attached volumes
|
||||
if block_device_info is not None:
|
||||
block_device_mapping = driver.block_device_info_get_mapping(
|
||||
block_device_info)
|
||||
if block_device_mapping:
|
||||
# Certain disk types, for example 'IDE' do not support hot
|
||||
# plugging. Hence we need to power off the instance and update
|
||||
# the instance state.
|
||||
self._vmops.power_off(instance)
|
||||
# TODO(garyk): update the volumeops to read the state form the
|
||||
# VM instead of relying on a instance flag
|
||||
instance.vm_state = vm_states.STOPPED
|
||||
for disk in block_device_mapping:
|
||||
connection_info = disk['connection_info']
|
||||
try:
|
||||
self.detach_volume(connection_info, instance,
|
||||
disk.get('device_name'))
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Failed to detach %(device_name)s. "
|
||||
"Exception: %(exc)s"),
|
||||
{'device_name': disk.get('device_name'),
|
||||
'exc': e},
|
||||
instance=instance)
|
||||
|
||||
self._vmops.destroy(instance, destroy_disks)
|
||||
|
||||
def pause(self, instance):
|
||||
|
|
|
@ -979,9 +979,6 @@ class VMwareVMOps(object):
|
|||
2. Un-register.
|
||||
3. Delete the contents of the folder holding the VM related data.
|
||||
"""
|
||||
if instance.task_state == task_states.RESIZE_REVERTING:
|
||||
return
|
||||
|
||||
LOG.debug("Destroying instance", instance=instance)
|
||||
self._destroy_instance(instance, destroy_disks=destroy_disks)
|
||||
LOG.debug("Instance destroyed", instance=instance)
|
||||
|
|
Loading…
Reference in New Issue