Merge "EMC VMAX - Recreating SG when it has been deleted"

This commit is contained in:
Jenkins
2016-03-04 17:36:51 +00:00
committed by Gerrit Code Review
4 changed files with 270 additions and 235 deletions

View File

@@ -484,6 +484,10 @@ class EMCVMAXCommonData(object):
test_host_v3 = {'capabilities': location_info_v3, test_host_v3 = {'capabilities': location_info_v3,
'host': fake_host_2_v3} 'host': fake_host_2_v3}
initiatorNames = ["123456789012345", "123456789054321"] initiatorNames = ["123456789012345", "123456789054321"]
storagegroups = [{'CreationClassName': storagegroup_creationclass,
'ElementName': storagegroupname},
{'CreationClassName': storagegroup_creationclass,
'ElementName': 'OS-SRP_1-Bronze-DSS-SG'}]
test_ctxt = {} test_ctxt = {}
new_type = {} new_type = {}
diff = {} diff = {}
@@ -2038,42 +2042,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
self.assertRaises(exception.VolumeBackendAPIException, self.assertRaises(exception.VolumeBackendAPIException,
self.driver.common.utils._get_random_portgroup, dom) 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): def test_is_sync_complete(self):
conn = self.fake_ecom_connection() conn = self.fake_ecom_connection()
syncname = SE_ConcreteJob() syncname = SE_ConcreteJob()
@@ -6307,6 +6275,8 @@ class EMCV3DriverTestCase(test.TestCase):
common = self.driver.common common = self.driver.common
common.get_target_wwns = mock.Mock( common.get_target_wwns = mock.Mock(
return_value=EMCVMAXCommonData.target_wwns) 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( self.driver.common._initial_setup = mock.Mock(
return_value=self.default_extraspec()) return_value=self.default_extraspec())
data = self.driver.terminate_connection(self.data.test_volume_v3, data = self.driver.terminate_connection(self.data.test_volume_v3,
@@ -6361,15 +6331,11 @@ class EMCV3DriverTestCase(test.TestCase):
extraSpecs = common._initial_setup(self.data.test_volume_v3) extraSpecs = common._initial_setup(self.data.test_volume_v3)
targetInstance = ( targetInstance = (
conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
storageGroupName = common.utils.get_v3_storage_group_name('SRP_1',
'Bronze',
'DSS')
deviceID = targetInstance['DeviceID'] deviceID = targetInstance['DeviceID']
common._delete_from_pool_v3.assert_called_with(storageConfigService, common._delete_from_pool_v3.assert_called_with(storageConfigService,
targetInstance, targetInstance,
targetInstance['Name'], targetInstance['Name'],
deviceID, deviceID,
storageGroupName,
extraSpecs) extraSpecs)
def test_get_remaining_slo_capacity_wlp(self): def test_get_remaining_slo_capacity_wlp(self):
@@ -7514,6 +7480,99 @@ class EMCVMAXMaskingTest(test.TestCase):
controllerConfigService, maskingviewdict['volumeName'])) controllerConfigService, maskingviewdict['volumeName']))
self.assertIsNone(result) 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): class EMCVMAXFCTest(test.TestCase):
def setUp(self): def setUp(self):

View File

