From ef6b747baad390ae7b439fa4be103be6b149669f Mon Sep 17 00:00:00 2001 From: Helen Walsh Date: Thu, 5 Nov 2015 13:33:34 +0000 Subject: [PATCH] Error handling for invalid SLO/Workload combo This fix checks the VMAX3 to see if the user inputted SLO/workload combination is valid. If it is not, a explanatory exception is thrown. Closes-Bug: #1512795 Change-Id: Ic55830eef96788eff8f6ab141a60e1dcfb9971b8 --- cinder/tests/unit/test_emc_vmax.py | 56 ++++++++++++++++++- cinder/volume/drivers/emc/emc_vmax_common.py | 13 +++++ cinder/volume/drivers/emc/emc_vmax_fc.py | 1 + cinder/volume/drivers/emc/emc_vmax_iscsi.py | 1 + .../drivers/emc/emc_vmax_provision_v3.py | 25 ++++++--- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cinder/tests/unit/test_emc_vmax.py b/cinder/tests/unit/test_emc_vmax.py index 3e7d510c3..d42e9eff4 100644 --- a/cinder/tests/unit/test_emc_vmax.py +++ b/cinder/tests/unit/test_emc_vmax.py @@ -1466,7 +1466,7 @@ class FakeEcomConnection(object): storagesetting = {} storagesetting['CreationClassName'] = 'CIM_StoragePoolSetting' storagesetting['InstanceID'] = ('SYMMETRIX-+-000197200056-+-SBronze:' - 'NONE-+-F-+-0-+-SR-+-SRP_1') + 'DSS-+-F-+-0-+-SR-+-SRP_1') storagesettings.append(storagesetting) return storagesettings @@ -5615,6 +5615,12 @@ class EMCV3DriverTestCase(test.TestCase): self, _mock_volume_type, mock_storage_system): v3_vol = self.data.test_volume_v3 v3_vol['host'] = 'HostX@Backend#NONE+SRP_1+1234567891011' + instid = 'SYMMETRIX-+-000197200056-+-NONE:DSS-+-F-+-0-+-SR-+-SRP_1' + storagepoolsetting = ( + {'InstanceID': instid, + 'CreationClassName': 'CIM_StoragePoolSetting'}) + self.driver.common.provisionv3.get_storage_pool_setting = mock.Mock( + return_value=storagepoolsetting) extraSpecs = {'storagetype:pool': 'SRP_1', 'volume_backend_name': 'V3_BE', 'storagetype:workload': 'DSS', @@ -6975,3 +6981,51 @@ class EMCV2MultiPoolDriverMultipleEcomsTestCase(test.TestCase): if bExists: os.remove(self.config_file_path) shutil.rmtree(self.tempdir) + + +class EMCVMAXProvisionV3Test(test.TestCase): + def setUp(self): + self.data = EMCVMAXCommonData() + + super(EMCVMAXProvisionV3Test, self).setUp() + + configuration = mock.Mock() + configuration.safe_get.return_value = 'ProvisionV3Tests' + configuration.config_group = 'ProvisionV3Tests' + emc_vmax_common.EMCVMAXCommon._gather_info = mock.Mock() + driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration) + driver.db = FakeDB() + self.driver = driver + + def test_get_storage_pool_setting(self): + provisionv3 = self.driver.common.provisionv3 + conn = FakeEcomConnection() + slo = 'Bronze' + workload = 'DSS' + poolInstanceName = {} + poolInstanceName['InstanceID'] = "SATA_GOLD1" + poolInstanceName['CreationClassName'] = ( + self.data.storagepool_creationclass) + + storagePoolCapability = provisionv3.get_storage_pool_capability( + conn, poolInstanceName) + storagepoolsetting = provisionv3.get_storage_pool_setting( + conn, storagePoolCapability, slo, workload) + self.assertTrue( + 'Bronze:DSS' in storagepoolsetting['InstanceID']) + + def test_get_storage_pool_setting_exception(self): + provisionv3 = self.driver.common.provisionv3 + conn = FakeEcomConnection() + slo = 'Bronze' + workload = 'NONE' + poolInstanceName = {} + poolInstanceName['InstanceID'] = "SATA_GOLD1" + poolInstanceName['CreationClassName'] = ( + self.data.storagepool_creationclass) + + storagePoolCapability = provisionv3.get_storage_pool_capability( + conn, poolInstanceName) + self.assertRaises(exception.VolumeBackendAPIException, + provisionv3.get_storage_pool_setting, + conn, storagePoolCapability, slo, workload) diff --git a/cinder/volume/drivers/emc/emc_vmax_common.py b/cinder/volume/drivers/emc/emc_vmax_common.py index 928e0cd6c..27b21c310 100644 --- a/cinder/volume/drivers/emc/emc_vmax_common.py +++ b/cinder/volume/drivers/emc/emc_vmax_common.py @@ -2838,6 +2838,19 @@ class EMCVMAXCommon(object): poolInstanceName, storageSystemName = ( self._get_pool_and_storage_system(extraSpecs)) + # Check to see if SLO and Workload are configured on the array. + storagePoolCapability = self.provisionv3.get_storage_pool_capability( + self.conn, poolInstanceName) + if storagePoolCapability: + self.provisionv3.get_storage_pool_setting( + self.conn, storagePoolCapability, extraSpecs[SLO], + extraSpecs[WORKLOAD]) + else: + exceptionMessage = (_( + "Cannot determine storage pool settings.")) + LOG.error(exceptionMessage) + raise exception.VolumeBackendAPIException(data=exceptionMessage) + LOG.debug("Create Volume: %(volume)s Pool: %(pool)s " "Storage System: %(storageSystem)s " "Size: %(size)lu.", diff --git a/cinder/volume/drivers/emc/emc_vmax_fc.py b/cinder/volume/drivers/emc/emc_vmax_fc.py index 4b3a286ed..cf33cc6fb 100644 --- a/cinder/volume/drivers/emc/emc_vmax_fc.py +++ b/cinder/volume/drivers/emc/emc_vmax_fc.py @@ -46,6 +46,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver): - Fix for randomly choosing port group. (bug #1501919) - get_short_host_name needs to be called in find_device_number (bug #1520635) + - Proper error handling for invalid SLOs (bug #1512795) """ VERSION = "2.3.0" diff --git a/cinder/volume/drivers/emc/emc_vmax_iscsi.py b/cinder/volume/drivers/emc/emc_vmax_iscsi.py index 605aef1cf..878a26849 100644 --- a/cinder/volume/drivers/emc/emc_vmax_iscsi.py +++ b/cinder/volume/drivers/emc/emc_vmax_iscsi.py @@ -54,6 +54,7 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver): - Fix for randomly choosing port group. (bug #1501919) - get_short_host_name needs to be called in find_device_number (bug #1520635) + - Proper error handling for invalid SLOs (bug #1512795) """ VERSION = "2.3.0" diff --git a/cinder/volume/drivers/emc/emc_vmax_provision_v3.py b/cinder/volume/drivers/emc/emc_vmax_provision_v3.py index a8a6d366b..dc8442e1c 100644 --- a/cinder/volume/drivers/emc/emc_vmax_provision_v3.py +++ b/cinder/volume/drivers/emc/emc_vmax_provision_v3.py @@ -316,7 +316,7 @@ class EMCVMAXProvisionV3(object): return foundStorageGroupInstanceName - def _get_storage_pool_capability(self, conn, poolInstanceName): + def get_storage_pool_capability(self, conn, poolInstanceName): """Get the pool capability. :param conn: the connection information to the ecom server @@ -334,7 +334,7 @@ class EMCVMAXProvisionV3(object): return storagePoolCapability - def _get_storage_pool_setting( + def get_storage_pool_setting( self, conn, storagePoolCapability, slo, workload): """Get the pool setting for pool capability. @@ -358,6 +358,16 @@ class EMCVMAXProvisionV3(object): if matchString in settingInstanceID: foundStoragePoolSetting = storagePoolSetting break + if foundStoragePoolSetting is None: + exceptionMessage = (_( + "The array does not support the storage pool setting " + "for SLO %(slo)s and workload %(workload)s. Please " + "check the array for valid SLOs and workloads.") + % {'slo': slo, + 'workload': workload}) + LOG.error(exceptionMessage) + raise exception.VolumeBackendAPIException( + data=exceptionMessage) return foundStoragePoolSetting def _get_supported_size_range_for_SLO( @@ -416,15 +426,14 @@ class EMCVMAXProvisionV3(object): :returns: supportedSizeDict """ supportedSizeDict = {} - storagePoolCapabilityInstanceName = self._get_storage_pool_capability( + storagePoolCapabilityInstanceName = self.get_storage_pool_capability( conn, poolInstanceName) if storagePoolCapabilityInstanceName: - storagePoolSettingInstanceName = self._get_storage_pool_setting( + storagePoolSettingInstanceName = self.get_storage_pool_setting( conn, storagePoolCapabilityInstanceName, slo, workload) - if storagePoolCapabilityInstanceName: - supportedSizeDict = self._get_supported_size_range_for_SLO( - conn, storageConfigService, poolInstanceName, - storagePoolSettingInstanceName, extraSpecs) + supportedSizeDict = self._get_supported_size_range_for_SLO( + conn, storageConfigService, poolInstanceName, + storagePoolSettingInstanceName, extraSpecs) return supportedSizeDict def activate_snap_relationship( -- 2.45.2