VMware: Add 'managedBy' info

Add vCenter managedBy info to volumes in the backend so that
they would be displayed as 'managed by OpenStack Cinder'. It
also warns the vSphere admin if an operation is attempted
using vSphere client.

Change-Id: I42c00b7df6aa0576b928e49f6eb21f45b56fa647
This commit is contained in:
Vipin Balachandran 2017-07-10 16:16:35 -07:00
parent 6cb68e10b5
commit 14ff0cc2bd
5 changed files with 116 additions and 11 deletions

View File

@ -1344,18 +1344,71 @@ class VMwareVcVmdkDriverTestCase(test.TestCase):
self._driver._validate_vcenter_version,
'5.1')
@mock.patch('oslo_vmware.vim_util.find_extension')
@mock.patch('oslo_vmware.vim_util.register_extension')
@mock.patch.object(VMDK_DRIVER, 'session')
def _test_register_extension(
self, session, register_extension, find_extension,
ext_exists=False):
if not ext_exists:
find_extension.return_value = None
self._driver._register_extension()
find_extension.assert_called_once_with(session.vim, vmdk.EXTENSION_KEY)
if not ext_exists:
register_extension.assert_called_once_with(
session.vim, vmdk.EXTENSION_KEY, vmdk.EXTENSION_TYPE,
label='OpenStack Cinder')
def test_register_extension(self):
self._test_register_extension()
def test_register_extension_with_existing_extension(self):
self._test_register_extension(ext_exists=True)
@mock.patch('oslo_vmware.vim_util.find_extension', return_value=None)
@mock.patch('oslo_vmware.vim_util.register_extension')
@mock.patch.object(VMDK_DRIVER, 'session')
def test_concurrent_register_extension(
self, session, register_extension, find_extension):
register_extension.side_effect = exceptions.VimFaultException(
['InvalidArgument'], 'error')
self._driver._register_extension()
find_extension.assert_called_once_with(session.vim, vmdk.EXTENSION_KEY)
register_extension.assert_called_once_with(
session.vim, vmdk.EXTENSION_KEY, vmdk.EXTENSION_TYPE,
label='OpenStack Cinder')
@mock.patch('oslo_vmware.vim_util.find_extension', return_value=None)
@mock.patch('oslo_vmware.vim_util.register_extension')
@mock.patch.object(VMDK_DRIVER, 'session')
def test_register_extension_failure(
self, session, register_extension, find_extension):
register_extension.side_effect = exceptions.VimFaultException(
['RuntimeFault'], 'error')
self.assertRaises(exceptions.VimFaultException,
self._driver._register_extension)
find_extension.assert_called_once_with(session.vim, vmdk.EXTENSION_KEY)
register_extension.assert_called_once_with(
session.vim, vmdk.EXTENSION_KEY, vmdk.EXTENSION_TYPE,
label='OpenStack Cinder')
@mock.patch.object(VMDK_DRIVER, '_validate_params')
@mock.patch.object(VMDK_DRIVER, '_get_vc_version')
@mock.patch.object(VMDK_DRIVER, '_validate_vcenter_version')
@mock.patch('oslo_vmware.pbm.get_pbm_wsdl_location')
@mock.patch.object(VMDK_DRIVER, '_register_extension')
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector')
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, 'session')
def _test_do_setup(
self, session, vops, ds_sel_cls, vops_cls, get_pbm_wsdl_loc,
validate_vc_version, get_vc_version, validate_params,
enable_pbm=True):
self, session, vops, ds_sel_cls, vops_cls, register_extension,
get_pbm_wsdl_loc, validate_vc_version, get_vc_version,
validate_params, enable_pbm=True):
if enable_pbm:
ver_str = '5.5'
pbm_wsdl = mock.sentinel.pbm_wsdl
@ -1378,8 +1431,10 @@ class VMwareVcVmdkDriverTestCase(test.TestCase):
get_pbm_wsdl_loc.assert_called_once_with(ver_str)
self.assertEqual(pbm_wsdl, self._driver.pbm_wsdl)
self.assertEqual(enable_pbm, self._driver._storage_policy_enabled)
register_extension.assert_called_once()
vops_cls.assert_called_once_with(
session, self._driver.configuration.vmware_max_objects_retrieval)
session, self._driver.configuration.vmware_max_objects_retrieval,
vmdk.EXTENSION_KEY, vmdk.EXTENSION_TYPE)
self.assertEqual(vops_cls.return_value, self._driver._volumeops)
ds_sel_cls.assert_called_once_with(
vops,

View File

@ -37,7 +37,9 @@ class VolumeOpsTestCase(test.TestCase):
def setUp(self):
super(VolumeOpsTestCase, self).setUp()
self.session = mock.MagicMock()
self.vops = volumeops.VMwareVolumeOps(self.session, self.MAX_OBJECTS)
self.vops = volumeops.VMwareVolumeOps(
self.session, self.MAX_OBJECTS, mock.sentinel.extension_key,
mock.sentinel.extension_type)
def test_split_datastore_path(self):
test1 = '[datastore1] myfolder/mysubfolder/myvm.vmx'
@ -604,10 +606,14 @@ class VolumeOpsTestCase(test.TestCase):
self.assertEqual(1, len(ret.extraConfig))
self.assertEqual(option_key, ret.extraConfig[0].key)
self.assertEqual(option_value, ret.extraConfig[0].value)
self.assertEqual(mock.sentinel.extension_key,
ret.managedBy.extensionKey)
self.assertEqual(mock.sentinel.extension_type, ret.managedBy.type)
expected = [mock.call.create('ns0:VirtualMachineFileInfo'),
mock.call.create('ns0:VirtualMachineConfigSpec'),
mock.call.create('ns0:VirtualMachineDefinedProfileSpec'),
mock.call.create('ns0:OptionValue')]
mock.call.create('ns0:OptionValue'),
mock.call.create('ns0:ManagedByInfo')]
factory.create.assert_has_calls(expected, any_order=True)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
@ -1004,6 +1010,10 @@ class VolumeOpsTestCase(test.TestCase):
self.assertFalse(ret.template)
self.assertEqual(snapshot, ret.snapshot)
self.assertEqual(mock.sentinel.uuid, ret.config.instanceUuid)
self.assertEqual(mock.sentinel.extension_key,
ret.config.managedBy.extensionKey)
self.assertEqual(mock.sentinel.extension_type,
ret.config.managedBy.type)
get_relocate_spec.assert_called_once_with(datastore, rp, host,
disk_move_type, disk_type,
disk_device)