@@ -414,7 +414,7 @@ class EMCVMAXCommon(object):
return deviceInfoDict return deviceInfoDict
def _attach_volume(self, volume, connector, extraSpecs, def _attach_volume(self, volume, connector, extraSpecs,
maskingViewDict, isLiveMigration=None): maskingViewDict, isLiveMigration=False):
"""Attach a volume to a host. """Attach a volume to a host.
If live migration is being undertaken then the volume If live migration is being undertaken then the volume
@@ -2198,12 +2198,9 @@ class EMCVMAXCommon(object):
deviceId = volumeInstance['DeviceID'] deviceId = volumeInstance['DeviceID']
if extraSpecs[ISV3]: if extraSpecs[ISV3]:
storageGroupName = self.utils.get_v3_storage_group_name(
extraSpecs[POOL], extraSpecs[SLO],
extraSpecs[WORKLOAD])
rc = self._delete_from_pool_v3( rc = self._delete_from_pool_v3(
storageConfigService, volumeInstance, volumeName, storageConfigService, volumeInstance, volumeName,
deviceId, storageGroupName, extraSpecs) deviceId, extraSpecs)
else: else:
rc = self._delete_from_pool(storageConfigService, volumeInstance, rc = self._delete_from_pool(storageConfigService, volumeInstance,
volumeName, deviceId, volumeName, deviceId,
@@ -3432,15 +3429,13 @@ class EMCVMAXCommon(object):
return rc return rc
def _delete_from_pool_v3(self, storageConfigService, volumeInstance, def _delete_from_pool_v3(self, storageConfigService, volumeInstance,
volumeName, deviceId, storageGroupName, volumeName, deviceId, extraSpecs):
extraSpecs):
"""Delete from pool (v3). """Delete from pool (v3).
:param storageConfigService: the storage config service :param storageConfigService: the storage config service
:param volumeInstance: the volume instance :param volumeInstance: the volume instance
:param volumeName: the volume Name :param volumeName: the volume Name
:param deviceId: the device ID of the volume :param deviceId: the device ID of the volume
:param storageGroupName: the name of the default SG
:param extraSpecs: extra specifications :param extraSpecs: extra specifications
:returns: int -- return code :returns: int -- return code
:raises: VolumeBackendAPIException :raises: VolumeBackendAPIException
@@ -3452,9 +3447,9 @@ class EMCVMAXCommon(object):
# Check if it is part of a storage group and delete it # Check if it is part of a storage group and delete it
# extra logic for case when volume is the last member. # 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, self.conn, controllerConfigurationService, volumeInstance,
volumeName, extraSpecs, None, 'noReset') volumeName, extraSpecs, None, False)
LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool " LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool "
"ConfigServic: %(service)s TheElement: %(vol_instance)s " "ConfigServic: %(service)s TheElement: %(vol_instance)s "
@@ -3472,23 +3467,9 @@ class EMCVMAXCommon(object):
# If we cannot successfully delete the volume, then we want to # If we cannot successfully delete the volume, then we want to
# return the volume to the default storage group, # return the volume to the default storage group,
# which should be the SG it previously belonged to. # which should be the SG it previously belonged to.
storageGroupInstanceName = self.utils.find_storage_masking_group( self.masking.return_volume_to_default_storage_group_v3(
self.conn, controllerConfigurationService, storageGroupName) self.conn, controllerConfigurationService,
volumeInstance, volumeName, extraSpecs)
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)
errorMessage = (_("Failed to delete volume %(volumeName)s.") % errorMessage = (_("Failed to delete volume %(volumeName)s.") %
{'volumeName': volumeName}) {'volumeName': volumeName})
@@ -3854,12 +3835,9 @@ class EMCVMAXCommon(object):
self.conn, storageSystem)) self.conn, storageSystem))
deviceId = targetInstance['DeviceID'] deviceId = targetInstance['DeviceID']
volumeName = targetInstance['Name'] volumeName = targetInstance['Name']
storageGroupName = self.utils.get_v3_storage_group_name(
extraSpecs[POOL], extraSpecs[SLO],
extraSpecs[WORKLOAD])
rc = self._delete_from_pool_v3( rc = self._delete_from_pool_v3(
storageConfigService, targetInstance, volumeName, storageConfigService, targetInstance, volumeName,
deviceId, storageGroupName, extraSpecs) deviceId, extraSpecs)
# Re-throw the exception. # Re-throw the exception.
raise raise

View File

