Merge "VMware: manage_existing_get_size for VMDK driver"

This commit is contained in:
Jenkins 2016-02-29 01:27:51 +00:00 committed by Gerrit Code Review
commit 0f9163a8ca
4 changed files with 195 additions and 0 deletions

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