View File

@ -63,6 +63,9 @@ TMP_IMAGES_DATASTORE_FOLDER_PATH = "cinder_temp/"
EXTRA_CONFIG_VOLUME_ID_KEY = "cinder.volume.id"
EXTENSION_KEY = 'org.openstack.storage'
EXTENSION_TYPE = 'volume'
vmdk_opts = [
cfg.StrOpt('vmware_host_ip',
help='IP address for connecting to VMware vCenter server.'),
@ -1679,6 +1682,24 @@ class VMwareVcVmdkDriver(driver.VolumeDriver):
' to %(ver)s in a future release.',
{'ver': self.NEXT_MIN_SUPPORTED_VC_VERSION})
def _register_extension(self):
ext = vim_util.find_extension(self.session.vim, EXTENSION_KEY)
if ext:
LOG.debug('Extension %s already exists.', EXTENSION_KEY)
else:
try:
vim_util.register_extension(self.session.vim,
EXTENSION_KEY,
EXTENSION_TYPE,
label='OpenStack Cinder')
LOG.info('Registered extension %s.', EXTENSION_KEY)
except exceptions.VimFaultException as e:
if 'InvalidArgument' in e.fault_list:
LOG.debug('Extension %s is already registered.',
EXTENSION_KEY)
else:
raise
def do_setup(self, context):
"""Any initialization the volume driver does while starting."""
self._validate_params()
@ -1701,10 +1722,13 @@ class VMwareVcVmdkDriver(driver.VolumeDriver):
# Destroy current session so that it is recreated with pbm enabled
self._session = None
self._register_extension()
# recreate session and initialize volumeops and ds_sel
# TODO(vbala) remove properties: session, volumeops and ds_sel
max_objects = self.configuration.vmware_max_objects_retrieval
self._volumeops = volumeops.VMwareVolumeOps(self.session, max_objects)
self._volumeops = volumeops.VMwareVolumeOps(
self.session, max_objects, EXTENSION_KEY, EXTENSION_TYPE)
self._ds_sel = hub.DatastoreSelector(
self.volumeops, self.session, max_objects)

View File

@ -278,9 +278,11 @@ class ControllerType(object):
class VMwareVolumeOps(object):
"""Manages volume operations."""
def __init__(self, session, max_objects):
def __init__(self, session, max_objects, extension_key, extension_type):
self._session = session
self._max_objects = max_objects
self._extension_key = extension_key
self._extension_type = extension_type
self._folder_cache = {}
def get_backing(self, name):
@ -683,6 +685,13 @@ class VMwareVolumeOps(object):
return option_values
def _create_managed_by_info(self):
managed_by = self._session.vim.client.factory.create(
'ns0:ManagedByInfo')
managed_by.extensionKey = self._extension_key
managed_by.type = self._extension_type
return managed_by
def _get_create_spec_disk_less(self, name, ds_name, profileId=None,
extra_config=None):
"""Return spec for creating disk-less backing.
@ -721,6 +730,7 @@ class VMwareVolumeOps(object):
create_spec.extraConfig = self._get_extra_config_option_values(
extra_config)
create_spec.managedBy = self._create_managed_by_info()
return create_spec
def get_create_spec(self, name, size_kb, disk_type, ds_name,
@ -1076,9 +1086,9 @@ class VMwareVolumeOps(object):
clone_spec.template = False
clone_spec.snapshot = snapshot
if extra_config or disks_to_clone:
config_spec = cf.create('ns0:VirtualMachineConfigSpec')
clone_spec.config = config_spec
config_spec = cf.create('ns0:VirtualMachineConfigSpec')
config_spec.managedBy = self._create_managed_by_info()
clone_spec.config = config_spec
if extra_config:
if BACKING_UUID_KEY in extra_config:

View File

@ -0,0 +1,6 @@
---
features:
- |
The volumes created by VMware VMDK driver will be displayed as
"managed by OpenStack Cinder" in vCenter server.