@@ -519,34 +519,53 @@ class EMCVMAXMasking(object):
if self._is_volume_in_storage_group( if self._is_volume_in_storage_group(
conn, storageGroupInstanceName, conn, storageGroupInstanceName,
volumeInstance, sgGroupName): volumeInstance, sgGroupName):
LOG.debug( LOG.warning(_LW(
"Volume: %(volumeName)s is already part " "Volume: %(volumeName)s is already part "
"of storage group %(sgGroupName)s.", "of storage group %(sgGroupName)s."),
{'volumeName': volumeName, {'volumeName': volumeName,
'sgGroupName': sgGroupName}) 'sgGroupName': sgGroupName})
else: else:
self.add_volume_to_storage_group( msg = self._add_volume_to_sg_and_verify(
conn, controllerConfigService, conn, controllerConfigService, storageGroupInstanceName,
storageGroupInstanceName, volumeInstance, volumeName, volumeInstance, volumeName, sgGroupName,
sgGroupName, maskingViewDict['extraSpecs']) 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})
return msg 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( def _get_and_remove_from_storage_group_v2(
self, conn, controllerConfigService, volumeInstanceName, self, conn, controllerConfigService, volumeInstanceName,
volumeName, fastPolicyName, extraSpecs): volumeName, fastPolicyName, extraSpecs):
@@ -1747,14 +1766,11 @@ class EMCVMAXMasking(object):
def remove_and_reset_members( def remove_and_reset_members(
self, conn, controllerConfigService, volumeInstance, self, conn, controllerConfigService, volumeInstance,
volumeName, extraSpecs, connector=None, noReset=None): volumeName, extraSpecs, connector=None, reset=True):
"""Part of unmap device or rollback. """This is called on a delete, unmap device or rollback.
Removes volume from the Device Masking Group that belongs to a If the connector is not None get the associated SG and remove volume
Masking View. Check if fast policy is in the extra specs, if it isn't from the storage group, otherwise it is a VMAX3 deletion.
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.
:param conn: connection the the ecom server :param conn: connection the the ecom server
:param controllerConfigService: the controller configuration service :param controllerConfigService: the controller configuration service
@@ -1762,33 +1778,72 @@ class EMCVMAXMasking(object):
:param volumeName: the volume name :param volumeName: the volume name
:param extraSpecs: additional info :param extraSpecs: additional info
:param connector: optional :param connector: optional
:param noReset: optional, if none, then reset :param reset: reset, return to original SG (optional)
:returns: storageGroupInstanceName :returns: storageGroupInstanceName
""" """
fastPolicyName = extraSpecs.get(FASTPOLICY, None)
isV3 = extraSpecs[ISV3]
storageGroupInstanceName = None storageGroupInstanceName = None
if connector is not None: if connector is not None:
storageGroupInstanceName = self._get_sg_associated_with_connector( storageGroupInstanceName = self._get_sg_associated_with_connector(
conn, controllerConfigService, volumeInstance.path, conn, controllerConfigService, volumeInstance.path,
volumeName, connector) volumeName, connector)
if storageGroupInstanceName is None: if storageGroupInstanceName:
return None self._remove_volume_from_sg(
conn, controllerConfigService, storageGroupInstanceName,
volumeInstance, extraSpecs)
else: # Connector is None in V3 volume deletion case. else: # Connector is None in V3 volume deletion case.
storageGroupInstanceNames = ( self._cleanup_deletion_v3(
self.get_associated_masking_groups_from_device( conn, controllerConfigService, volumeInstance, extraSpecs)
conn, volumeInstance.path)) if reset:
if storageGroupInstanceNames: self._return_back_to_default_sg(
storageGroupInstanceName = storageGroupInstanceNames[0] conn, controllerConfigService, volumeInstance, volumeName,
else: extraSpecs)
return None
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) instance = conn.GetInstance(storageGroupInstanceName, LocalOnly=False)
storageGroupName = instance['ElementName'] storageGroupName = instance['ElementName']
volumeInstanceNames = self.get_devices_from_storage_group( volumeInstanceNames = self.get_devices_from_storage_group(
conn, storageGroupInstanceName) conn, storageGroupInstanceName)
storageSystemInstanceName = self.utils.find_storage_system(
conn, controllerConfigService)
numVolInStorageGroup = len(volumeInstanceNames) numVolInStorageGroup = len(volumeInstanceNames)
LOG.debug( LOG.debug(
@@ -1797,25 +1852,18 @@ class EMCVMAXMasking(object):
{'numVol': numVolInStorageGroup, {'numVol': numVolInStorageGroup,
'maskingGroup': storageGroupInstanceName}) 'maskingGroup': storageGroupInstanceName})
if not isV3:
isTieringPolicySupported, __ = (
self._get_tiering_info(conn, storageSystemInstanceName,
fastPolicyName))
if numVolInStorageGroup == 1: if numVolInStorageGroup == 1:
# Last volume in the storage group. # Last volume in the storage group.
self._last_vol_in_SG( self._last_vol_in_SG(
conn, controllerConfigService, storageGroupInstanceName, conn, controllerConfigService, storageGroupInstanceName,
storageGroupName, volumeInstance, volumeName, extraSpecs) storageGroupName, volumeInstance,
volumeInstance['ElementName'], extraSpecs)
else: else:
# Not the last volume so remove it from storage group in # Not the last volume so remove it from storage group
# the masking view.
self._multiple_vols_in_SG( self._multiple_vols_in_SG(
conn, controllerConfigService, storageGroupInstanceName, conn, controllerConfigService, storageGroupInstanceName,
storageGroupName, volumeInstance, volumeName, volumeInstance, volumeInstance['ElementName'],
numVolInStorageGroup, fastPolicyName, extraSpecs) numVolInStorageGroup, extraSpecs)
return storageGroupInstanceName
def _last_vol_in_SG( def _last_vol_in_SG(
self, conn, controllerConfigService, storageGroupInstanceName, self, conn, controllerConfigService, storageGroupInstanceName,
@@ -1881,29 +1929,20 @@ class EMCVMAXMasking(object):
def _multiple_vols_in_SG( def _multiple_vols_in_SG(
self, conn, controllerConfigService, storageGroupInstanceName, self, conn, controllerConfigService, storageGroupInstanceName,
storageGroupName, volumeInstance, volumeName, numVolsInSG, volumeInstance, volumeName, numVolsInSG, extraSpecs):
fastPolicyName, extraSpecs): """If the volume is not the last in the storage group
"""Necessary steps if the volume is not the last in the SG.
1. Remove the volume from the SG. Remove the volume from the SG.
2. Return the volume to default SG if necessary.
:param conn: the ecom connection :param conn: the ecom connection
:param controllerConfigService: storage system instance name :param controllerConfigService: storage system instance name
:param storageGroupInstanceName: the SG instance name :param storageGroupInstanceName: the SG instance name
:param storageGroupName: the Storage group name (String)
:param volumeInstance: the volume instance :param volumeInstance: the volume instance
:param volumeName: the volume name :param volumeName: the volume name
:param numVolsInSG: the number of volumes in the SG :param numVolsInSG: the number of volumes in the SG
:param fastPolicyName: the FAST policy name
:param extraSpecs: the extra specifications :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: " LOG.debug("Start: number of volumes in masking storage group: "
"%(numVol)d", {'numVol': numVolsInSG}) "%(numVol)d", {'numVol': numVolsInSG})
self.provision.remove_device_from_storage_group( self.provision.remove_device_from_storage_group(
@@ -1914,19 +1953,6 @@ class EMCVMAXMasking(object):
"RemoveMembers for volume %(volumeName)s completed " "RemoveMembers for volume %(volumeName)s completed "
"successfully.", {'volumeName': volumeName}) "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( volumeInstanceNames = self.get_devices_from_storage_group(
conn, storageGroupInstanceName) conn, storageGroupInstanceName)
LOG.debug( LOG.debug(
@@ -1939,10 +1965,6 @@ class EMCVMAXMasking(object):
volumeInstance, volumeName, extraSpecs): volumeInstance, volumeName, extraSpecs):
"""Delete the Masking view, the storage Group and the initiator group. """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 conn: connection the the ecom server
:param controllerConfigService: the controller configuration service :param controllerConfigService: the controller configuration service
:param mvInstanceName: masking view instance name :param mvInstanceName: masking view instance name
@@ -1978,56 +2000,49 @@ class EMCVMAXMasking(object):
storageSystemInstanceName['Name'], storageSystemInstanceName['Name'],
storageGroupInstanceName, extraSpecs) storageGroupInstanceName, extraSpecs)
self._cleanup_last_vol(
conn, controllerConfigService, storageGroupInstanceName,
storageGroupName, volumeInstance, volumeName,
storageSystemInstanceName, isTieringPolicySupported, 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.
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
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( self._remove_last_vol_and_delete_sg(
conn, controllerConfigService, storageGroupInstanceName, conn, controllerConfigService, storageGroupInstanceName,
storageGroupName, volumeInstance.path, volumeName, storageGroupName, volumeInstance.path, volumeName,
extraSpecs) extraSpecs)
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
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 volumeInstance: the volume Instance
:param volumeName: the volume name
:param extraSpecs: extra specs
"""
# Add it back to the default storage group. # Add it back to the default storage group.
if extraSpecs[ISV3]: if extraSpecs[ISV3]:
self._return_volume_to_default_storage_group_v3( self.return_volume_to_default_storage_group_v3(
conn, controllerConfigService, storageGroupName, conn, controllerConfigService,
volumeInstance, volumeName, storageSystemInstanceName, volumeInstance, volumeName, extraSpecs)
extraSpecs)
else: else:
# V2 if FAST POLICY enabled, move the volume to the default # V2 if FAST POLICY enabled, move the volume to the default
# SG. # SG.
fastPolicyName = extraSpecs.get(FASTPOLICY, None) 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: if fastPolicyName is not None and isTieringPolicySupported:
self._cleanup_tiering( self._cleanup_tiering(
conn, controllerConfigService, fastPolicyName, conn, controllerConfigService, fastPolicyName,
volumeInstance, volumeName, extraSpecs) 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( def _get_sg_associated_with_connector(
self, conn, controllerConfigService, volumeInstanceName, self, conn, controllerConfigService, volumeInstanceName,
@@ -2141,51 +2156,41 @@ class EMCVMAXMasking(object):
conn, tierPolicyServiceInstanceName, conn, tierPolicyServiceInstanceName,
storageGroupInstanceName, tierPolicyInstanceName, extraSpecs) storageGroupInstanceName, tierPolicyInstanceName, extraSpecs)
def _return_volume_to_default_storage_group_v3( def return_volume_to_default_storage_group_v3(
self, conn, controllerConfigService, storageGroupName, self, conn, controllerConfigurationService,
volumeInstance, volumeName, storageSystemInstanceName, volumeInstance, volumeName, extraSpecs):
extraSpecs):
"""Return volume to the default storage group in v3. """Return volume to the default storage group in v3.
:param conn: the ecom connection :param conn: the ecom connection
:param controllerConfigService: controller config service :param controllerConfigService: controller config service
:param storageGroupName: storage group name
:param volumeInstance: volumeInstance :param volumeInstance: volumeInstance
:param volumeName: the volume name :param volumeName: the volume name
:param storageSystemInstanceName: the storage system instance name
:param extraSpecs: additional info :param extraSpecs: additional info
:raises: VolumeBackendAPIException :raises: VolumeBackendAPIException
""" """
# First strip the shortHostname from the storage group name. storageGroupName = self.utils.get_v3_storage_group_name(
defaultStorageGroupName, shorthostName = ( extraSpecs[self.utils.POOL], extraSpecs[self.utils.SLO],
self.utils.strip_short_host_name(storageGroupName)) extraSpecs[self.utils.WORKLOAD])
storageGroupInstanceName = self.utils.find_storage_masking_group(
conn, controllerConfigurationService, storageGroupName)
# Check if host name exists which signifies detach operation. if not storageGroupInstanceName:
if shorthostName is not None: storageGroupInstanceName = (
# Populate maskingViewDict and storageGroupInstanceName. self.provisionv3.create_storage_group_v3(
maskingViewDict = {} conn, controllerConfigurationService, storageGroupName,
maskingViewDict['sgGroupName'] = defaultStorageGroupName extraSpecs[self.utils.POOL], extraSpecs[self.utils.SLO],
maskingViewDict['volumeInstance'] = volumeInstance extraSpecs[self.utils.WORKLOAD], extraSpecs))
maskingViewDict['volumeName'] = volumeName if not storageGroupInstanceName:
maskingViewDict['controllerConfigService'] = ( errorMessage = (_("Failed to create storage group "
controllerConfigService) "%(storageGroupName)s.") %
maskingViewDict['storageSystemName'] = ( {'storageGroupName': storageGroupName})
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})
LOG.error(errorMessage) LOG.error(errorMessage)
raise exception.VolumeBackendAPIException( raise exception.VolumeBackendAPIException(data=errorMessage)
data=errorMessage)
self._add_volume_to_sg_and_verify(
conn, controllerConfigurationService,
storageGroupInstanceName, volumeInstance, volumeName,
storageGroupName, extraSpecs)
def _cleanup_tiering( def _cleanup_tiering(
self, conn, controllerConfigService, fastPolicyName, self, conn, controllerConfigService, fastPolicyName,

View File

@@ -64,6 +64,9 @@ class EMCVMAXUtils(object):
This Utility class is for EMC volume drivers based on SMI-S. This Utility class is for EMC volume drivers based on SMI-S.
It supports VMAX arrays. It supports VMAX arrays.
""" """
SLO = 'storagetype:slo'
WORKLOAD = 'storagetype:workload'
POOL = 'storagetype:pool'
def __init__(self, prtcl): def __init__(self, prtcl):
if not pywbemAvailable: if not pywbemAvailable:
@@ -1528,16 +1531,6 @@ class EMCVMAXUtils(object):
'workload': workload}) 'workload': workload})
return storageGroupName 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): def _get_fast_settings_from_storage_group(self, storageGroupInstance):
"""Get the emc FAST setting from the storage group. """Get the emc FAST setting from the storage group.