Merge "VMware: refactor utility functions related to VMDK"

This commit is contained in:
Jenkins 2015-01-20 04:29:11 +00:00 committed by Gerrit Code Review
commit 07c2929f88
8 changed files with 99 additions and 127 deletions

View File

@ -523,6 +523,8 @@ class VirtualMachine(ManagedObject):
disk_backing.fileName = filename
disk_backing.key = -101
disk.backing = disk_backing
disk.capacityInBytes = 1024
disk.capacityInKB = 1
controller = VirtualLsiLogicController()
controller.key = controller_key

View File

@ -1757,17 +1757,17 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
adapter_type = constants.DEFAULT_ADAPTER_TYPE
disk_type = constants.DEFAULT_DISK_TYPE
path_and_type = ('fake-path', adapter_type, disk_type)
vmdk_info = vm_util.VmdkInfo('fake-path', adapter_type, disk_type, 64)
with contextlib.nested(
mock.patch.object(vm_util, 'get_vm_ref',
return_value=mock.sentinel.vm_ref),
mock.patch.object(volumeops.VMwareVolumeOps, '_get_volume_ref'),
mock.patch.object(vm_util, 'get_vmdk_path_and_adapter_type',
return_value=path_and_type),
mock.patch.object(vm_util, 'get_vmdk_info',
return_value=vmdk_info),
mock.patch.object(volumeops.VMwareVolumeOps, 'attach_disk_to_vm'),
mock.patch.object(volumeops.VMwareVolumeOps,
'_update_volume_details')
) as (get_vm_ref, get_volume_ref, get_vmdk_path_and_adapter_type,
) as (get_vm_ref, get_volume_ref, get_vmdk_info,
attach_disk_to_vm, update_volume_details):
self.conn.attach_volume(None, connection_info, self.instance,
'/dev/vdc')
@ -1776,7 +1776,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.instance)
get_volume_ref.assert_called_once_with(
connection_info['data']['volume'])
self.assertTrue(get_vmdk_path_and_adapter_type.called)
self.assertTrue(get_vmdk_info.called)
attach_disk_to_vm.assert_called_once_with(mock.sentinel.vm_ref,
self.instance, adapter_type, disk_type, vmdk_path='fake-path')
update_volume_details.assert_called_once_with(
@ -1789,7 +1789,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
adapter_type = constants.DEFAULT_ADAPTER_TYPE
disk_type = constants.DEFAULT_DISK_TYPE
path_and_type = ('fake-path', adapter_type, disk_type)
vmdk_info = vm_util.VmdkInfo('fake-path', adapter_type, disk_type, 64)
with contextlib.nested(
mock.patch.object(vm_util, 'get_vm_ref',
return_value=mock.sentinel.vm_ref),
@ -1798,15 +1798,14 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
mock.patch.object(volumeops.VMwareVolumeOps,
'_get_vmdk_backed_disk_device',
return_value=mock.sentinel.disk_device),
mock.patch.object(vm_util, 'get_vmdk_path_and_adapter_type',
return_value=path_and_type),
mock.patch.object(vm_util, 'get_vmdk_info',
return_value=vmdk_info),
mock.patch.object(volumeops.VMwareVolumeOps,
'_consolidate_vmdk_volume'),
mock.patch.object(volumeops.VMwareVolumeOps,
'detach_disk_from_vm')
) as (get_vm_ref, get_volume_ref, get_vmdk_backed_disk_device,
get_vmdk_path_and_adapter_type, consolidate_vmdk_volume,
detach_disk_from_vm):
get_vmdk_info, consolidate_vmdk_volume, detach_disk_from_vm):
self.conn.detach_volume(connection_info, self.instance,
'/dev/vdc', encryption=None)
@ -1816,7 +1815,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
connection_info['data']['volume'])
get_vmdk_backed_disk_device.assert_called_once_with(
mock.sentinel.vm_ref, connection_info['data'])
self.assertTrue(get_vmdk_path_and_adapter_type.called)
self.assertTrue(get_vmdk_info.called)
consolidate_vmdk_volume.assert_called_once_with(self.instance,
mock.sentinel.vm_ref, mock.sentinel.disk_device,
mock.sentinel.volume_ref, adapter_type=adapter_type,

View File

@ -204,6 +204,7 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
disk.controllerKey = controller_key
disk_backing = fake.VirtualDiskFlatVer2BackingInfo()
disk_backing.fileName = filename
disk.capacityInBytes = 1024
if parent:
disk_backing.parent = parent
disk.backing = disk_backing
@ -212,43 +213,32 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
devices = [disk, controller]
return devices
def test_get_vmdk_path(self):
uuid = '00000000-0000-0000-0000-000000000000'
filename = '[test_datastore] %s/%s.vmdk' % (uuid, uuid)
devices = self._vmdk_path_and_adapter_type_devices(filename)
session = fake.FakeSession()
with mock.patch.object(session, '_call_method',
return_value=devices):
instance = {'uuid': uuid}
vmdk_path = vm_util.get_vmdk_path(session, None, instance)
self.assertEqual(filename, vmdk_path)
def test_get_vmdk_path_and_adapter_type(self):
filename = '[test_datastore] test_file.vmdk'
devices = self._vmdk_path_and_adapter_type_devices(filename)
vmdk_info = vm_util.get_vmdk_path_and_adapter_type(devices)
adapter_type = vmdk_info[1]
self.assertEqual('lsiLogicsas', adapter_type)
self.assertEqual(vmdk_info[0], filename)
session = fake.FakeSession()
with mock.patch.object(session, '_call_method', return_value=devices):
vmdk = vm_util.get_vmdk_info(session, None)
self.assertEqual('lsiLogicsas', vmdk.adapter_type)
self.assertEqual(filename, vmdk.path)
def test_get_vmdk_path_and_adapter_type_with_match(self):
n_filename = '[test_datastore] uuid/uuid.vmdk'
devices = self._vmdk_path_and_adapter_type_devices(n_filename)
vmdk_info = vm_util.get_vmdk_path_and_adapter_type(
devices, uuid='uuid')
adapter_type = vmdk_info[1]
self.assertEqual('lsiLogicsas', adapter_type)
self.assertEqual(n_filename, vmdk_info[0])
session = fake.FakeSession()
with mock.patch.object(session, '_call_method', return_value=devices):
vmdk = vm_util.get_vmdk_info(session, None, uuid='uuid')
self.assertEqual('lsiLogicsas', vmdk.adapter_type)
self.assertEqual(n_filename, vmdk.path)
def test_get_vmdk_path_and_adapter_type_with_nomatch(self):
n_filename = '[test_datastore] diuu/diuu.vmdk'
session = fake.FakeSession()
devices = self._vmdk_path_and_adapter_type_devices(n_filename)
vmdk_info = vm_util.get_vmdk_path_and_adapter_type(
devices, uuid='uuid')
adapter_type = vmdk_info[1]
self.assertEqual('lsiLogicsas', adapter_type)
self.assertIsNone(vmdk_info[0])
with mock.patch.object(session, '_call_method', return_value=devices):
vmdk = vm_util.get_vmdk_info(session, None, uuid='uuid')
self.assertEqual('lsiLogicsas', vmdk.adapter_type)
self.assertIsNone(vmdk.path)
def test_get_vmdk_adapter_type(self):
# Test for the adapter_type to be used in vmdk descriptor

View File

@ -353,9 +353,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
vm_rescue_ref = mock.Mock()
vm_ref = mock.Mock()
args_list = [(vm_ref, 'VirtualMachine',
'config.hardware.device'),
(vm_rescue_ref, 'VirtualMachine',
args_list = [(vm_rescue_ref, 'VirtualMachine',
'config.hardware.device')]
def fake_call_method(module, method, *args, **kwargs):
@ -363,11 +361,13 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
self.assertEqual('get_dynamic_property', method)
self.assertEqual(expected_args, args)
path = mock.Mock()
path_and_type = (path, mock.Mock(), mock.Mock())
vmdk = vm_util.VmdkInfo(mock.sentinel.PATH,
mock.sentinel.ADAPTER_TYPE,
mock.sentinel.DISK_TYPE,
mock.sentinel.CAPACITY)
with contextlib.nested(
mock.patch.object(vm_util, 'get_vmdk_path_and_adapter_type',
return_value=path_and_type),
mock.patch.object(vm_util, 'get_vmdk_info',
return_value=vmdk),
mock.patch.object(vm_util, 'get_vmdk_volume_disk'),
mock.patch.object(vm_util, 'power_on_instance'),
mock.patch.object(vm_util, 'get_vm_ref', return_value=vm_ref),
@ -377,14 +377,15 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
fake_call_method),
mock.patch.object(vm_util, 'power_off_instance'),
mock.patch.object(self._vmops, '_destroy_instance'),
) as (_get_vmdk_path_and_adapter_type, _get_vmdk_volume_disk,
) as (_get_vmdk_info, _get_vmdk_volume_disk,
_power_on_instance, _get_vm_ref, _get_vm_ref_from_name,
_call_method, _power_off, _destroy_instance):
self._vmops.unrescue(self._instance, power_on=power_on)
_get_vmdk_path_and_adapter_type.assert_called_once_with(
None, uuid='fake_uuid')
_get_vmdk_volume_disk.assert_called_once_with(None, path=path)
_get_vmdk_info.assert_called_once_with(self._session,
vm_ref, 'fake_uuid')
_get_vmdk_volume_disk.assert_called_once_with(
None, path=mock.sentinel.PATH)
if power_on:
_power_on_instance.assert_called_once_with(self._session,
self._instance,

View File

@ -103,13 +103,13 @@ class VMwareVolumeOpsTestCase(test.NoDBTestCase):
'data': {'volume': 'vm-10',
'volume_id': 'volume-fake-id'}}
instance = mock.MagicMock(name='fake-name', vm_state=vm_states.ACTIVE)
path_and_type = ('fake-path', 'ide', 'preallocated')
vmdk_info = vm_util.VmdkInfo('fake-path', 'ide', 'preallocated', 1024)
with contextlib.nested(
mock.patch.object(vm_util, 'get_vm_ref'),
mock.patch.object(self._volumeops, '_get_volume_ref'),
mock.patch.object(vm_util, 'get_vmdk_path_and_adapter_type',
return_value=path_and_type)
) as (get_vm_ref, get_volume_ref, get_vmdk_path_and_adapter_type):
mock.patch.object(vm_util, 'get_vmdk_info',
return_value=vmdk_info)
) as (get_vm_ref, get_volume_ref, get_vmdk_info):
self.assertRaises(exception.Invalid,
self._volumeops._attach_volume_vmdk, connection_info,
instance)
@ -118,7 +118,7 @@ class VMwareVolumeOpsTestCase(test.NoDBTestCase):
instance)
get_volume_ref.assert_called_once_with(
connection_info['data']['volume'])
self.assertTrue(get_vmdk_path_and_adapter_type.called)
self.assertTrue(get_vmdk_info.called)
def test_detach_volume_vmdk_invalid(self):
connection_info = {'driver_volume_type': 'vmdk',
@ -126,17 +126,17 @@ class VMwareVolumeOpsTestCase(test.NoDBTestCase):
'data': {'volume': 'vm-10',
'volume_id': 'volume-fake-id'}}
instance = mock.MagicMock(name='fake-name', vm_state=vm_states.ACTIVE)
path_and_type = ('fake-path', 'ide', 'preallocated')
vmdk_info = vm_util.VmdkInfo('fake-path', 'ide', 'preallocated', 1024)
with contextlib.nested(
mock.patch.object(vm_util, 'get_vm_ref',
return_value=mock.sentinel.vm_ref),
mock.patch.object(self._volumeops, '_get_volume_ref'),
mock.patch.object(self._volumeops,
'_get_vmdk_backed_disk_device'),
mock.patch.object(vm_util, 'get_vmdk_path_and_adapter_type',
return_value=path_and_type)
mock.patch.object(vm_util, 'get_vmdk_info',
return_value=vmdk_info)
) as (get_vm_ref, get_volume_ref, get_vmdk_backed_disk_device,
get_vmdk_path_and_adapter_type):
get_vmdk_info):
self.assertRaises(exception.Invalid,
self._volumeops._detach_volume_vmdk, connection_info,
instance)
@ -147,4 +147,4 @@ class VMwareVolumeOpsTestCase(test.NoDBTestCase):
connection_info['data']['volume'])
get_vmdk_backed_disk_device.assert_called_once_with(
mock.sentinel.vm_ref, connection_info['data'])
self.assertTrue(get_vmdk_path_and_adapter_type.called)
self.assertTrue(get_vmdk_info.called)

