Merge "VMware: manage_existing for VMDK driver"
This commit is contained in:
commit
f674bd602b
cinder
releasenotes/notes
@ -2413,6 +2413,53 @@ class VMwareVcVmdkDriverTestCase(test.TestCase):
|
||||
existing_ref))
|
||||
get_existing.assert_called_once_with(existing_ref)
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_existing')
|
||||
@mock.patch.object(VMDK_DRIVER, '_create_backing')
|
||||
@mock.patch.object(VMDK_DRIVER, 'volumeops')
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_ds_name_folder_path')
|
||||
@mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.'
|
||||
'_get_disk_type')
|
||||
def test_manage_existing(
|
||||
self, get_disk_type, get_ds_name_folder_path, vops,
|
||||
create_backing, get_existing):
|
||||
|
||||
vm = mock.sentinel.vm
|
||||
src_path = mock.sentinel.src_path
|
||||
disk_backing = mock.Mock(fileName=src_path)
|
||||
disk_device = mock.Mock(backing=disk_backing, capacityInKB=1048576)
|
||||
get_existing.return_value = (vm, disk_device)
|
||||
|
||||
backing = mock.sentinel.backing
|
||||
create_backing.return_value = backing
|
||||
|
||||
src_dc = mock.sentinel.src_dc
|
||||
dest_dc = mock.sentinel.dest_dc
|
||||
vops.get_dc.side_effect = [src_dc, dest_dc]
|
||||
|
||||
volume = self._create_volume_dict()
|
||||
ds_name = "ds1"
|
||||
folder_path = "%s/" % volume['name']
|
||||
get_ds_name_folder_path.return_value = (ds_name, folder_path)
|
||||
|
||||
disk_type = mock.sentinel.disk_type
|
||||
get_disk_type.return_value = disk_type
|
||||
|
||||
existing_ref = mock.sentinel.existing_ref
|
||||
self._driver.manage_existing(volume, existing_ref)
|
||||
|
||||
get_existing.assert_called_once_with(existing_ref)
|
||||
create_backing.assert_called_once_with(
|
||||
volume, create_params={vmdk.CREATE_PARAM_DISK_LESS: True})
|
||||
vops.detach_disk_from_backing.assert_called_once_with(vm, disk_device)
|
||||
dest_path = "[%s] %s%s.vmdk" % (ds_name, folder_path, volume['name'])
|
||||
vops.move_vmdk_file.assert_called_once_with(
|
||||
src_dc, src_path, dest_path, dest_dc_ref=dest_dc)
|
||||
vops.attach_disk_to_backing.assert_called_once_with(
|
||||
backing, disk_device.capacityInKB, disk_type, 'lsiLogic',
|
||||
dest_path)
|
||||
vops.update_backing_disk_uuid.assert_called_once_with(backing,
|
||||
volume['id'])
|
||||
|
||||
@mock.patch('oslo_vmware.api.VMwareAPISession')
|
||||
def test_session(self, apiSession):
|
||||
self._session = None
|
||||
|
@ -1326,6 +1326,39 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
spec=reconfig_spec)
|
||||
self.session.wait_for_task.assert_called_once_with(task)
|
||||
|
||||
def test_create_spec_for_disk_remove(self):
|
||||
disk_spec = mock.Mock()
|
||||
self.session.vim.client.factory.create.return_value = disk_spec
|
||||
|
||||
disk_device = mock.sentinel.disk_device
|
||||
self.vops._create_spec_for_disk_remove(disk_device)
|
||||
|
||||
self.session.vim.client.factory.create.assert_called_once_with(
|
||||
'ns0:VirtualDeviceConfigSpec')
|
||||
self.assertEqual('remove', disk_spec.operation)
|
||||
self.assertEqual(disk_device, disk_spec.device)
|
||||
|
||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||
'_create_spec_for_disk_remove')
|
||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||
'_reconfigure_backing')
|
||||
def test_detach_disk_from_backing(self, reconfigure_backing, create_spec):
|
||||
disk_spec = mock.sentinel.disk_spec
|
||||
create_spec.return_value = disk_spec
|
||||
|
||||
reconfig_spec = mock.Mock()
|
||||
self.session.vim.client.factory.create.return_value = reconfig_spec
|
||||
|
||||
backing = mock.sentinel.backing
|
||||
disk_device = mock.sentinel.disk_device
|
||||
self.vops.detach_disk_from_backing(backing, disk_device)
|
||||
|
||||
create_spec.assert_called_once_with(disk_device)
|
||||
self.session.vim.client.factory.create.assert_called_once_with(
|
||||
'ns0:VirtualMachineConfigSpec')
|
||||
self.assertEqual([disk_spec], reconfig_spec.deviceChange)
|
||||
reconfigure_backing.assert_called_once_with(backing, reconfig_spec)
|
||||
|
||||
def test_rename_backing(self):
|
||||
task = mock.sentinel.task
|
||||
self.session.invoke_api.return_value = task
|
||||
@ -1653,6 +1686,31 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
force=True)
|
||||
self.session.wait_for_task.assert_called_once_with(task)
|
||||
|
||||
def test_move_vmdk_file(self):
|
||||
task = mock.sentinel.task
|
||||
invoke_api = self.session.invoke_api
|
||||
invoke_api.return_value = task
|
||||
|
||||
disk_mgr = self.session.vim.service_content.virtualDiskManager
|
||||
src_dc_ref = mock.sentinel.src_dc_ref
|
||||
src_vmdk_file_path = mock.sentinel.src_vmdk_file_path
|
||||
dest_dc_ref = mock.sentinel.dest_dc_ref
|
||||
dest_vmdk_file_path = mock.sentinel.dest_vmdk_file_path
|
||||
self.vops.move_vmdk_file(src_dc_ref,
|
||||
src_vmdk_file_path,
|
||||
dest_vmdk_file_path,
|
||||
dest_dc_ref=dest_dc_ref)
|
||||
|
||||
invoke_api.assert_called_once_with(self.session.vim,
|
||||
'MoveVirtualDisk_Task',
|
||||
disk_mgr,
|
||||
sourceName=src_vmdk_file_path,
|
||||
sourceDatacenter=src_dc_ref,
|
||||
destName=dest_vmdk_file_path,
|
||||
destDatacenter=dest_dc_ref,
|
||||
force=True)
|
||||
self.session.wait_for_task.assert_called_once_with(task)
|
||||
|
||||
def test_delete_vmdk_file(self):
|
||||
task = mock.sentinel.task
|
||||
invoke_api = self.session.invoke_api
|
||||
|
@ -1694,6 +1694,45 @@ class VMwareVcVmdkDriver(driver.VolumeDriver):
|
||||
(_vm, disk) = self._get_existing(existing_ref)
|
||||
return int(math.ceil(disk.capacityInKB * units.Ki / float(units.Gi)))
|
||||
|
||||
def manage_existing(self, volume, existing_ref):
|
||||
"""Brings an existing virtual disk under Cinder management.
|
||||
|
||||
Detaches the virtual disk identified by existing_ref and attaches
|
||||
it to a volume backing.
|
||||
|
||||
:param volume: Cinder volume to manage
|
||||
:param existing_ref: Driver-specific information used to identify a
|
||||
volume
|
||||
"""
|
||||
(vm, disk) = self._get_existing(existing_ref)
|
||||
|
||||
# Create a backing for the volume.
|
||||
create_params = {CREATE_PARAM_DISK_LESS: True}
|
||||
backing = self._create_backing(volume, create_params=create_params)
|
||||
|
||||
# Detach the disk to be managed from the source VM.
|
||||
self.volumeops.detach_disk_from_backing(vm, disk)
|
||||
|
||||
# Move the disk to the datastore folder of volume backing.
|
||||
src_dc = self.volumeops.get_dc(vm)
|
||||
dest_dc = self.volumeops.get_dc(backing)
|
||||
(ds_name, folder_path) = self._get_ds_name_folder_path(backing)
|
||||
dest_path = volumeops.VirtualDiskPath(
|
||||
ds_name, folder_path, volume['name'])
|
||||
self.volumeops.move_vmdk_file(src_dc,
|
||||
disk.backing.fileName,
|
||||
dest_path.get_descriptor_ds_file_path(),
|
||||
dest_dc_ref=dest_dc)
|
||||
|
||||
# Attach the disk to be managed to volume backing.
|
||||
self.volumeops.attach_disk_to_backing(
|
||||
backing,
|
||||
disk.capacityInKB,
|
||||
VMwareVcVmdkDriver._get_disk_type(volume),
|
||||
'lsiLogic',
|
||||
dest_path.get_descriptor_ds_file_path())
|
||||
self.volumeops.update_backing_disk_uuid(backing, volume['id'])
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
if not self._session:
|
||||
|
@ -1228,6 +1228,26 @@ class VMwareVolumeOps(object):
|
||||
self._reconfigure_backing(backing, reconfig_spec)
|
||||
LOG.debug("Backing VM: %s reconfigured with new disk.", backing)
|
||||
|
||||
def _create_spec_for_disk_remove(self, disk_device):
|
||||
cf = self._session.vim.client.factory
|
||||
disk_spec = cf.create('ns0:VirtualDeviceConfigSpec')
|
||||
disk_spec.operation = 'remove'
|
||||
disk_spec.device = disk_device
|
||||
return disk_spec
|
||||
|
||||
def detach_disk_from_backing(self, backing, disk_device):
|
||||
"""Detach the given disk from backing."""
|
||||
|
||||
LOG.debug("Reconfiguring backing VM: %(backing)s to remove disk: "
|
||||
"%(disk_device)s.",
|
||||
{'backing': backing, 'disk_device': disk_device})
|
||||
|
||||
cf = self._session.vim.client.factory
|
||||
reconfig_spec = cf.create('ns0:VirtualMachineConfigSpec')
|
||||
spec = self._create_spec_for_disk_remove(disk_device)
|
||||
reconfig_spec.deviceChange = [spec]
|
||||
self._reconfigure_backing(backing, reconfig_spec)
|
||||
|
||||
def rename_backing(self, backing, new_name):
|
||||
"""Rename backing VM.
|
||||
|
||||
@ -1495,6 +1515,32 @@ class VMwareVolumeOps(object):
|
||||
LOG.info(_LI("Successfully copied disk at: %(src)s to: %(dest)s."),
|
||||
{'src': src_vmdk_file_path, 'dest': dest_vmdk_file_path})
|
||||
|
||||
def move_vmdk_file(self, src_dc_ref, src_vmdk_file_path,
|
||||
dest_vmdk_file_path, dest_dc_ref=None):
|
||||
"""Move the given vmdk file to another datastore location.
|
||||
|
||||
:param src_dc_ref: Reference to datacenter containing src datastore
|
||||
:param src_vmdk_file_path: Source vmdk file path
|
||||
:param dest_vmdk_file_path: Destination vmdk file path
|
||||
:param dest_dc_ref: Reference to datacenter of dest datastore.
|
||||
If unspecified, source datacenter is used.
|
||||
"""
|
||||
LOG.debug('Moving disk: %(src)s to %(dest)s.',
|
||||
{'src': src_vmdk_file_path, 'dest': dest_vmdk_file_path})
|
||||
|
||||
dest_dc_ref = dest_dc_ref or src_dc_ref
|
||||
diskMgr = self._session.vim.service_content.virtualDiskManager
|
||||
task = self._session.invoke_api(self._session.vim,
|
||||
'MoveVirtualDisk_Task',
|
||||
diskMgr,
|
||||
sourceName=src_vmdk_file_path,
|
||||
sourceDatacenter=src_dc_ref,
|
||||
destName=dest_vmdk_file_path,
|
||||
destDatacenter=dest_dc_ref,
|
||||
force=True)
|
||||
|
||||
self._session.wait_for_task(task)
|
||||
|
||||
def delete_vmdk_file(self, vmdk_file_path, dc_ref):
|
||||
"""Delete given vmdk files.
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Added support for manage volume in the VMware VMDK driver.
|
Loading…
x
Reference in New Issue
Block a user