Merge "VMware: manage_existing for VMDK driver"
This commit is contained in:
commit
f674bd602b
@ -2413,6 +2413,53 @@ class VMwareVcVmdkDriverTestCase(test.TestCase):
|
|||||||
existing_ref))
|
existing_ref))
|
||||||
get_existing.assert_called_once_with(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')
|
@mock.patch('oslo_vmware.api.VMwareAPISession')
|
||||||
def test_session(self, apiSession):
|
def test_session(self, apiSession):
|
||||||
self._session = None
|
self._session = None
|
||||||
|
@ -1326,6 +1326,39 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
spec=reconfig_spec)
|
spec=reconfig_spec)
|
||||||
self.session.wait_for_task.assert_called_once_with(task)
|
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):
|
def test_rename_backing(self):
|
||||||
task = mock.sentinel.task
|
task = mock.sentinel.task
|
||||||
self.session.invoke_api.return_value = task
|
self.session.invoke_api.return_value = task
|
||||||
@ -1653,6 +1686,31 @@ class VolumeOpsTestCase(test.TestCase):
|
|||||||
force=True)
|
force=True)
|
||||||
self.session.wait_for_task.assert_called_once_with(task)
|
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):
|
def test_delete_vmdk_file(self):
|
||||||
task = mock.sentinel.task
|
task = mock.sentinel.task
|
||||||
invoke_api = self.session.invoke_api
|
invoke_api = self.session.invoke_api
|
||||||
|
@ -1694,6 +1694,45 @@ class VMwareVcVmdkDriver(driver.VolumeDriver):
|
|||||||
(_vm, disk) = self._get_existing(existing_ref)
|
(_vm, disk) = self._get_existing(existing_ref)
|
||||||
return int(math.ceil(disk.capacityInKB * units.Ki / float(units.Gi)))
|
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
|
@property
|
||||||
def session(self):
|
def session(self):
|
||||||
if not self._session:
|
if not self._session:
|
||||||
|
@ -1228,6 +1228,26 @@ class VMwareVolumeOps(object):
|
|||||||
self._reconfigure_backing(backing, reconfig_spec)
|
self._reconfigure_backing(backing, reconfig_spec)
|
||||||
LOG.debug("Backing VM: %s reconfigured with new disk.", backing)
|
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):
|
def rename_backing(self, backing, new_name):
|
||||||
"""Rename backing VM.
|
"""Rename backing VM.
|
||||||
|
|
||||||
@ -1495,6 +1515,32 @@ class VMwareVolumeOps(object):
|
|||||||
LOG.info(_LI("Successfully copied disk at: %(src)s to: %(dest)s."),
|
LOG.info(_LI("Successfully copied disk at: %(src)s to: %(dest)s."),
|
||||||
{'src': src_vmdk_file_path, 'dest': dest_vmdk_file_path})
|
{'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):
|
def delete_vmdk_file(self, vmdk_file_path, dc_ref):
|
||||||
"""Delete given vmdk files.
|
"""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