View File

@ -18,6 +18,7 @@
The VMware API VM utility module to build SOAP object specs.
"""
import collections
import copy
import functools
@ -120,6 +121,10 @@ def vm_ref_cache_from_name(func):
# the config key which stores the VNC port
VNC_CONFIG_KEY = 'config.extraConfig["RemoteDisplay.vnc.port"]'
VmdkInfo = collections.namedtuple('VmdkInfo', ['path', 'adapter_type',
'disk_type',
'capacity_in_bytes'])
def _iface_id_option_value(client_factory, iface_id, port_index):
opt = client_factory.create('ns0:OptionValue')
@ -444,23 +449,17 @@ def get_vm_extra_config_spec(client_factory, extra_opts):
return config_spec
def get_vmdk_path(session, vm_ref, instance):
"""Gets the vmdk file path for specified instance."""
def get_vmdk_info(session, vm_ref, uuid=None):
"""Returns information for the primary VMDK attached to the given VM."""
hardware_devices = session._call_method(vim_util,
"get_dynamic_property", vm_ref, "VirtualMachine",
"config.hardware.device")
(vmdk_path, adapter_type, disk_type) = get_vmdk_path_and_adapter_type(
hardware_devices, uuid=instance['uuid'])
return vmdk_path
def get_vmdk_path_and_adapter_type(hardware_devices, uuid=None):
"""Gets the vmdk file path and the storage adapter type."""
if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice":
hardware_devices = hardware_devices.VirtualDevice
vmdk_file_path = None
vmdk_controller_key = None
disk_type = None
capacity_in_bytes = None
adapter_type_dict = {}
for device in hardware_devices:
@ -473,6 +472,15 @@ def get_vmdk_path_and_adapter_type(hardware_devices, uuid=None):
else:
vmdk_file_path = device.backing.fileName
vmdk_controller_key = device.controllerKey
# Devices pre-vSphere-5.5 only reports capacityInKB, which has
# rounding inaccuracies. Use that only if the more accurate
# attribute is absent.
if hasattr(device, 'capacityInBytes'):
capacity_in_bytes = device.capacityInBytes
else:
capacity_in_bytes = device.capacityInKB * units.Ki
if getattr(device.backing, 'thinProvisioned', False):
disk_type = "thin"
else:
@ -492,8 +500,8 @@ def get_vmdk_path_and_adapter_type(hardware_devices, uuid=None):
adapter_type_dict[device.key] = constants.ADAPTER_TYPE_PARAVIRTUAL
adapter_type = adapter_type_dict.get(vmdk_controller_key, "")
return (vmdk_file_path, adapter_type, disk_type)
return VmdkInfo(vmdk_file_path, adapter_type, disk_type,
capacity_in_bytes)
def _find_controller_slot(controller_keys, taken, max_unit_number):

View File

@ -713,24 +713,19 @@ class VMwareVMOps(object):
service_content = self._session.vim.service_content
def _get_vm_and_vmdk_attribs():
# Get the vmdk file name that the VM is pointing to
hw_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device")
(vmdk_file_path_before_snapshot, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(
hw_devices, uuid=instance.uuid)
if not vmdk_file_path_before_snapshot:
# Get the vmdk info that the VM is pointing to
vmdk = vm_util.get_vmdk_info(self._session, vm_ref,
instance.uuid)
if not vmdk.path:
LOG.debug("No root disk defined. Unable to snapshot.")
raise error_util.NoRootDiskDefined()
datastore_name = ds_util.DatastorePath.parse(
vmdk_file_path_before_snapshot).datastore
datastore_name = ds_util.DatastorePath.parse(vmdk.path).datastore
os_type = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "summary.config.guestId")
return (vmdk_file_path_before_snapshot, adapter_type, disk_type,
datastore_name, os_type)
return (vmdk.path, vmdk.adapter_type,
vmdk.disk_type, datastore_name, os_type)
(vmdk_file_path_before_snapshot, adapter_type, disk_type,
datastore_name, os_type) = _get_vm_and_vmdk_attribs()
@ -1030,17 +1025,14 @@ class VMwareVMOps(object):
power_on=False)
# Attach vmdk to the rescue VM
hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device")
(vmdk_path, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(
hardware_devices, uuid=instance.uuid)
vmdk = vm_util.get_vmdk_info(self._session, vm_ref, instance.uuid)
rescue_vm_ref = vm_util.get_vm_ref_from_name(self._session,
instance_name)
self._volumeops.attach_disk_to_vm(
rescue_vm_ref, instance,
adapter_type, disk_type, vmdk_path)
self._volumeops.attach_disk_to_vm(rescue_vm_ref,
instance,
vmdk.adapter_type,
vmdk.disk_type,
vmdk.path)
vm_util.power_on_instance(self._session, instance,
vm_ref=rescue_vm_ref)
@ -1048,13 +1040,7 @@ class VMwareVMOps(object):
"""Unrescue the specified instance."""
# Get the original vmdk_path
vm_ref = vm_util.get_vm_ref(self._session, instance)
hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device")
(vmdk_path, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(
hardware_devices, uuid=instance.uuid)
vmdk = vm_util.get_vmdk_info(self._session, vm_ref, instance.uuid)
instance_name = instance.uuid + self._rescue_suffix
# detach the original instance disk from the rescue disk
vm_rescue_ref = vm_util.get_vm_ref_from_name(self._session,
@ -1062,7 +1048,7 @@ class VMwareVMOps(object):
hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_rescue_ref,
"VirtualMachine", "config.hardware.device")
device = vm_util.get_vmdk_volume_disk(hardware_devices, path=vmdk_path)
device = vm_util.get_vmdk_volume_disk(hardware_devices, path=vmdk.path)
vm_util.power_off_instance(self._session, instance, vm_rescue_ref)
self._volumeops.detach_disk_from_vm(vm_rescue_ref, instance, device)
self._destroy_instance(instance, instance_name=instance_name)
@ -1191,8 +1177,9 @@ class VMwareVMOps(object):
old_root_gb = instance.system_metadata['old_instance_type_root_gb']
if instance['root_gb'] > int(old_root_gb):
root_disk_in_kb = instance['root_gb'] * units.Mi
vmdk_path = vm_util.get_vmdk_path(self._session, vm_ref,
instance)
vmdk_info = vm_util.get_vmdk_info(self._session, vm_ref,
instance.uuid)
vmdk_path = vmdk_info.path
data_store_ref = ds_util.get_datastore(self._session,
self._cluster, datastore_regex=self._datastore_regex).ref
dc_info = self.get_datacenter_ref_and_name(data_store_ref)

View File

@ -321,22 +321,17 @@ class VMwareVolumeOps(object):
# Get details required for adding disk device such as
# adapter_type, disk_type
hw_devices = self._session._call_method(vim_util,
'get_dynamic_property',
volume_ref, 'VirtualMachine',
'config.hardware.device')
(volume_vmdk_path, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(hw_devices)
vmdk = vm_util.get_vmdk_info(self._session, volume_ref)
# IDE does not support disk hotplug
if (instance.vm_state == vm_states.ACTIVE and
adapter_type == constants.ADAPTER_TYPE_IDE):
msg = _('%s does not support disk hotplug.') % adapter_type
vmdk.adapter_type == constants.ADAPTER_TYPE_IDE):
msg = _('%s does not support disk hotplug.') % vmdk.adapter_type
raise exception.Invalid(msg)
# Attach the disk to virtual machine instance
self.attach_disk_to_vm(vm_ref, instance, adapter_type,
disk_type, vmdk_path=volume_vmdk_path)
self.attach_disk_to_vm(vm_ref, instance, vmdk.adapter_type,
vmdk.disk_type, vmdk_path=vmdk.path)
# Store the uuid of the volume_device
self._update_volume_details(vm_ref, instance, data['volume_id'])
@ -358,15 +353,10 @@ class VMwareVolumeOps(object):
raise exception.StorageError(
reason=_("Unable to find iSCSI Target"))
# Get the vmdk file name that the VM is pointing to
hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device")
(vmdk_file_path, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(hardware_devices)
vmdk = vm_util.get_vmdk_info(self._session, vm_ref)
self.attach_disk_to_vm(vm_ref, instance,
adapter_type, 'rdmp',
vmdk.adapter_type, 'rdmp',
device_name=device_name)
LOG.debug("Attached ISCSI: %s", connection_info, instance=instance)
@ -494,22 +484,17 @@ class VMwareVolumeOps(object):
# Get details required for adding disk device such as
# adapter_type, disk_type
hw_devices = self._session._call_method(vim_util,
'get_dynamic_property',
volume_ref, 'VirtualMachine',
'config.hardware.device')
(vmdk_file_path, adapter_type,
disk_type) = vm_util.get_vmdk_path_and_adapter_type(hw_devices)
vmdk = vm_util.get_vmdk_info(self._session, volume_ref)
# IDE does not support disk hotplug
if (instance.vm_state == vm_states.ACTIVE and
adapter_type == constants.ADAPTER_TYPE_IDE):
msg = _('%s does not support disk hotplug.') % adapter_type
vmdk.adapter_type == constants.ADAPTER_TYPE_IDE):
msg = _('%s does not support disk hotplug.') % vmdk.adapter_type
raise exception.Invalid(msg)
self._consolidate_vmdk_volume(instance, vm_ref, device, volume_ref,
adapter_type=adapter_type,
disk_type=disk_type)
adapter_type=vmdk.adapter_type,
disk_type=vmdk.disk_type)
self.detach_disk_from_vm(vm_ref, instance, device)
LOG.debug("Detached VMDK: %s", connection_info, instance=instance)