Merge "VMware: detach cinder volume when instance destroyed"

This commit is contained in:
Jenkins 2015-06-17 21:01:59 +00:00 committed by Gerrit Code Review
commit e354ad9608
3 changed files with 78 additions and 4 deletions

View File

@ -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()

View File

@ -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):

View File

@ -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)