Merge "VMware: manage_existing_get_size for VMDK driver"
This commit is contained in:
commit
0f9163a8ca
cinder
@ -2353,6 +2353,66 @@ class VMwareVcVmdkDriverTestCase(test.TestCase):
|
||||
{hub.DatastoreSelector.SIZE_BYTES: volume['size'] * units.Gi,
|
||||
hub.DatastoreSelector.PROFILE_NAME: None}, hosts=[host])
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, 'volumeops')
|
||||
def test_get_disk_device(self, vops):
|
||||
vm = mock.sentinel.vm
|
||||
vops.get_entity_by_inventory_path.return_value = vm
|
||||
|
||||
dev = mock.sentinel.dev
|
||||
vops.get_disk_device.return_value = dev
|
||||
|
||||
vm_inv_path = mock.sentinel.vm_inv_path
|
||||
vmdk_path = mock.sentinel.vmdk_path
|
||||
ret = self._driver._get_disk_device(vmdk_path, vm_inv_path)
|
||||
|
||||
self.assertEqual((vm, dev), ret)
|
||||
vops.get_entity_by_inventory_path.assert_called_once_with(vm_inv_path)
|
||||
vops.get_disk_device.assert_called_once_with(vm, vmdk_path)
|
||||
|
||||
def test_get_existing_with_empty_source_name(self):
|
||||
self.assertRaises(cinder_exceptions.InvalidInput,
|
||||
self._driver._get_existing,
|
||||
{})
|
||||
|
||||
def test_get_existing_with_invalid_source_name(self):
|
||||
self.assertRaises(cinder_exceptions.InvalidInput,
|
||||
self._driver._get_existing,
|
||||
{'source-name': 'foo'})
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_disk_device', return_value=None)
|
||||
def test_get_existing_with_invalid_existing_ref(self, get_disk_device):
|
||||
self.assertRaises(cinder_exceptions.ManageExistingInvalidReference,
|
||||
self._driver._get_existing,
|
||||
{'source-name': '[ds1] foo/foo.vmdk@/dc-1/vm/foo'})
|
||||
get_disk_device.assert_called_once_with('[ds1] foo/foo.vmdk',
|
||||
'/dc-1/vm/foo')
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_disk_device')
|
||||
def test_get_existing(self, get_disk_device):
|
||||
vm = mock.sentinel.vm
|
||||
disk_device = mock.sentinel.disk_device
|
||||
get_disk_device.return_value = (vm, disk_device)
|
||||
self.assertEqual(
|
||||
(vm, disk_device),
|
||||
self._driver._get_existing({'source-name':
|
||||
'[ds1] foo/foo.vmdk@/dc-1/vm/foo'}))
|
||||
get_disk_device.assert_called_once_with('[ds1] foo/foo.vmdk',
|
||||
'/dc-1/vm/foo')
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_existing')
|
||||
@ddt.data((16384, 1), (1048576, 1), (1572864, 2))
|
||||
def test_manage_existing_get_size(self, test_data, get_existing):
|
||||
(capacity_kb, exp_size) = test_data
|
||||
disk_device = mock.Mock(capacityInKB=capacity_kb)
|
||||
get_existing.return_value = (mock.sentinel.vm, disk_device)
|
||||
|
||||
volume = mock.sentinel.volume
|
||||
existing_ref = mock.sentinel.existing_ref
|
||||
self.assertEqual(exp_size,
|
||||
self._driver.manage_existing_get_size(volume,
|
||||
existing_ref))
|
||||
get_existing.assert_called_once_with(existing_ref)
|
||||
|
||||
@mock.patch('oslo_vmware.api.VMwareAPISession')
|
||||
def test_session(self, apiSession):
|
||||
self._session = None
|
||||
|
@ -1791,6 +1791,53 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
'ClusterComputeResource', self.MAX_OBJECTS)
|
||||
continue_retrieval.assert_called_once_with(retrieve_result)
|
||||
|
||||
def test_get_entity_by_inventory_path(self):
|
||||
self.session.invoke_api.return_value = mock.sentinel.ref
|
||||
|
||||
path = mock.sentinel.path
|
||||
ret = self.vops.get_entity_by_inventory_path(path)
|
||||
self.assertEqual(mock.sentinel.ref, ret)
|
||||
self.session.invoke_api.assert_called_once_with(
|
||||
self.session.vim,
|
||||
"FindByInventoryPath",
|
||||
self.session.vim.service_content.searchIndex,
|
||||
inventoryPath=path)
|
||||
|
||||
def test_get_disk_devices(self):
|
||||
disk_device = mock.Mock()
|
||||
disk_device.__class__.__name__ = 'VirtualDisk'
|
||||
|
||||
controller_device = mock.Mock()
|
||||
controller_device.__class__.__name__ = 'VirtualLSILogicController'
|
||||
|
||||
devices = mock.Mock()
|
||||
devices.__class__.__name__ = "ArrayOfVirtualDevice"
|
||||
devices.VirtualDevice = [disk_device, controller_device]
|
||||
self.session.invoke_api.return_value = devices
|
||||
|
||||
vm = mock.sentinel.vm
|
||||
self.assertEqual([disk_device], self.vops._get_disk_devices(vm))
|
||||
self.session.invoke_api.assert_called_once_with(
|
||||
vim_util, 'get_object_property', self.session.vim,
|
||||
vm, 'config.hardware.device')
|
||||
|
||||
def _create_disk_device(self, file_name):
|
||||
backing = mock.Mock(fileName=file_name)
|
||||
backing.__class__.__name__ = 'VirtualDiskFlatVer2BackingInfo'
|
||||
return mock.Mock(backing=backing)
|
||||
|
||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||
'_get_disk_devices')
|
||||
def test_get_disk_device(self, get_disk_devices):
|
||||
dev_1 = self._create_disk_device('[ds1] foo/foo.vmdk')
|
||||
dev_2 = self._create_disk_device('[ds1] foo/foo_1.vmdk')
|
||||
get_disk_devices.return_value = [dev_1, dev_2]
|
||||
|
||||
vm = mock.sentinel.vm
|
||||
self.assertEqual(dev_2,
|
||||
self.vops.get_disk_device(vm, '[ds1] foo/foo_1.vmdk'))
|
||||
get_disk_devices.assert_called_once_with(vm)
|
||||
|
||||
|
||||
class VirtualDiskPathTest(test.TestCase):
|
||||
"""Unit tests for VirtualDiskPath."""
|
||||
|
@ -24,6 +24,7 @@ machine is never powered on and is often referred as the shadow VM.
|
||||
|
||||
import contextlib
|
||||
import distutils.version as dist_version # pylint: disable=E0611
|
||||
import math
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
@ -1650,6 +1651,49 @@ class VMwareVcVmdkDriver(driver.VolumeDriver):
|
||||
{'backup_id': backup['id'],
|
||||
'name': volume['name']})
|
||||
|
||||
def _get_disk_device(self, vmdk_path, vm_inv_path):
|
||||
# Get the VM that corresponds to the given inventory path.
|
||||
vm = self.volumeops.get_entity_by_inventory_path(vm_inv_path)
|
||||
if vm:
|
||||
# Get the disk device that corresponds to the given vmdk path.
|
||||
disk_device = self.volumeops.get_disk_device(vm, vmdk_path)
|
||||
if disk_device:
|
||||
return (vm, disk_device)
|
||||
|
||||
def _get_existing(self, existing_ref):
|
||||
src_name = existing_ref.get('source-name')
|
||||
if not src_name:
|
||||
raise exception.InvalidInput(
|
||||
reason=_("source-name cannot be empty."))
|
||||
|
||||
# source-name format: vmdk_path@vm_inventory_path
|
||||
parts = src_name.split('@')
|
||||
if len(parts) != 2:
|
||||
raise exception.InvalidInput(
|
||||
reason=_("source-name format should be: "
|
||||
"'vmdk_path@vm_inventory_path'."))
|
||||
|
||||
(vmdk_path, vm_inv_path) = parts
|
||||
existing = self._get_disk_device(vmdk_path, vm_inv_path)
|
||||
if not existing:
|
||||
reason = _("%s does not exist.") % src_name
|
||||
raise exception.ManageExistingInvalidReference(
|
||||
existing_ref=existing_ref, reason=reason)
|
||||
|
||||
return existing
|
||||
|
||||
def manage_existing_get_size(self, volume, existing_ref):
|
||||
"""Return size of the volume to be managed by manage_existing.
|
||||
|
||||
When calculating the size, round up to the next GB.
|
||||
|
||||
:param volume: Cinder volume to manage
|
||||
:param existing_ref: Driver-specific information used to identify a
|
||||
volume
|
||||
"""
|
||||
(_vm, disk) = self._get_existing(existing_ref)
|
||||
return int(math.ceil(disk.capacityInKB * units.Ki / float(units.Gi)))
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
if not self._session:
|
||||
|
@ -1569,3 +1569,47 @@ class VMwareVolumeOps(object):
|
||||
host_refs.extend(hosts.ManagedObjectReference)
|
||||
|
||||
return host_refs
|
||||
|
||||
def get_entity_by_inventory_path(self, path):
|
||||
"""Returns the managed object identified by the given inventory path.
|
||||
|
||||
:param path: Inventory path
|
||||
:return: Reference to the managed object
|
||||
"""
|
||||
return self._session.invoke_api(
|
||||
self._session.vim,
|
||||
"FindByInventoryPath",
|
||||
self._session.vim.service_content.searchIndex,
|
||||
inventoryPath=path)
|
||||
|
||||
def _get_disk_devices(self, vm):
|
||||
disk_devices = []
|
||||
hardware_devices = self._session.invoke_api(vim_util,
|
||||
'get_object_property',
|
||||
self._session.vim,
|
||||
vm,
|
||||
'config.hardware.device')
|
||||
|
||||
if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice":
|
||||
hardware_devices = hardware_devices.VirtualDevice
|
||||
|
||||
for device in hardware_devices:
|
||||
if device.__class__.__name__ == "VirtualDisk":
|
||||
disk_devices.append(device)
|
||||
|
||||
return disk_devices
|
||||
|
||||
def get_disk_device(self, vm, vmdk_path):
|
||||
"""Get the disk device of the VM which corresponds to the given path.
|
||||
|
||||
:param vm: VM reference
|
||||
:param vmdk_path: Datastore path of virtual disk
|
||||
:return: Matching disk device
|
||||
"""
|
||||
disk_devices = self._get_disk_devices(vm)
|
||||
|
||||
for disk_device in disk_devices:
|
||||
backing = disk_device.backing
|
||||
if (backing.__class__.__name__ == "VirtualDiskFlatVer2BackingInfo"
|
||||
and backing.fileName == vmdk_path):
|
||||
return disk_device
|
||||
|
Loading…
x
Reference in New Issue
Block a user