From 10c5c93925abe3d34c4430e0ed852d8358fb2353 Mon Sep 17 00:00:00 2001 From: Subramanian Neelakantan Date: Wed, 11 Dec 2013 19:19:37 +0530 Subject: [PATCH] vmware: PBM wsdl file configuration Currently the PBM wsdl files have to be downloaded to the local file system and needs to be configured in 'pbm_wsdl_location'. If it is manually configured then PBM feature is enabled. This patch does away with the manual configuration of 'pbm_wsdl_location'. PBM wsdl files are now shipped with the driver. VC version is fetched from the backend server and the corresponding wsdl file is used. If the backend is a VC version that is less than 5.5 then PBM feature is turned off. Implements: blueprint vmdk-storage-policy-volume-type Change-Id: I559006b532fa39aab6d54cb0b21d5f7afba62af3 --- cinder/tests/test_vmware_vmdk.py | 73 +- cinder/volume/drivers/vmware/vmdk.py | 127 ++- .../drivers/vmware/wsdl/5.5/core-types.xsd | 242 +++++ .../vmware/wsdl/5.5/pbm-messagetypes.xsd | 155 +++ .../drivers/vmware/wsdl/5.5/pbm-types.xsd | 729 ++++++++++++++ .../volume/drivers/vmware/wsdl/5.5/pbm.wsdl | 889 ++++++++++++++++++ .../drivers/vmware/wsdl/5.5/pbmService.wsdl | 16 + etc/cinder/cinder.conf.sample | 19 +- 8 files changed, 2204 insertions(+), 46 deletions(-) create mode 100644 cinder/volume/drivers/vmware/wsdl/5.5/core-types.xsd create mode 100644 cinder/volume/drivers/vmware/wsdl/5.5/pbm-messagetypes.xsd create mode 100644 cinder/volume/drivers/vmware/wsdl/5.5/pbm-types.xsd create mode 100644 cinder/volume/drivers/vmware/wsdl/5.5/pbm.wsdl create mode 100644 cinder/volume/drivers/vmware/wsdl/5.5/pbmService.wsdl diff --git a/cinder/tests/test_vmware_vmdk.py b/cinder/tests/test_vmware_vmdk.py index 682c80a93..933cdd1e8 100644 --- a/cinder/tests/test_vmware_vmdk.py +++ b/cinder/tests/test_vmware_vmdk.py @@ -17,6 +17,9 @@ Test suite for VMware VMDK driver. """ +from distutils.version import LooseVersion +import os + import mock import mox @@ -1053,34 +1056,88 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase): class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase): """Test class for VMwareVcVmdkDriver.""" - PBM_WSDL = '/fake/wsdl/path' DEFAULT_PROFILE = 'fakeProfile' + DEFAULT_VC_VERSION = '5.5' def setUp(self): super(VMwareVcVmdkDriverTestCase, self).setUp() - self._config.pbm_wsdl_location = self.PBM_WSDL self._config.pbm_default_policy = self.DEFAULT_PROFILE + self._config.vmware_host_version = self.DEFAULT_VC_VERSION self._driver = vmdk.VMwareVcVmdkDriver(configuration=self._config) + def test_get_pbm_wsdl_location(self): + # no version returns None + wsdl = self._driver._get_pbm_wsdl_location(None) + self.assertIsNone(wsdl) + + def expected_wsdl(version): + driver_dir = os.path.join(os.path.dirname(__file__), '..', + 'volume', 'drivers', 'vmware') + driver_abs_dir = os.path.abspath(driver_dir) + return 'file://' + os.path.join(driver_abs_dir, 'wsdl', version, + 'pbmService.wsdl') + + # verify wsdl path for different version strings + with mock.patch('os.path.exists') as path_exists: + path_exists.return_value = True + wsdl = self._driver._get_pbm_wsdl_location(LooseVersion('5')) + self.assertEqual(expected_wsdl('5'), wsdl) + wsdl = self._driver._get_pbm_wsdl_location(LooseVersion('5.5')) + self.assertEqual(expected_wsdl('5.5'), wsdl) + wsdl = self._driver._get_pbm_wsdl_location(LooseVersion('5.5.1')) + self.assertEqual(expected_wsdl('5.5'), wsdl) + # if wsdl path does not exist, then it returns None + path_exists.return_value = False + wsdl = self._driver._get_pbm_wsdl_location(LooseVersion('5.5')) + self.assertIsNone(wsdl) + + @mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.' + 'session', new_callable=mock.PropertyMock) + def test_get_vc_version(self, session): + # test config overrides fetching from VC server + version = self._driver._get_vc_version() + self.assertEqual(self.DEFAULT_VC_VERSION, version) + # explicitly remove config entry + self._driver.configuration.vmware_host_version = None + session.return_value.vim.service_content.about.version = '6.0.1' + version = self._driver._get_vc_version() + self.assertEqual(LooseVersion('6.0.1'), version) + + @mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.' + '_get_pbm_wsdl_location') + @mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.' + '_get_vc_version') @mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.' 'session', new_callable=mock.PropertyMock) @mock.patch('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver.' 'volumeops', new_callable=mock.PropertyMock) - def test_do_setup(self, vol_ops, session): - """Test do_setup.""" + def test_do_setup(self, vol_ops, session, _get_vc_version, + _get_pbm_wsdl_location): vol_ops = vol_ops.return_value session = session.return_value - # pbm_wsdl_location is set and pbm_default_policy is used + # pbm is enabled and pbm_default_policy is used + _get_vc_version.return_value = LooseVersion('5.5') + _get_pbm_wsdl_location.return_value = 'fake_pbm_location' self._driver.do_setup(mock.ANY) default = self.DEFAULT_PROFILE vol_ops.retrieve_profile_id.assert_called_once_with(default) - # pbm_wsdl_location is set and pbm_default_policy is wrong + self.assertTrue(self._driver._storage_policy_enabled) + + # pbm is enabled and pbm_default_policy is wrong + self._driver._storage_policy_enabled = False + vol_ops.retrieve_profile_id.reset_mock() vol_ops.retrieve_profile_id.return_value = None self.assertRaises(error_util.PbmDefaultPolicyDoesNotExist, self._driver.do_setup, mock.ANY) - # pbm_wsdl_location is not set - self._driver.configuration.pbm_wsdl_location = None + vol_ops.retrieve_profile_id.assert_called_once_with(default) + + # pbm is disabled + self._driver._storage_policy_enabled = False + vol_ops.retrieve_profile_id.reset_mock() + _get_vc_version.return_value = LooseVersion('5.0') self._driver.do_setup(mock.ANY) + self.assertFalse(self._driver._storage_policy_enabled) + self.assertFalse(vol_ops.retrieve_profile_id.called) def test_init_conn_with_instance_and_backing(self): """Test initialize_connection with instance and backing.""" diff --git a/cinder/volume/drivers/vmware/vmdk.py b/cinder/volume/drivers/vmware/vmdk.py index 44603e71c..3eef28c18 100644 --- a/cinder/volume/drivers/vmware/vmdk.py +++ b/cinder/volume/drivers/vmware/vmdk.py @@ -22,9 +22,13 @@ driver creates a virtual machine for each of the volumes. This virtual machine is never powered on and is often referred as the shadow VM. """ +import distutils.version as dist_version # pylint: disable=E0611 +import os + from oslo.config import cfg from cinder import exception +from cinder.openstack.common import excutils from cinder.openstack.common import log as logging from cinder import units from cinder.volume import driver @@ -80,18 +84,18 @@ vmdk_opts = [ 'Query results will be obtained in batches from the ' 'server and not in one shot. Server may still limit the ' 'count to something less than the configured value.'), + cfg.StrOpt('vmware_host_version', + help='Optional string specifying the VMware VC server version. ' + 'The driver attempts to retrieve the version from VMware ' + 'VC server. Set this configuration only if you want to ' + 'override the VC server version.'), ] spbm_opts = [ - cfg.StrOpt('pbm_wsdl_location', - help='PBM service WSDL file location URL. ' - 'e.g. file:///opt/SDK/spbm/wsdl/pbmService.wsdl. ' - 'Not setting this will disable storage policy based ' - 'placement of volumes.'), cfg.StrOpt('pbm_default_policy', - help='The PBM default policy. If pbm_wsdl_location is set and ' - 'there is no defined storage policy for the specific ' - 'request then this policy will be used.'), + help='The PBM default policy. If using VC server version 5.5 ' + 'or above and there is no defined storage policy for the ' + 'specific request then this policy will be used.'), ] CONF = cfg.CONF @@ -193,13 +197,16 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver): if not getattr(self.configuration, param, None): raise exception.InvalidInput(_("%s not set.") % param) - # Create the session object for the first time - max_objects = self.configuration.vmware_max_objects_retrieval - self._volumeops = volumeops.VMwareVolumeOps(self.session, max_objects) - LOG.info(_("Successfully setup driver: %(driver)s for " - "server: %(ip)s.") % - {'driver': self.__class__.__name__, - 'ip': self.configuration.vmware_host_ip}) + # Create the session object for the first time for ESX driver + driver = self.__class__.__name__ + if driver == 'VMwareEsxVmdkDriver': + max_objects = self.configuration.vmware_max_objects_retrieval + self._volumeops = volumeops.VMwareVolumeOps(self.session, + max_objects) + LOG.info(_("Successfully setup driver: %(driver)s for " + "server: %(ip)s.") % + {'driver': driver, + 'ip': self.configuration.vmware_host_ip}) def check_for_setup_error(self): pass @@ -960,6 +967,9 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver): class VMwareVcVmdkDriver(VMwareEsxVmdkDriver): """Manage volumes on VMware VC server.""" + # PBM is enabled only for VC versions 5.5 and above + PBM_ENABLED_VC_VERSION = dist_version.LooseVersion('5.5') + def __init__(self, *args, **kwargs): super(VMwareVcVmdkDriver, self).__init__(*args, **kwargs) self.configuration.append_config_values(spbm_opts) @@ -974,7 +984,7 @@ class VMwareVcVmdkDriver(VMwareEsxVmdkDriver): api_retry_count = self.configuration.vmware_api_retry_count task_poll_interval = self.configuration.vmware_task_poll_interval wsdl_loc = self.configuration.safe_get('vmware_wsdl_location') - pbm_wsdl = self.configuration.pbm_wsdl_location + pbm_wsdl = self.pbm_wsdl if hasattr(self, 'pbm_wsdl') else None self._session = api.VMwareAPISession(ip, username, password, api_retry_count, task_poll_interval, @@ -982,29 +992,88 @@ class VMwareVcVmdkDriver(VMwareEsxVmdkDriver): pbm_wsdl=pbm_wsdl) return self._session + def _get_pbm_wsdl_location(self, vc_version): + """Return PBM WSDL file location corresponding to VC version.""" + if not vc_version: + return + ver = str(vc_version).split('.') + major_minor = ver[0] + if len(ver) >= 2: + major_minor = major_minor + '.' + ver[1] + curr_dir = os.path.abspath(os.path.dirname(__file__)) + pbm_service_wsdl = os.path.join(curr_dir, 'wsdl', major_minor, + 'pbmService.wsdl') + if not os.path.exists(pbm_service_wsdl): + LOG.warn(_("PBM WSDL file %s is missing!"), pbm_service_wsdl) + return + pbm_wsdl = 'file://' + pbm_service_wsdl + LOG.info(_("Using PBM WSDL location: %s"), pbm_wsdl) + return pbm_wsdl + + def _get_vc_version(self): + """Connect to VC server and fetch version. + + Can be over-ridden by setting 'vmware_host_version' config. + :returns: VC version as a LooseVersion object + """ + version_str = self.configuration.vmware_host_version + if version_str: + LOG.info(_("Using overridden vmware_host_version from config: " + "%s"), version_str) + else: + version_str = self.session.vim.service_content.about.version + LOG.info(_("Fetched VC server version: %s"), version_str) + # convert version_str to LooseVersion and return + version = None + try: + version = dist_version.LooseVersion(version_str) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.exception(_("Version string '%s' is not parseable"), + version_str) + return version + def do_setup(self, context): """Any initialization the volume driver does while starting.""" super(VMwareVcVmdkDriver, self).do_setup(context) # VC specific setup is done here - pbm_wsdl = self.configuration.pbm_wsdl_location + + # Enable pbm only if VC version is greater than 5.5 + vc_version = self._get_vc_version() + if vc_version and vc_version >= self.PBM_ENABLED_VC_VERSION: + self.pbm_wsdl = self._get_pbm_wsdl_location(vc_version) + if not self.pbm_wsdl: + LOG.error(_("Not able to configure PBM for VC server: %s"), + vc_version) + raise error_util.VMwareDriverException() + self._storage_policy_enabled = True + # Destroy current session so that it is recreated with pbm enabled + self._session = None + + # recreate session and initialize volumeops + max_objects = self.configuration.vmware_max_objects_retrieval + self._volumeops = volumeops.VMwareVolumeOps(self.session, max_objects) + + # if default policy is configured verify it exists in VC default_policy = self.configuration.pbm_default_policy - if not pbm_wsdl: - if default_policy: - LOG.warn(_("Ignoring %s since pbm_wsdl_location is not " - "set."), default_policy) - return - # pbm_wsdl is set, so storage policy should be enabled - self._storage_policy_enabled = True - # now verify the default policy exists in VC if default_policy: - if not self.volumeops.retrieve_profile_id(default_policy): - msg = _("The configured default PBM policy '%s' is not " - "defined on vCenter Server.") % default_policy - raise error_util.PbmDefaultPolicyDoesNotExist(message=msg) + if not self._storage_policy_enabled: + LOG.warn(_("Ignoring default policy '%(policy)s' since " + "Storage Policy Based Management is not " + "enabled on VC version %(ver)s") % + {'policy': default_policy, 'ver': vc_version}) else: + if not self.volumeops.retrieve_profile_id(default_policy): + msg = _("The configured default PBM policy '%s' is not " + "defined on vCenter Server.") % default_policy + raise error_util.PbmDefaultPolicyDoesNotExist(message=msg) LOG.info(_("Successfully verified existence of " "pbm_default_policy: %s."), default_policy) + LOG.info(_("Successfully setup driver: %(driver)s for server: " + "%(ip)s.") % {'driver': self.__class__.__name__, + 'ip': self.configuration.vmware_host_ip}) + def _get_volume_group_folder(self, datacenter): """Get volume group folder. diff --git a/cinder/volume/drivers/vmware/wsdl/5.5/core-types.xsd b/cinder/volume/drivers/vmware/wsdl/5.5/core-types.xsd new file mode 100644 index 000000000..85c5a1d8d --- /dev/null +++ b/cinder/volume/drivers/vmware/wsdl/5.5/core-types.xsd @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cinder/volume/drivers/vmware/wsdl/5.5/pbm-messagetypes.xsd b/cinder/volume/drivers/vmware/wsdl/5.5/pbm-messagetypes.xsd new file mode 100644 index 000000000..eeffb3b98 --- /dev/null +++ b/cinder/volume/drivers/vmware/wsdl/5.5/pbm-messagetypes.xsd @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cinder/volume/drivers/vmware/wsdl/5.5/pbm-types.xsd b/cinder/volume/drivers/vmware/wsdl/5.5/pbm-types.xsd new file mode 100644 index 000000000..397c9cfbb --- /dev/null +++ b/cinder/volume/drivers/vmware/wsdl/5.5/pbm-types.xsd @@ -0,0 +1,729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cinder/volume/drivers/vmware/wsdl/5.5/pbm.wsdl b/cinder/volume/drivers/vmware/wsdl/5.5/pbm.wsdl new file mode 100644 index 000000000..50b2d0030 --- /dev/null +++ b/cinder/volume/drivers/vmware/wsdl/5.5/pbm.wsdl @@ -0,0 +1,889 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cinder/volume/drivers/vmware/wsdl/5.5/pbmService.wsdl b/cinder/volume/drivers/vmware/wsdl/5.5/pbmService.wsdl new file mode 100644 index 000000000..e1299285d --- /dev/null +++ b/cinder/volume/drivers/vmware/wsdl/5.5/pbmService.wsdl @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/etc/cinder/cinder.conf.sample b/etc/cinder/cinder.conf.sample index d2f32770c..331b65723 100644 --- a/etc/cinder/cinder.conf.sample +++ b/etc/cinder/cinder.conf.sample @@ -1661,15 +1661,10 @@ # Options defined in cinder.volume.drivers.vmware.vmdk # -# PBM service WSDL file location URL. e.g. -# file:///opt/SDK/spbm/wsdl/pbmService.wsdl. Not setting this -# will disable storage policy based placement of volumes. -# (string value) -#pbm_wsdl_location= - -# The PBM default policy. If pbm_wsdl_location is set and -# there is no defined storage policy for the specific request -# then this policy will be used. (string value) +# The PBM default policy. If using VC server version 5.5 or +# above and there is no defined storage policy for the +# specific request then this policy will be used. (string +# value) #pbm_default_policy= # IP address for connecting to VMware ESX/VC server. (string @@ -1711,6 +1706,12 @@ # less than the configured value. (integer value) #vmware_max_objects_retrieval=100 +# Optional string specifying the VMware VC server version. The +# driver attempts to retrieve the version from VMware VC +# server. Set this configuration only if you want to override +# the VC server version. (string value) +#vmware_host_version= + # # Options defined in cinder.volume.drivers.windows.windows -- 2.45.2