From fbe42695c1310b395106f0fd62479ff32654d903 Mon Sep 17 00:00:00 2001 From: Helen Walsh Date: Sat, 13 Feb 2016 23:26:47 +0000 Subject: [PATCH] EMC VMAX - Recreating SG when it has been deleted The default storage group for VMAX3 can be deleted when the last volume has been removed from it. Certain scenarios require a volume to be returned to the default storage group. Change-Id: Icd65ee7c1b313c2410d72a252038e7cfb8b3dd2a Closes-Bug: #1543626 --- cinder/tests/unit/test_emc_vmax.py | 139 +++++--- cinder/volume/drivers/emc/emc_vmax_common.py | 40 +-- cinder/volume/drivers/emc/emc_vmax_masking.py | 301 +++++++++--------- cinder/volume/drivers/emc/emc_vmax_utils.py | 13 +- 4 files changed, 264 insertions(+), 229 deletions(-) diff --git a/cinder/tests/unit/test_emc_vmax.py b/cinder/tests/unit/test_emc_vmax.py index bd87d3474..0179452a9 100644 --- a/cinder/tests/unit/test_emc_vmax.py +++ b/cinder/tests/unit/test_emc_vmax.py @@ -484,6 +484,10 @@ class EMCVMAXCommonData(object): test_host_v3 = {'capabilities': location_info_v3, 'host': fake_host_2_v3} initiatorNames = ["123456789012345", "123456789054321"] + storagegroups = [{'CreationClassName': storagegroup_creationclass, + 'ElementName': storagegroupname}, + {'CreationClassName': storagegroup_creationclass, + 'ElementName': 'OS-SRP_1-Bronze-DSS-SG'}] test_ctxt = {} new_type = {} diff = {} @@ -2020,42 +2024,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): self.assertRaises(exception.VolumeBackendAPIException, self.driver.common.utils._get_random_portgroup, dom) - def test_cleanup_last_vol(self): - conn = FakeEcomConnection() - masking = self.driver.common.masking - extraSpecs = {'volume_backend_name': 'GOLD_BE', - 'isV3': True} - controllerConfigService = ( - self.driver.utils.find_controller_configuration_service( - conn, self.data.storage_system)) - storageGroupName = self.data.storagegroupname - storageGroupInstanceName = ( - self.driver.utils.find_storage_masking_group( - conn, controllerConfigService, storageGroupName)) - volumeInstance = EMC_StorageVolume() - volumeInstance.path = ( - conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) - - volumeName = self.data.test_volume['name'] - masking._last_volume_delete_masking_view = mock.Mock() - storageSystemInstanceName = ( - conn.EnumerateInstanceNames("EMC_StorageSystem")[0]) - # Failure case, an exception is thrown in - # _remove_last_vol_and_delete_sg so the returning the vol to - # the default SG cannot continue - self.assertRaises( - exception.VolumeBackendAPIException, - masking._cleanup_last_vol, conn, controllerConfigService, - storageGroupInstanceName, storageGroupName, volumeInstance, - volumeName, storageSystemInstanceName, False, extraSpecs) - - # Success case, the last vol is removed and the SG is deleted - masking._remove_last_vol_and_delete_sg = mock.Mock(return_value=True) - masking._cleanup_last_vol( - conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, - storageSystemInstanceName, False, extraSpecs) - def test_is_sync_complete(self): conn = self.fake_ecom_connection() syncname = SE_ConcreteJob() @@ -6289,6 +6257,8 @@ class EMCV3DriverTestCase(test.TestCase): common = self.driver.common common.get_target_wwns = mock.Mock( return_value=EMCVMAXCommonData.target_wwns) + common.masking.utils.find_storage_masking_group = mock.Mock( + return_value=self.data.storagegroups[0]) self.driver.common._initial_setup = mock.Mock( return_value=self.default_extraspec()) data = self.driver.terminate_connection(self.data.test_volume_v3, @@ -6343,15 +6313,11 @@ class EMCV3DriverTestCase(test.TestCase): extraSpecs = common._initial_setup(self.data.test_volume_v3) targetInstance = ( conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) - storageGroupName = common.utils.get_v3_storage_group_name('SRP_1', - 'Bronze', - 'DSS') deviceID = targetInstance['DeviceID'] common._delete_from_pool_v3.assert_called_with(storageConfigService, targetInstance, targetInstance['Name'], deviceID, - storageGroupName, extraSpecs) def test_get_remaining_slo_capacity_wlp(self): @@ -7496,6 +7462,99 @@ class EMCVMAXMaskingTest(test.TestCase): controllerConfigService, maskingviewdict['volumeName'])) self.assertIsNone(result) + def test_return_volume_to_default_storage_group_v3(self): + masking = self.driver.common.masking + conn = self.fake_ecom_connection() + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeInstance = conn.GetInstance(volumeInstanceName) + volumeName = "V3-Vol" + extraSpecs = {'volume_backend_name': 'V3_BE', + 'isV3': True, + 'storagetype:pool': 'SRP_1', + 'storagetype:workload': 'DSS', + 'storagetype:slo': 'Bronze'} + controllerConfigService = ( + self.driver.utils.find_controller_configuration_service( + conn, self.data.storage_system)) + masking.provisionv3.create_storage_group_v3 = mock.Mock( + return_value={'Value'}) + masking._is_volume_in_storage_group = mock.Mock( + return_value=True) + masking.return_volume_to_default_storage_group_v3 = mock.Mock() + masking._return_back_to_default_sg( + conn, controllerConfigService, volumeInstance, volumeName, + extraSpecs) + masking.return_volume_to_default_storage_group_v3.assert_called_with( + conn, controllerConfigService, + volumeInstance, volumeName, extraSpecs) + + def test_return_volume_to_default_storage_group_v3_exception(self): + masking = self.driver.common.masking + conn = self.fake_ecom_connection() + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeInstance = conn.GetInstance(volumeInstanceName) + volumeName = "V3-Vol" + extraSpecs = {'volume_backend_name': 'V3_BE', + 'isV3': True, + 'storagetype:pool': 'SRP_1', + 'storagetype:workload': 'DSS', + 'storagetype:slo': 'Bronze'} + controllerConfigService = ( + self.driver.utils.find_controller_configuration_service( + conn, self.data.storage_system)) + + self.assertRaises( + exception.VolumeBackendAPIException, + masking.return_volume_to_default_storage_group_v3, + conn, controllerConfigService, + volumeInstance, volumeName, extraSpecs) + + def test_add_volume_to_sg_and_verify(self): + masking = self.driver.common.masking + conn = self.fake_ecom_connection() + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeInstance = conn.GetInstance(volumeInstanceName) + volumeName = "V3-Vol" + storageGroupInstanceName = self.data.storagegroups[0] + sgGroupName = self.data.storagegroupname + extraSpecs = {'volume_backend_name': 'V3_BE', + 'isV3': True, + 'storagetype:pool': 'SRP_1', + 'storagetype:workload': 'DSS', + 'storagetype:slo': 'Bronze'} + controllerConfigService = ( + self.driver.utils.find_controller_configuration_service( + conn, self.data.storage_system)) + msg = masking._add_volume_to_sg_and_verify( + conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, volumeName, sgGroupName, extraSpecs) + self.assertIsNone(msg) + + def test_remove_volume_from_sg(self): + masking = self.driver.common.masking + conn = self.fake_ecom_connection() + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeInstance = conn.GetInstance(volumeInstanceName) + storageGroupInstanceName = self.data.storagegroups[1] + extraSpecs = {'volume_backend_name': 'V3_BE', + 'isV3': True, + 'storagetype:pool': 'SRP_1', + 'storagetype:workload': 'DSS', + 'storagetype:slo': 'Bronze'} + controllerConfigService = ( + self.driver.utils.find_controller_configuration_service( + conn, self.data.storage_system)) + masking._remove_volume_from_sg = mock.Mock() + masking._cleanup_deletion_v3( + conn, controllerConfigService, volumeInstance, extraSpecs) + masking._remove_volume_from_sg.assert_called_with( + conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, extraSpecs) + class EMCVMAXFCTest(test.TestCase): def setUp(self): diff --git a/cinder/volume/drivers/emc/emc_vmax_common.py b/cinder/volume/drivers/emc/emc_vmax_common.py index 1e4fede9d..06728cd4e 100644 --- a/cinder/volume/drivers/emc/emc_vmax_common.py +++ b/cinder/volume/drivers/emc/emc_vmax_common.py @@ -414,7 +414,7 @@ class EMCVMAXCommon(object): return deviceInfoDict def _attach_volume(self, volume, connector, extraSpecs, - maskingViewDict, isLiveMigration=None): + maskingViewDict, isLiveMigration=False): """Attach a volume to a host. If live migration is being undertaken then the volume @@ -2199,12 +2199,9 @@ class EMCVMAXCommon(object): deviceId = volumeInstance['DeviceID'] if extraSpecs[ISV3]: - storageGroupName = self.utils.get_v3_storage_group_name( - extraSpecs[POOL], extraSpecs[SLO], - extraSpecs[WORKLOAD]) rc = self._delete_from_pool_v3( storageConfigService, volumeInstance, volumeName, - deviceId, storageGroupName, extraSpecs) + deviceId, extraSpecs) else: rc = self._delete_from_pool(storageConfigService, volumeInstance, volumeName, deviceId, @@ -3433,15 +3430,13 @@ class EMCVMAXCommon(object): return rc def _delete_from_pool_v3(self, storageConfigService, volumeInstance, - volumeName, deviceId, storageGroupName, - extraSpecs): + volumeName, deviceId, extraSpecs): """Delete from pool (v3). :param storageConfigService: the storage config service :param volumeInstance: the volume instance :param volumeName: the volume Name :param deviceId: the device ID of the volume - :param storageGroupName: the name of the default SG :param extraSpecs: extra specifications :returns: int -- return code :raises: VolumeBackendAPIException @@ -3453,9 +3448,9 @@ class EMCVMAXCommon(object): # Check if it is part of a storage group and delete it # extra logic for case when volume is the last member. - sgFromVolInstanceName = self.masking.remove_and_reset_members( + self.masking.remove_and_reset_members( self.conn, controllerConfigurationService, volumeInstance, - volumeName, extraSpecs, None, 'noReset') + volumeName, extraSpecs, None, False) LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool " "ConfigServic: %(service)s TheElement: %(vol_instance)s " @@ -3473,23 +3468,9 @@ class EMCVMAXCommon(object): # If we cannot successfully delete the volume, then we want to # return the volume to the default storage group, # which should be the SG it previously belonged to. - storageGroupInstanceName = self.utils.find_storage_masking_group( - self.conn, controllerConfigurationService, storageGroupName) - - if sgFromVolInstanceName is not storageGroupInstanceName: - LOG.debug( - "Volume: %(volumeName)s was not previously part of " - " %(storageGroupInstanceName)s. " - "Returning to %(storageGroupName)s.", - {'volumeName': volumeName, - 'storageGroupInstanceName': storageGroupInstanceName, - 'storageGroupName': storageGroupName}) - - if storageGroupInstanceName is not None: - self.masking.add_volume_to_storage_group( - self.conn, controllerConfigurationService, - storageGroupInstanceName, volumeInstance, volumeName, - storageGroupName, extraSpecs) + self.masking.return_volume_to_default_storage_group_v3( + self.conn, controllerConfigurationService, + volumeInstance, volumeName, extraSpecs) errorMessage = (_("Failed to delete volume %(volumeName)s.") % {'volumeName': volumeName}) @@ -3855,12 +3836,9 @@ class EMCVMAXCommon(object): self.conn, storageSystem)) deviceId = targetInstance['DeviceID'] volumeName = targetInstance['Name'] - storageGroupName = self.utils.get_v3_storage_group_name( - extraSpecs[POOL], extraSpecs[SLO], - extraSpecs[WORKLOAD]) rc = self._delete_from_pool_v3( storageConfigService, targetInstance, volumeName, - deviceId, storageGroupName, extraSpecs) + deviceId, extraSpecs) # Re-throw the exception. raise diff --git a/cinder/volume/drivers/emc/emc_vmax_masking.py b/cinder/volume/drivers/emc/emc_vmax_masking.py index d770e58be..762f33226 100644 --- a/cinder/volume/drivers/emc/emc_vmax_masking.py +++ b/cinder/volume/drivers/emc/emc_vmax_masking.py @@ -519,34 +519,53 @@ class EMCVMAXMasking(object): if self._is_volume_in_storage_group( conn, storageGroupInstanceName, volumeInstance, sgGroupName): - LOG.debug( + LOG.warning(_LW( "Volume: %(volumeName)s is already part " - "of storage group %(sgGroupName)s.", + "of storage group %(sgGroupName)s."), {'volumeName': volumeName, 'sgGroupName': sgGroupName}) else: - self.add_volume_to_storage_group( - conn, controllerConfigService, - storageGroupInstanceName, volumeInstance, volumeName, - sgGroupName, maskingViewDict['extraSpecs']) - if not self._is_volume_in_storage_group( - conn, storageGroupInstanceName, - volumeInstance, sgGroupName): - # This may be used in exception hence _ instead of _LE. - msg = (_( - "Volume: %(volumeName)s was not added " - "to storage group %(sgGroupName)s. ") % - {'volumeName': volumeName, - 'sgGroupName': sgGroupName}) - LOG.error(msg) - else: - LOG.info(_LI( - "Successfully added %(volumeName)s to %(sgGroupName)s."), - {'volumeName': volumeName, - 'sgGroupName': sgGroupName}) + msg = self._add_volume_to_sg_and_verify( + conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, volumeName, sgGroupName, + maskingViewDict['extraSpecs']) return msg + def _add_volume_to_sg_and_verify( + self, conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, volumeName, sgGroupName, extraSpecs): + """Add the volume to the storage group and double check it is there. + + :param conn: the ecom connection + :param controllerConfigService: controller service + :param storageGroupInstanceName: storage group instance name + :param volumeInstance: the volume instance + :param volumeName: the volume name + :param sgGroupName: the storage group name + :param extraSpecs: the extra specifications + :returns: string -- the error message + """ + msg = None + self.add_volume_to_storage_group( + conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, volumeName, sgGroupName, extraSpecs) + if not self._is_volume_in_storage_group( + conn, storageGroupInstanceName, volumeInstance, sgGroupName): + # This may be used in exception hence _ instead of _LE. + msg = (_( + "Volume: %(volumeName)s was not added " + "to storage group %(sgGroupName)s.") % + {'volumeName': volumeName, + 'sgGroupName': sgGroupName}) + LOG.error(msg) + else: + LOG.info(_LI("Successfully added %(volumeName)s to " + "%(sgGroupName)s."), + {'volumeName': volumeName, + 'sgGroupName': sgGroupName}) + return msg + def _get_and_remove_from_storage_group_v2( self, conn, controllerConfigService, volumeInstanceName, volumeName, fastPolicyName, extraSpecs): @@ -1747,14 +1766,11 @@ class EMCVMAXMasking(object): def remove_and_reset_members( self, conn, controllerConfigService, volumeInstance, - volumeName, extraSpecs, connector=None, noReset=None): - """Part of unmap device or rollback. + volumeName, extraSpecs, connector=None, reset=True): + """This is called on a delete, unmap device or rollback. - Removes volume from the Device Masking Group that belongs to a - Masking View. Check if fast policy is in the extra specs, if it isn't - we do not need to do any thing for FAST. Assume that - isTieringPolicySupported is False unless the FAST policy is in - the extra specs and tiering is enabled on the array. + If the connector is not None get the associated SG and remove volume + from the storage group, otherwise it is a VMAX3 deletion. :param conn: connection the the ecom server :param controllerConfigService: the controller configuration service @@ -1762,33 +1778,72 @@ class EMCVMAXMasking(object): :param volumeName: the volume name :param extraSpecs: additional info :param connector: optional - :param noReset: optional, if none, then reset + :param reset: reset, return to original SG (optional) :returns: storageGroupInstanceName """ - fastPolicyName = extraSpecs.get(FASTPOLICY, None) - isV3 = extraSpecs[ISV3] storageGroupInstanceName = None if connector is not None: storageGroupInstanceName = self._get_sg_associated_with_connector( conn, controllerConfigService, volumeInstance.path, volumeName, connector) - if storageGroupInstanceName is None: - return None + if storageGroupInstanceName: + self._remove_volume_from_sg( + conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, extraSpecs) else: # Connector is None in V3 volume deletion case. - storageGroupInstanceNames = ( - self.get_associated_masking_groups_from_device( - conn, volumeInstance.path)) - if storageGroupInstanceNames: - storageGroupInstanceName = storageGroupInstanceNames[0] - else: - return None + self._cleanup_deletion_v3( + conn, controllerConfigService, volumeInstance, extraSpecs) + if reset: + self._return_back_to_default_sg( + conn, controllerConfigService, volumeInstance, volumeName, + extraSpecs) + + return storageGroupInstanceName + + def _cleanup_deletion_v3( + self, conn, controllerConfigService, volumeInstance, extraSpecs): + """Pre cleanup before VMAX3 deletion operation + + :param conn: the ecom connection + :param controllerConfigService: storage system instance name + :param volumeInstance: the volume instance + :param extraSpecs: the extra specifications + """ + storageGroupInstanceNames = ( + self.get_associated_masking_groups_from_device( + conn, volumeInstance.path)) + + if storageGroupInstanceNames: + sgNum = len(storageGroupInstanceNames) + if len(storageGroupInstanceNames) > 1: + LOG.warning(_LW("Volume %(volumeName)s is belong to " + "%(sgNum)s storage groups."), + {'volumeName': volumeInstance['ElementName'], + 'sgNum': sgNum}) + for storageGroupInstanceName in storageGroupInstanceNames: + self._remove_volume_from_sg( + conn, controllerConfigService, + storageGroupInstanceName, + volumeInstance, + extraSpecs) + + def _remove_volume_from_sg( + self, conn, controllerConfigService, storageGroupInstanceName, + volumeInstance, extraSpecs): + + """Remove volume from storage group + + :param conn: the ecom connection + :param controllerConfigService: storage system instance name + :param storageGroupInstanceName: the SG instance name + :param volumeInstance: the volume instance + :param extraSpecs: the extra specifications + """ instance = conn.GetInstance(storageGroupInstanceName, LocalOnly=False) storageGroupName = instance['ElementName'] volumeInstanceNames = self.get_devices_from_storage_group( conn, storageGroupInstanceName) - storageSystemInstanceName = self.utils.find_storage_system( - conn, controllerConfigService) numVolInStorageGroup = len(volumeInstanceNames) LOG.debug( @@ -1797,25 +1852,18 @@ class EMCVMAXMasking(object): {'numVol': numVolInStorageGroup, 'maskingGroup': storageGroupInstanceName}) - if not isV3: - isTieringPolicySupported, __ = ( - self._get_tiering_info(conn, storageSystemInstanceName, - fastPolicyName)) - if numVolInStorageGroup == 1: # Last volume in the storage group. self._last_vol_in_SG( conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, extraSpecs) + storageGroupName, volumeInstance, + volumeInstance['ElementName'], extraSpecs) else: - # Not the last volume so remove it from storage group in - # the masking view. + # Not the last volume so remove it from storage group self._multiple_vols_in_SG( conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, - numVolInStorageGroup, fastPolicyName, extraSpecs) - - return storageGroupInstanceName + volumeInstance, volumeInstance['ElementName'], + numVolInStorageGroup, extraSpecs) def _last_vol_in_SG( self, conn, controllerConfigService, storageGroupInstanceName, @@ -1881,29 +1929,20 @@ class EMCVMAXMasking(object): def _multiple_vols_in_SG( self, conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, numVolsInSG, - fastPolicyName, extraSpecs): - """Necessary steps if the volume is not the last in the SG. + volumeInstance, volumeName, numVolsInSG, extraSpecs): + """If the volume is not the last in the storage group - 1. Remove the volume from the SG. - 2. Return the volume to default SG if necessary. + Remove the volume from the SG. :param conn: the ecom connection :param controllerConfigService: storage system instance name :param storageGroupInstanceName: the SG instance name - :param storageGroupName: the Storage group name (String) :param volumeInstance: the volume instance :param volumeName: the volume name :param numVolsInSG: the number of volumes in the SG - :param fastPolicyName: the FAST policy name :param extraSpecs: the extra specifications """ - storageSystemInstanceName = self.utils.find_storage_system( - conn, controllerConfigService) - if not extraSpecs[ISV3]: - isTieringPolicySupported, __ = ( - self._get_tiering_info(conn, storageSystemInstanceName, - fastPolicyName)) + LOG.debug("Start: number of volumes in masking storage group: " "%(numVol)d", {'numVol': numVolsInSG}) self.provision.remove_device_from_storage_group( @@ -1914,19 +1953,6 @@ class EMCVMAXMasking(object): "RemoveMembers for volume %(volumeName)s completed " "successfully.", {'volumeName': volumeName}) - # Add it back to the default storage group. - if extraSpecs[ISV3]: - self._return_volume_to_default_storage_group_v3( - conn, controllerConfigService, storageGroupName, - volumeInstance, volumeName, storageSystemInstanceName, - extraSpecs) - else: - # V2 if FAST POLICY enabled, move the volume to the default SG. - if fastPolicyName is not None and isTieringPolicySupported: - self._cleanup_tiering( - conn, controllerConfigService, fastPolicyName, - volumeInstance, volumeName, extraSpecs) - volumeInstanceNames = self.get_devices_from_storage_group( conn, storageGroupInstanceName) LOG.debug( @@ -1939,10 +1965,6 @@ class EMCVMAXMasking(object): volumeInstance, volumeName, extraSpecs): """Delete the Masking view, the storage Group and the initiator group. - Also does necessary cleanup like removing the policy from the - storage group for V2 and returning the volume to the default - storage group. - :param conn: connection the the ecom server :param controllerConfigService: the controller configuration service :param mvInstanceName: masking view instance name @@ -1978,56 +2000,49 @@ class EMCVMAXMasking(object): storageSystemInstanceName['Name'], storageGroupInstanceName, extraSpecs) - self._cleanup_last_vol( + self._remove_last_vol_and_delete_sg( conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, - storageSystemInstanceName, isTieringPolicySupported, extraSpecs) + storageGroupName, volumeInstance.path, volumeName, + extraSpecs) - def _cleanup_last_vol( - self, conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance, volumeName, - storageSystemInstanceName, isTieringPolicySupported, extraSpecs): - """Do necessary cleanup when the volume is the last in the SG. + LOG.debug( + "Volume %(volumeName)s successfully removed from SG and " + "Storage Group %(storageGroupName)s successfully deleted. ", + {'volumeName': volumeName, + 'storageGroupName': storageGroupName}) + + def _return_back_to_default_sg( + self, conn, controllerConfigService, volumeInstance, volumeName, + extraSpecs): + """Return volume to default storage group - This includes removing the last volume from the SG and deleting the - SG. It also means moving the volume to the default SG for VMAX3 and + Moving the volume to the default SG for VMAX3 and FAST for VMAX2. :param conn: connection the the ecom server :param controllerConfigService: the controller configuration service - :param storageGroupInstanceName: storage group instance name - :param storageGroupName: the storage group name :param volumeInstance: the volume Instance :param volumeName: the volume name - :param storageSystemInstanceName: the storage system instance name - :param isTieringPolicySupported: tiering policy supported flag :param extraSpecs: extra specs """ - # Remove the last volume and delete the storage group. - self._remove_last_vol_and_delete_sg( - conn, controllerConfigService, storageGroupInstanceName, - storageGroupName, volumeInstance.path, volumeName, - extraSpecs) # Add it back to the default storage group. if extraSpecs[ISV3]: - self._return_volume_to_default_storage_group_v3( - conn, controllerConfigService, storageGroupName, - volumeInstance, volumeName, storageSystemInstanceName, - extraSpecs) + self.return_volume_to_default_storage_group_v3( + conn, controllerConfigService, + volumeInstance, volumeName, extraSpecs) else: # V2 if FAST POLICY enabled, move the volume to the default # SG. fastPolicyName = extraSpecs.get(FASTPOLICY, None) + storageSystemInstanceName = self.utils.find_storage_system( + conn, controllerConfigService) + isTieringPolicySupported, __ = ( + self._get_tiering_info(conn, storageSystemInstanceName, + fastPolicyName)) if fastPolicyName is not None and isTieringPolicySupported: self._cleanup_tiering( conn, controllerConfigService, fastPolicyName, volumeInstance, volumeName, extraSpecs) - LOG.debug( - "Volume %(volumeName)s successfully removed from SG and " - "returned to default storage group where applicable. " - "Storage Group %(storageGroupName)s successfully deleted. ", - {'volumeName': volumeName, - 'storageGroupName': storageGroupName}) def _get_sg_associated_with_connector( self, conn, controllerConfigService, volumeInstanceName, @@ -2141,51 +2156,41 @@ class EMCVMAXMasking(object): conn, tierPolicyServiceInstanceName, storageGroupInstanceName, tierPolicyInstanceName, extraSpecs) - def _return_volume_to_default_storage_group_v3( - self, conn, controllerConfigService, storageGroupName, - volumeInstance, volumeName, storageSystemInstanceName, - extraSpecs): + def return_volume_to_default_storage_group_v3( + self, conn, controllerConfigurationService, + volumeInstance, volumeName, extraSpecs): """Return volume to the default storage group in v3. :param conn: the ecom connection :param controllerConfigService: controller config service - :param storageGroupName: storage group name :param volumeInstance: volumeInstance :param volumeName: the volume name - :param storageSystemInstanceName: the storage system instance name :param extraSpecs: additional info :raises: VolumeBackendAPIException """ - # First strip the shortHostname from the storage group name. - defaultStorageGroupName, shorthostName = ( - self.utils.strip_short_host_name(storageGroupName)) - - # Check if host name exists which signifies detach operation. - if shorthostName is not None: - # Populate maskingViewDict and storageGroupInstanceName. - maskingViewDict = {} - maskingViewDict['sgGroupName'] = defaultStorageGroupName - maskingViewDict['volumeInstance'] = volumeInstance - maskingViewDict['volumeName'] = volumeName - maskingViewDict['controllerConfigService'] = ( - controllerConfigService) - maskingViewDict['storageSystemName'] = ( - storageSystemInstanceName) - sgInstanceName = self.utils.find_storage_masking_group( - conn, controllerConfigService, defaultStorageGroupName) - if sgInstanceName is not None: - errorMessage = ( - self._check_adding_volume_to_storage_group( - conn, maskingViewDict, - sgInstanceName)) - else: - errorMessage = (_( - "Storage group %(sgGroupName)s " - "does not exist.") - % {'sgGroupName': defaultStorageGroupName}) + storageGroupName = self.utils.get_v3_storage_group_name( + extraSpecs[self.utils.POOL], extraSpecs[self.utils.SLO], + extraSpecs[self.utils.WORKLOAD]) + storageGroupInstanceName = self.utils.find_storage_masking_group( + conn, controllerConfigurationService, storageGroupName) + + if not storageGroupInstanceName: + storageGroupInstanceName = ( + self.provisionv3.create_storage_group_v3( + conn, controllerConfigurationService, storageGroupName, + extraSpecs[self.utils.POOL], extraSpecs[self.utils.SLO], + extraSpecs[self.utils.WORKLOAD], extraSpecs)) + if not storageGroupInstanceName: + errorMessage = (_("Failed to create storage group " + "%(storageGroupName)s.") % + {'storageGroupName': storageGroupName}) LOG.error(errorMessage) - raise exception.VolumeBackendAPIException( - data=errorMessage) + raise exception.VolumeBackendAPIException(data=errorMessage) + + self._add_volume_to_sg_and_verify( + conn, controllerConfigurationService, + storageGroupInstanceName, volumeInstance, volumeName, + storageGroupName, extraSpecs) def _cleanup_tiering( self, conn, controllerConfigService, fastPolicyName, diff --git a/cinder/volume/drivers/emc/emc_vmax_utils.py b/cinder/volume/drivers/emc/emc_vmax_utils.py index a065a2505..0c32707a5 100644 --- a/cinder/volume/drivers/emc/emc_vmax_utils.py +++ b/cinder/volume/drivers/emc/emc_vmax_utils.py @@ -62,6 +62,9 @@ class EMCVMAXUtils(object): This Utility class is for EMC volume drivers based on SMI-S. It supports VMAX arrays. """ + SLO = 'storagetype:slo' + WORKLOAD = 'storagetype:workload' + POOL = 'storagetype:pool' def __init__(self, prtcl): if not pywbemAvailable: @@ -1526,16 +1529,6 @@ class EMCVMAXUtils(object): 'workload': workload}) return storageGroupName - def strip_short_host_name(self, storageGroupName): - tempList = storageGroupName.split("-") - if len(tempList) == 6: - shorthostName = tempList.pop(1) - updatedStorageGroup = "-".join(tempList) - return updatedStorageGroup, shorthostName - else: - shorthostName = None - return storageGroupName, shorthostName - def _get_fast_settings_from_storage_group(self, storageGroupInstance): """Get the emc FAST setting from the storage group. -- 2.45.2