result = self._enum_fcscsiendpoint()
elif ResultClass == 'CIM_TargetMaskingGroup':
result = self._assocnames_portgroup()
-
+ elif ResultClass == 'Symm_LunMaskingView':
+ result = self._enum_maskingView()
else:
result = self._default_assocnames(objectpath)
return result
portgroups.append(portgroup)
return portgroups
+ def _enum_maskingView(self):
+ maskingViews = []
+ maskingView = {}
+ maskingView['CreationClassName'] = 'Symm_LunMaskingView'
+ maskingView['ElementName'] = 'myMaskingView'
+ maskingViews.append(maskingView)
+ return maskingViews
+
def _default_enum(self):
names = []
name = {}
EMCVMAXMasking,
'_wrap_get_storage_group_from_volume',
return_value=None)
- @mock.patch.object(
- EMCVMAXCommon,
- '_wrap_find_device_number',
- return_value={'storagesystem': EMCVMAXCommonData.storage_system})
@mock.patch.object(
EMCVMAXUtils,
'find_storage_masking_group',
def test_map_new_masking_view_no_fast_success(self,
mock_check,
mock_storage_group,
- mock_wrap_device,
mock_wrap_group,
mock_volume_type):
self.driver.initialize_connection(self.data.test_volume,
return_value=None)
@mock.patch.object(
EMCVMAXCommon,
- '_wrap_find_device_number',
+ 'find_device_number',
return_value={'hostlunid': 1,
'storagesystem': EMCVMAXCommonData.storage_system})
@mock.patch.object(
return_value=None)
@mock.patch.object(
EMCVMAXCommon,
- '_wrap_find_device_number',
+ 'find_device_number',
return_value={'hostlunid': 1,
'storagesystem': EMCVMAXCommonData.storage_system})
@mock.patch.object(
return_value=None)
@mock.patch.object(
EMCVMAXCommon,
- '_wrap_find_device_number',
+ 'find_device_number',
return_value={'storagesystem': EMCVMAXCommonData.storage_system})
def test_map_no_fast_failed(self, mock_wrap_group, mock_wrap_device):
self.assertRaises(exception.VolumeBackendAPIException,
return_value=None)
@mock.patch.object(
EMCVMAXCommon,
- '_wrap_find_device_number',
+ 'find_device_number',
return_value={'hostlunid': 1,
'storagesystem': EMCVMAXCommonData.storage_system})
@mock.patch.object(
return_value=None)
@mock.patch.object(
EMCVMAXCommon,
- '_wrap_find_device_number',
+ 'find_device_number',
return_value={'storagesystem': EMCVMAXCommonData.storage_system})
def test_map_fast_failed(self, mock_wrap_group, mock_wrap_device):
self.assertRaises(exception.VolumeBackendAPIException,
driver.common.conn = FakeEcomConnection()
driver.zonemanager_lookup_service = None
self.driver = driver
+ self.driver.utils = EMCVMAXUtils(object)
+ self.driver.masking = EMCVMAXMasking('FC')
def create_fake_config_file_fast(self):
EMCVMAXMasking,
'get_masking_view_by_volume',
return_value=EMCVMAXCommonData.lunmaskctrl_name)
- def test_detach_fast_success(self, mock_volume_type, mock_maskingview):
+ @mock.patch.object(
+ EMCVMAXCommon,
+ 'get_masking_views_by_port_group',
+ return_value=[])
+ def test_detach_fast_success(self, mock_volume_type, mock_maskingview,
+ mock_mvs):
common = self.driver.common
common.get_target_wwns = mock.Mock(
return_value=EMCVMAXCommonData.target_wwns)
self.data.connector)
common.get_target_wwns.assert_called_once_with(
EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
-
- self.assertEqual(0, len(data['data']))
+ numTargetWwns = len(EMCVMAXCommonData.target_wwns)
+ self.assertEqual(numTargetWwns, len(data['data']))
@mock.patch.object(
volume_types,
self.data.test_ctxt, self.data.test_volume, self.data.new_type,
self.data.diff, self.data.test_host)
+ # Bug 1382641
+ def test_get_sg_associated_with_connector(self):
+ conn = self.fake_ecom_connection()
+ controllerConfigService = (
+ self.driver.utils.find_controller_configuration_service(
+ conn, self.data.storage_system))
+
+ mockSgInstanceName1 = {}
+ mockSgInstanceName1['CreationClassName'] = 'CIM_DeviceMaskingGroup'
+ mockSgInstanceName1['ElementName'] = 'OS_1382641_SG'
+ mockSgInstanceName2 = {}
+ mockSgInstanceName2['CreationClassName'] = 'CIM_DeviceMaskingGroup'
+ mockSgInstanceName2['ElementName'] = 'OS_not_1382641_SG'
+ self.driver.masking.get_associated_masking_groups_from_device = (
+ mock.Mock(return_value=[mockSgInstanceName1, mockSgInstanceName2]))
+
+ volumeInstanceName = (
+ conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
+ volumeName = "1382641-Vol"
+ sgInstanceName = self.driver.masking._get_sg_associated_with_connector(
+ conn, controllerConfigService, volumeInstanceName,
+ volumeName, self.data.connector)
+
+ (self.driver.masking.get_associated_masking_groups_from_device.
+ assert_called_once_with(conn, volumeInstanceName))
+
+ self.assertEqual(mockSgInstanceName1['ElementName'],
+ sgInstanceName['ElementName'])
+
def _cleanup(self):
bExists = os.path.exists(self.config_file_path)
if bExists:
% {'snapshotname': snapshotName,
'rc': rc})
- def _remove_members(
- self, controllerConfigService, volumeInstance, extraSpecs):
+ def _remove_members(self, controllerConfigService, volumeInstance,
+ extraSpecs, connector):
"""This method unmaps a volume from a host.
Removes volume from the Device Masking Group that belongs to
:param controllerConfigService: instance name of
ControllerConfigurationService
- :param volume: volume Object
+ :param volumeInstance: volume instanceObject
+ :param extraSpecs: the volume extra specs
+ :param connector: the connector object
"""
volumeName = volumeInstance['ElementName']
LOG.debug("Detaching volume %s" % volumeName)
fastPolicyName = extraSpecs[FASTPOLICY]
return self.masking.remove_and_reset_members(
self.conn, controllerConfigService, volumeInstance,
- fastPolicyName, volumeName)
+ fastPolicyName, volumeName, connector)
def _unmap_lun(self, volume, connector):
"""Unmaps a volume from the host.
LOG.info(_LI("Unmap volume: %(volume)s")
% {'volume': volumename})
- device_info = self.find_device_number(volume, connector)
+ device_info = self.find_device_number(volume)
device_number = device_info['hostlunid']
if device_number is None:
LOG.info(_LI("Volume %s is not mapped. No volume to unmap.")
% {'storage_system': storage_system})
raise exception.VolumeBackendAPIException(data=exception_message)
- self._remove_members(configservice, vol_instance, extraSpecs)
+ self._remove_members(configservice, vol_instance,
+ extraSpecs, connector)
def initialize_connection(self, volume, connector):
"""Initializes the connection and returns device and connection info.
LOG.info(_LI("Initialize connection: %(volume)s")
% {'volume': volumeName})
self.conn = self._get_ecom_connection()
- deviceInfoDict = self._wrap_find_device_number(volume, connector)
+ deviceInfoDict = self.find_device_number(volume)
if ('hostlunid' in deviceInfoDict and
deviceInfoDict['hostlunid'] is not None):
isSameHost = self._is_same_host(connector, deviceInfoDict)
self.conn, maskingViewDict)
# Find host lun id again after the volume is exported to the host.
- deviceInfoDict = self.find_device_number(volume, connector)
+ deviceInfoDict = self.find_device_number(volume)
if 'hostlunid' not in deviceInfoDict:
# Did not successfully attach to host,
# so a rollback for FAST is required.
return True
return False
- def _wrap_find_device_number(self, volume, connector):
- """Aid for unit testing
-
- :params volume: the volume Object
- :params connector: the connector Object
- :returns: deviceInfoDict
- """
- return self.find_device_number(volume, connector)
-
def terminate_connection(self, volume, connector):
"""Disallow connection from connector.
self.conn, storageSystemName))
# create a volume to the size of the
- # newSize - oldSize = additionalVolumeSize
+ # newSize - oldSize = additionalVolumeSize.
unboundVolumeInstance = self._create_and_get_unbound_volume(
self.conn, storageConfigService, volumeInstance.path,
additionalVolumeSize)
LOG.error(exceptionMessage)
raise exception.VolumeBackendAPIException(data=exceptionMessage)
- # add the new unbound volume to the original composite volume
+ # Add the new unbound volume to the original composite volume.
rc, modifiedVolumeDict = (
self._modify_and_get_composite_volume_instance(
self.conn, elementCompositionService, volumeInstance,
LOG.error(exceptionMessage)
raise exception.VolumeBackendAPIException(data=exceptionMessage)
- # check the occupied space of the new extended volume
+ # Check the occupied space of the new extended volume.
extendedVolumeInstance = self.utils.find_volume_instance(
self.conn, modifiedVolumeDict, volumeName)
extendedVolumeSize = self.utils.get_volume_size(
'volumeSize': extendedVolumeSize})
# If the requested size and the actual size don't
- # tally throw an exception
+ # tally throw an exception.
newSizeBits = self.utils.convert_gb_to_bits(newSize)
diffVolumeSize = self.utils.compare_size(
newSizeBits, extendedVolumeSize)
"%(emcConfigFileName)s ")
% {'arrayName': arrayName,
'emcConfigFileName': emcConfigFileName})
- # This value can be None
+ # This value can be None.
fastPolicyName = self.utils.parse_fast_policy_name_from_file(
emcConfigFileName)
if fastPolicyName is not None:
return True
def migrate_volume(self, ctxt, volume, host, new_type=None):
- """Migrate volume to another host
+ """Migrate volume to another host.
:param ctxt: context
:param volume: the volume object including the volume_type_id
def _migrate_volume(
self, volume, volumeInstance, targetPoolName,
targetFastPolicyName, sourceFastPolicyName, new_type=None):
- """Migrate volume to another host
+ """Migrate volume to another host.
:param volume: the volume object including the volume_type_id
:param volumeInstance: the volume instance
if moved is False and sourceFastPolicyName is not None:
# Return the volume to the default source fast policy storage
- # group because the migrate was unsuccessful
+ # group because the migrate was unsuccessful.
LOG.warn(_LW("Failed to migrate: %(volumeName)s from "
"default source storage group "
"for FAST policy: %(sourceFastPolicyName)s "
storageSystemName, sourceFastPolicyName,
volumeName)
else:
- # migrate was successful but still issues
+ # migrate was successful but still issues.
self._migrate_rollback(
self.conn, volumeInstance, storageSystemName,
sourceFastPolicyName, volumeName, sourcePoolInstanceName)
def _migrate_rollback(self, conn, volumeInstance,
storageSystemName, sourceFastPolicyName,
volumeName, sourcePoolInstanceName):
- """Full rollback
+ """Full rollback.
Failed on final step on adding migrated volume to new target
default storage group for the target FAST policy
def _migrate_cleanup(self, conn, volumeInstance,
storageSystemName, sourceFastPolicyName,
volumeName):
- """If the migrate fails, put volume back to source FAST SG
+ """If the migrate fails, put volume back to source FAST SG.
:param conn: connection info to ECOM
:param volumeInstance: the volume instance
self.utils.find_controller_configuration_service(
conn, storageSystemName))
- # Check to see what SG it is in
+ # Check to see what SG it is in.
assocStorageGroupInstanceName = (
self.utils.get_storage_group_from_volume(conn,
volumeInstance.path))
- # This is the SG it should be in
+ # This is the SG it should be in.
defaultStorageGroupInstanceName = (
self.fast.get_policy_default_storage_group(
conn, controllerConfigurationService, sourceFastPolicyName))
- # It is not in any storage group. Must add it to default source
+ # It is not in any storage group. Must add it to default source.
if assocStorageGroupInstanceName is None:
self.add_to_default_SG(conn, volumeInstance,
storageSystemName, sourceFastPolicyName,
volumeName)
- # It is in the incorrect storage group
+ # It is in the incorrect storage group.
if (assocStorageGroupInstanceName is not None and
(assocStorageGroupInstanceName !=
defaultStorageGroupInstanceName)):
def _migrate_volume_from(self, volume, volumeInstance,
targetPoolName, sourceFastPolicyName):
- """Check FAST policies and migrate from source pool
+ """Check FAST policies and migrate from source pool.
:param volume: the volume object including the volume_type_id
:param volumeInstance: the volume instance
% {'sourceFastPolicyName': sourceFastPolicyName})
# If the source volume is is FAST enabled it must first be removed
- # from the default storage group for that policy
+ # from the default storage group for that policy.
if sourceFastPolicyName is not None:
self.remove_from_default_SG(
self.conn, volumeInstance, storageSystemName,
sourceFastPolicyName, volumeName)
- # migrate from one pool to another
+ # Migrate from one pool to another.
storageRelocationService = self.utils.find_storage_relocation_service(
self.conn, storageSystemName)
self.conn, storageRelocationService, volumeInstance.path,
targetPoolInstanceName)
except Exception as e:
- # rollback by deleting the volume if adding the volume to the
- # default storage group were to fail
+ # Rollback by deleting the volume if adding the volume to the
+ # default storage group were to fail.
LOG.error(_LE("Exception: %s") % six.text_type(e))
exceptionMessage = (_("Error migrating volume: %(volumename)s. "
"to target pool %(targetPoolName)s. ")
LOG.error(exceptionMessage)
return falseRet
- # check that the volume is now migrated to the correct storage pool,
- # if it is terminate the migrate session
+ # Check that the volume is now migrated to the correct storage pool,
+ # if it is terminate the migrate session.
foundPoolInstanceName = self.utils.get_assoc_pool_from_volume(
self.conn, volumeInstance.path)
def remove_from_default_SG(
self, conn, volumeInstance, storageSystemName,
sourceFastPolicyName, volumeName):
- """For FAST, remove volume from default storage group
+ """For FAST, remove volume from default storage group.
:param conn: connection info to ECOM
:param volumeInstance: the volume instance
def add_to_default_SG(
self, conn, volumeInstance, storageSystemName,
targetFastPolicyName, volumeName):
- """For FAST, add volume to default storage group
+ """For FAST, add volume to default storage group.
:param conn: connection info to ECOM
:param volumeInstance: the volume instance
LOG.error(errorMessage)
return falseRet
- # get the pool from the source array and check that is is different
- # to the pool in the target array
+ # Get the pool from the source array and check that is is different
+ # to the pool in the target array.
assocPoolInstanceName = self.utils.get_assoc_pool_from_volume(
self.conn, volumeInstanceName)
assocPoolInstance = self.conn.GetInstance(
extraSpecs = self.utils.get_volumetype_extraspecs(volume)
configGroup = None
- # If there are no extra specs then the default case is assumed
+ # If there are no extra specs then the default case is assumed.
if extraSpecs:
configGroup = self.configuration.config_group
LOG.info(_LI("configGroup of current host: %s"), configGroup)
return extraSpecs, configurationFile
def _get_ecom_connection(self):
- """Get the ecom connection
+ """Get the ecom connection.
:returns: conn,the ecom connection
"""
def _find_storage_sync_sv_sv(self, snapshot, volume,
waitforsync=True):
- """Find the storage synchronized name
+ """Find the storage synchronized name.
:param snapshot: snapshot object
:param volume: volume object
"Storage Synchronized instance: %(sync)s."
% {'storage_system': storage_system,
'sync': foundsyncname})
- # Wait for SE_StorageSynchronized_SV_SV to be fully synced
+ # Wait for SE_StorageSynchronized_SV_SV to be fully synced.
if waitforsync:
self.utils.wait_for_sync(self.conn, foundsyncname)
'initiator': foundinitiatornames})
return foundinitiatornames
- def find_device_number(self, volume, connector):
+ def find_device_number(self, volume):
"""Given the volume dict find a device number.
Find a device number that a host can see for a volume.
:param volume: the volume dict
- :param connector: the connector dict
:returns: data, the data dict
"""
foundNumDeviceNumber = None
+ foundMaskingViewName = None
volumeName = volume['name']
volumeInstance = self._find_lun(volume)
storageSystemName = volumeInstance['SystemName']
% {'len': len(endpoints)})
for targetendpoint in endpoints:
wwn = targetendpoint['Name']
- # Add target wwn to the list if it is not already there
+ # Add target wwn to the list if it is not already there.
if not any(d == wwn for d in targetWwns):
targetWwns.append(wwn)
else:
instance = self.utils.get_existing_instance(
self.conn, hardwareIdInstance.path)
if instance is None:
- # hardwareId doesn't exist any more. Skip it.
+ # HardwareId doesn't exist any more. Skip it.
break
foundHardwareIdList.append(hardwareIdInstance.path)
break
CINDER_EMC_CONFIG_FILE_POSTFIX)
# The file saved in self.configuration may not be the correct one,
- # double check
+ # double check.
if configGroupName not in configurationFile:
configurationFile = (
CINDER_EMC_CONFIG_FILE_PREFIX + configGroupName +
data=exceptionMessage)
# Get the FAST policy from the file this value can be None if the
- # user doesn't want to associate with any FAST policy
+ # user doesn't want to associate with any FAST policy.
fastPolicyName = self.utils.parse_fast_policy_name_from_file(
configurationFile)
if fastPolicyName is not None:
'OS-' + shortHostName + '-' + poolName + '-' + protocol + '-SG')
maskingViewDict['maskingViewName'] = (
'OS-' + shortHostName + '-' + poolName + '-' + protocol + '-MV')
- # The portGroup is gotten from emc xml config file
+ # The portGroup is gotten from emc xml config file.
maskingViewDict['pgGroupName'] = (
self.utils.parse_file_to_get_port_group_name(
self.configuration.cinder_emc_config_file))
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
except Exception as e:
- # rollback by deleting the volume if adding the volume to the
- # default storage group were to fail
+ # Rollback by deleting the volume if adding the volume to the
+ # default storage group were to fail.
LOG.error(_LE("Exception: %s") % six.text_type(e))
errorMessage = (_(
"Rolling back %(volumeName)s by deleting it. ")
:param fastPolicyName: the FAST policy name(if it exists)
:returns: rc
"""
- # check if the source volume contains any meta devices
+ # Check if the source volume contains any meta devices.
metaHeadInstanceName = self.utils.get_volume_meta_head(
self.conn, sourceInstance.path)
return self._create_replica_and_delete_clone_relationship(
repServiceInstanceName, cloneVolume, sourceVolume,
sourceInstance, None, extraSpecs)
- else: # composite volume with meta device members
- # check if the meta members' capacity
+ else: # Composite volume with meta device members
+ # Check if the meta members' capacity.
metaMemberInstanceNames = (
self.utils.get_meta_members_of_composite_volume(
self.conn, metaHeadInstanceName))
"Capacity in bits: %(capInBits)lu ")
% {'capInBits': volumeSizeInbits,
'targetVol': baseTargetVolumeInstance.path})
- else: # create append volume
+ else: # Create append volume.
targetVolumeName = "MetaVol"
volume = {'size': int(self.utils.convert_bits_to_gbs(
volumeSizeInbits))}
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
- # append the new unbound volume to the
- # base target composite volume
+ # Append the new unbound volume to the
+ # base target composite volume.
baseTargetVolumeInstance = self.utils.find_volume_instance(
self.conn, baseVolumeDict, baseVolumeName)
elementCompositionService = (
syncInstanceName, storageSystemName = (
self._find_storage_sync_sv_sv(cloneVolume, sourceVolume))
- # Remove the Clone relationship so it can be used as a regular lun
- # 8 - Detach operation
+ # Remove the Clone relationship so it can be used as a regular lun.
+ # 8 - Detach operation.
rc, job = self.provision.delete_clone_relationship(
self.conn, repServiceInstanceName, syncInstanceName, cloneName,
sourceName)
- # if FAST enabled place clone volume or volume from snapshot to
- # default storage group
+ # If FAST enabled place clone volume or volume from snapshot to
+ # default storage group.
if extraSpecs[FASTPOLICY] is not None:
LOG.debug("Adding volume: %(cloneName)s to default storage group "
"for FAST policy: %(fastPolicyName)s "
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
- # check if the clone/snapshot volume already part of the default sg
+ # Check if the clone/snapshot volume already part of the default
+ # sg.
cloneInstance = self.utils.find_volume_instance(
self.conn, cloneDict, cloneName)
inDefaultSG = self.fast.is_volume_in_default_SG(
% {'volumename': volumeName,
'fastPolicyName': fastPolicyName})
LOG.warn(warnMessage)
- # check if it is part of another storage group
- self._pre_check_for_deletion(controllerConfigurationService,
- volumeInstance.path, volumeName)
+ # Check if it is part of another storage group.
+ self._remove_device_from_storage_group(
+ controllerConfigurationService, volumeInstance.path,
+ volumeName)
else:
- # check if volume is part of a storage group
- self._pre_check_for_deletion(controllerConfigurationService,
- volumeInstance.path, volumeName)
+ # Check if volume is part of a storage group.
+ self._remove_device_from_storage_group(
+ controllerConfigurationService,
+ volumeInstance.path, volumeName)
LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool "
"ConfigServic: %(service)s TheElement: %(vol_instance)s "
volumeName)
except Exception as e:
- # if we cannot successfully delete the volume then we want to
- # return the volume to the default storage group
+ # If we cannot successfully delete the volume then we want to
+ # return the volume to the default storage group.
if (fastPolicyName is not None and
defaultStorageGroupInstanceName is not None and
storageSystemName is not None):
return (rc, volumeName)
- def _pre_check_for_deletion(self, controllerConfigurationService,
- volumeInstanceName, volumeName):
- """Check is volume is part of a storage group prior to delete
+ def _remove_device_from_storage_group(
+ self, controllerConfigurationService, volumeInstanceName,
+ volumeName):
+ """Check is volume is part of a storage group prior to delete.
Log a warning if volume is part of storage group
:param volumeName: volume name (string)
"""
- storageGroupInstanceName = (
- self.masking.get_associated_masking_group_from_device(
+ storageGroupInstanceNames = (
+ self.masking.get_associated_masking_groups_from_device(
self.conn, volumeInstanceName))
- if storageGroupInstanceName is not None:
- LOG.warn(_LW("Pre check for deletion "
- "Volume: %(volumeName)s is part of a storage group "
- "Attempting removal "
- "from %(storageGroupInstanceName)s ")
- % {'volumeName': volumeName,
- 'storageGroupInstanceName': storageGroupInstanceName})
- self.provision.remove_device_from_storage_group(
- self.conn, controllerConfigurationService,
- storageGroupInstanceName,
- volumeInstanceName, volumeName)
+ if storageGroupInstanceNames:
+ LOG.warn(_LW(
+ "Pre check for deletion "
+ "Volume: %(volumeName)s is part of a storage group "
+ "Attempting removal from %(storageGroupInstanceNames)s"),
+ {'volumeName': volumeName,
+ 'storageGroupInstanceNames': storageGroupInstanceNames})
+ for storageGroupInstanceName in storageGroupInstanceNames:
+ self.provision.remove_device_from_storage_group(
+ self.conn, controllerConfigurationService,
+ storageGroupInstanceName,
+ volumeInstanceName, volumeName)
def _find_lunmasking_scsi_protocol_controller(self, storageSystemName,
connector):
self.conn, controllerInstanceName)
if instance is None:
# Skip this controller as it doesn't exist
- # any more
+ # any more.
pass
else:
foundControllerInstanceName = (
'connector': connector,
'ctrl': ctrl})
- # return 0 if masking view does not exist
+ # Return 0 if masking view does not exist.
if ctrl is None:
return 0
:returns: targetWwns, the target WWN list
"""
targetWwns = []
- mvInstanceName = self.get_masking_view_by_volume(volume)
- targetWwns = self.masking.get_target_wwns(self.conn, mvInstanceName)
- LOG.info(_LI("Target wwns in masking view %(maskingView)s: "
- "%(targetWwns)s"),
- {'maskingView': mvInstanceName,
- 'targetWwns': str(targetWwns)})
+ mvInstanceName = self.get_masking_view_by_volume(volume, connector)
+ if mvInstanceName is not None:
+ targetWwns = self.masking.get_target_wwns(
+ self.conn, mvInstanceName)
+ LOG.info(_LI("Target wwns in masking view %(maskingView)s: "
+ "%(targetWwns)s"),
+ {'maskingView': mvInstanceName,
+ 'targetWwns': str(targetWwns)})
return targetWwns
def get_port_group_from_masking_view(self, maskingViewInstanceName):
return self.masking.get_port_group_from_masking_view(
self.conn, maskingViewInstanceName)
- def get_masking_view_by_volume(self, volume):
- """Given volume, retrieve the masking view instance name.
+ def get_masking_view_by_volume(self, volume, connector):
+ """Given volume, retrieve the masking view instance name
:param volume: the volume
- :param mvInstanceName: masking view instance name
+ :param connector: the connector object
:returns maskingviewInstanceName
"""
- LOG.debug("Finding Masking View for volume %(volume)s"
- % {'volume': volume})
+ LOG.debug("Finding Masking View for volume %(volume)s",
+ {'volume': volume})
volumeInstance = self._find_lun(volume)
return self.masking.get_masking_view_by_volume(
- self.conn, volumeInstance)
+ self.conn, volumeInstance, connector)
def get_masking_views_by_port_group(self, portGroupInstanceName):
"""Given port group, retrieve the masking view instance name.
self.conn, storageSystemName)
# If FAST is intended to be used we must first check that the pool
- # is associated with the correct storage tier
+ # is associated with the correct storage tier.
if extraSpecs[FASTPOLICY] is not None:
foundPoolInstanceName = self.fast.get_pool_associated_to_policy(
self.conn, extraSpecs[FASTPOLICY], extraSpecs[ARRAY],
# Now that we have already checked that the pool is associated with
# the correct storage tier and the volume was successfully created
# add the volume to the default storage group created for
- # volumes in pools associated with this fast policy
+ # volumes in pools associated with this fast policy.
if extraSpecs[FASTPOLICY]:
LOG.info(_LI("Adding volume: %(volumeName)s to default storage "
"group for FAST policy: %(fastPolicyName)s ")
self.provision.add_members_to_masking_group(
conn, controllerConfigService, storageGroupInstanceName,
volumeInstance.path, volumeName)
- # check to see if the volume is in the storage group
+ # Check to see if the volume is in the storage group.
assocStorageGroupInstanceName = (
self.utils.get_storage_group_from_volume(conn,
volumeInstance.path))
tierPolicyServiceInstanceName = self.utils.get_tier_policy_service(
conn, storageSystemInstanceName)
- # get the fast policy instance name
+ # Get the fast policy instance name.
tierPolicyRuleInstanceName = self._get_service_level_tier_policy(
conn, tierPolicyServiceInstanceName, fastPolicyName)
if tierPolicyRuleInstanceName is None:
LOG.error(exceptionMessage)
return failedRet
- # now associate it with a FAST policy
+ # Now associate it with a FAST policy.
self.add_storage_group_to_tier_policy_rule(
conn, tierPolicyServiceInstanceName,
defaultStorageGroupInstanceName, tierPolicyRuleInstanceName,
:param storageGroupName: the storage group name (String)
:param fastPolicyName: the fast policy name (String)
"""
- # 5 is ("Add InElements to Policy")
+ # 5 is ("Add InElements to Policy").
modificationType = '5'
rc, job = conn.InvokeMethod(
conn, controllerConfigService)
tierPolicyServiceInstanceName = self.utils.get_tier_policy_service(
conn, storageSystemInstanceName)
- # get the fast policy instance name
+ # Get the fast policy instance name.
tierPolicyRuleInstanceName = self._get_service_level_tier_policy(
conn, tierPolicyServiceInstanceName, fastPolicyName)
if tierPolicyRuleInstanceName is None:
% {'storageGroupInstanceName': storageGroupInstanceName,
'tierPolicyRuleInstanceName': tierPolicyRuleInstanceName})
- # Associate the new storage group with the existing fast policy
+ # Associate the new storage group with the existing fast policy.
try:
self.add_storage_group_to_tier_policy_rule(
conn, tierPolicyServiceInstanceName,
LOG.error(errorMessage)
return failedRet
- # check that the storage group has been associated with with the
- # tier policy rule
+ # Check that the storage group has been associated with with the
+ # tier policy rule.
assocTierPolicyInstanceName = (
self.get_associated_tier_policy_from_storage_group(
conn, storageGroupInstanceName))
tierPolicyRuleInstanceName = self._get_service_level_tier_policy(
conn, tierPolicyServiceInstanceName, fastPolicyName)
- # Get the associated storage tiers from the tier policy rule
+ # Get the associated storage tiers from the tier policy rule.
storageTierInstanceNames = self.get_associated_tier_from_tier_policy(
conn, tierPolicyRuleInstanceName)
- # For each gold storage tier get the associated pools
+ # For each gold storage tier get the associated pools.
foundPoolInstanceName = None
for storageTierInstanceName in storageTierInstanceNames:
assocStoragePoolInstanceNames = (
import six
from cinder import context
-from cinder.i18n import _LI
+from cinder.i18n import _LI, _LW
from cinder.openstack.common import log as logging
from cinder.volume import driver
from cinder.volume.drivers.emc import emc_vmax_common
LOG.info(_LI("Start FC detach process for volume: %(volume)s")
% {'volume': volume['name']})
- target_wwns, init_targ_map = self._build_initiator_target_map(
- storage_system, volume, connector)
-
- mvInstanceName = self.common.get_masking_view_by_volume(volume)
- portGroupInstanceName = self.common.get_port_group_from_masking_view(
- mvInstanceName)
-
- LOG.info(_LI("Found port group: %(portGroup)s "
- "in masking view %(maskingView)s"),
- {'portGroup': portGroupInstanceName,
- 'maskingView': mvInstanceName})
-
- self.common.terminate_connection(volume, connector)
-
- LOG.info(_LI("Looking for masking views still associated with"
- "Port Group %s"), portGroupInstanceName)
- mvInstances = self.common.get_masking_views_by_port_group(
- portGroupInstanceName)
- if len(mvInstances) > 0:
- LOG.debug("Found %(numViews)lu maskingviews."
- % {'numViews': len(mvInstances)})
- data = {'driver_volume_type': 'fibre_channel',
- 'data': {}}
- else: # no views found
- LOG.debug("No Masking Views were found. Deleting zone.")
- data = {'driver_volume_type': 'fibre_channel',
- 'data': {'target_wwn': target_wwns,
- 'initiator_target_map': init_targ_map}}
-
- LOG.debug("Return FC data for zone removal: %(data)s."
- % {'data': data})
-
+ mvInstanceName = self.common.get_masking_view_by_volume(
+ volume, connector)
+ data = {'driver_volume_type': 'fibre_channel',
+ 'data': {}}
+ if mvInstanceName is not None:
+ portGroupInstanceName = (
+ self.common.get_port_group_from_masking_view(
+ mvInstanceName))
+
+ LOG.info(_LI("Found port group: %(portGroup)s "
+ "in masking view %(maskingView)s"),
+ {'portGroup': portGroupInstanceName,
+ 'maskingView': mvInstanceName})
+
+ self.common.terminate_connection(volume, connector)
+
+ LOG.debug("Looking for masking views still associated with "
+ "Port Group %s", portGroupInstanceName)
+ mvInstances = self.common.get_masking_views_by_port_group(
+ portGroupInstanceName)
+ if len(mvInstances) > 0:
+ LOG.debug("Found %(numViews)lu MaskingViews.",
+ {'numViews': len(mvInstances)})
+ else: # No views found.
+ target_wwns, init_targ_map = self._build_initiator_target_map(
+ storage_system, volume, connector)
+ LOG.debug("No MaskingViews were found. Deleting zone.")
+ data = {'driver_volume_type': 'fibre_channel',
+ 'data': {'target_wwn': target_wwns,
+ 'initiator_target_map': init_targ_map}}
+
+ LOG.debug("Return FC data for zone removal: %(data)s.",
+ {'data': data})
+ else:
+ LOG.warn(_LW("Volume %(volume)s is not in any masking view."),
+ {'volume': volume['name']})
return data
def _build_initiator_target_map(self, storage_system, volume, connector):
target_wwns.extend(map_d['target_port_wwn_list'])
for initiator in map_d['initiator_port_wwn_list']:
init_targ_map[initiator] = map_d['target_port_wwn_list']
- else: # no lookup service, pre-zoned case
+ else: # No lookup service, pre-zoned case.
target_wwns = self.common.get_target_wwns(storage_system,
connector)
for initiator in initiator_wwns:
LOG.debug("ISCSI Discovery: Found %s" % (location))
properties['target_discovered'] = True
- device_info = self.common.find_device_number(volume, connector)
+ device_info = self.common.find_device_number(volume)
if device_info is None or device_info['hostlunid'] is None:
exception_message = (_("Cannot find device number for volume "
# We must make sure that volume is returned to default storage
# group if anything goes wrong.
fastPolicyName = maskingViewDict['fastPolicy']
- # If FAST is enabled remove the volume from the default SG
+ # If FAST is enabled remove the volume from the default SG.
if fastPolicyName is not None:
defaultStorageGroupInstanceName = (
self._get_and_remove_from_storage_group_v2(
self._get_storage_group_instance_name(
conn, maskingViewDict, storageGroupInstanceName))
if storageGroupInstanceName is None:
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Cannot get or create a storage group: %(sgGroupName)s"
" for volume %(volumeName)s ") %
conn, maskingViewInstanceName))
if sgFromMvInstanceName is None:
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Cannot get storage group: %(sgGroupName)s "
"from masking view %(maskingViewInstanceName)s.") %
portGroupInstanceName = self._get_port_group_instance_name(
conn, controllerConfigService, pgGroupName)
if portGroupInstanceName is None:
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Cannot get port group: %(pgGroupName)s.") %
{'pgGroupName': pgGroupName})
conn, controllerConfigService, igGroupName, connector,
storageSystemName))
if initiatorGroupInstanceName is None:
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Cannot get or create initiator group: "
"%(igGroupName)s.") %
if not self._verify_initiator_group_from_masking_view(
conn, controllerConfigService, maskingViewName,
connector, storageSystemName, igGroupName):
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Unable to verify initiator group: %(igGroupName)s "
"in masking view %(maskingViewName)s.") %
storageGroupInstanceName, portGroupInstanceName,
initiatorGroupInstanceName))
if maskingViewInstanceName is None:
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
- "Cannot create masking view: %(maskingViewName)s. ") %
+ "Cannot create masking view: %(maskingViewName)s.") %
{'maskingViewName': maskingViewName})
LOG.error(msg)
if not self._is_volume_in_storage_group(
conn, storageGroupInstanceName,
volumeInstance):
- # This may be used in exception hence _ instead of _LE
+ # This may be used in exception hence _ instead of _LE.
msg = (_(
"Volume: %(volumeName)s was not added "
"to storage group %(sgGroupName)s.") %
break
if foundMaskingViewInstanceName is not None:
- # now check that is has not been deleted
+ # Now check that is has not been deleted.
instance = self.utils.get_existing_instance(
conn, foundMaskingViewInstanceName)
if instance is None:
conn, controllerConfigService, initiatorNames)
# If you cannot find an initiatorGroup that matches the connector
- # info create a new initiatorGroup
+ # info create a new initiatorGroup.
if foundInitiatorGroupInstanceName is None:
- # check that our connector information matches the
- # hardwareId(s) on the symm
+ # Check that our connector information matches the
+ # hardwareId(s) on the symm.
storageHardwareIDInstanceNames = (
self._get_storage_hardware_id_instance_names(
conn, initiatorNames, storageSystemName))
return foundInitiatorGroupInstanceName
def _find_initiator_names(self, conn, connector):
- """check the connector object for initiators(ISCSI) or wwpns(FC).
+ """Check the connector object for initiators(ISCSI) or wwpns(FC).
:param conn: the connection to the ecom
:param connector: the connector object
return foundHardwardIDsInstanceNames
def _get_initiator_group_from_job(self, conn, job):
- """After creating an new initiator group find it and return it
+ """After creating an new initiator group find it and return it.
:param conn: the connection to the ecom server
:param job: the create initiator group job
return rc, job
def find_new_masking_view(self, conn, jobDict):
- """Find the newly created volume
+ """Find the newly created volume.
:param conn: the connection to the ecom server
:param jobDict: the job tuple
self, conn, controllerConfigService, maskingViewName,
storageGroupInstanceName, portGroupInstanceName,
initiatorGroupInstanceName):
- """Gets the masking view instance name
+ """Gets the masking view instance name.
:param conn: the connection to the ecom server
:param controllerConfigService: the controller configuration server
foundStorageGroupInstanceName = (
self.utils.get_storage_group_from_volume(
conn, rollbackDict['volumeInstance'].path))
- # volume is not associated with any storage group so add it back
- # to the default
+ # Volume is not associated with any storage group so add it back
+ # to the default.
if len(foundStorageGroupInstanceName) == 0:
LOG.warning(_LW(
"No storage group found. "
{'foundStorageGroupInstanceName':
foundStorageGroupInstanceName})
- # check the name see is it the default storage group or another
+ # Check the name, see is it the default storage group
+ # or another.
if (foundStorageGroupInstanceName !=
rollbackDict['defaultStorageGroupInstanceName']):
- # remove it from its current masking view and return it
- # to its default masking view if fast is enabled
+ # Remove it from its current masking view and return it
+ # to its default masking view if fast is enabled.
self.remove_and_reset_members(
conn,
rollbackDict['controllerConfigService'],
def _create_initiator_Group(
self, conn, controllerConfigService, igGroupName,
hardwareIdinstanceNames):
- """Create a new initiator group
+ """Create a new initiator group.
Given a list of hardwareId Instance name create a new
initiator group
def _get_port_group_from_masking_view(
self, conn, maskingViewName, storageSystemName):
- """Given the masking view name get the port group from it
+ """Given the masking view name get the port group from it.
:param conn: connection the the ecom server
:param maskingViewName: the name of the masking view
def _delete_masking_view(
self, conn, controllerConfigService, maskingViewName,
maskingViewInstanceName):
- """Delete a masking view
+ """Delete a masking view.
:param conn: connection the ecom server
:param controllerConfigService: the controller configuration service
def get_masking_view_from_storage_group(
self, conn, storageGroupInstanceName):
- """Get the associated maskingview instance name
+ """Get the associated maskingview instance name.
Given storage group instance name, get the associated masking
view instance name
self, conn, controllerConfigService, storageGroupInstanceName,
volumeInstance, volumeName, sgGroupName, fastPolicyName,
storageSystemName=None):
- """Add a volume to an existing storage group
+ """Add a volume to an existing storage group.
:param conn: connection to ecom server
:param controllerConfigService: the controller configuration service
% {'length': len(assocVolumeInstanceNames),
'volumeName': volumeName})
- # required for unit tests
+ # Required for unit tests.
emptyStorageGroupInstanceName = (
self._wrap_get_storage_group_from_volume(conn, volumeInstanceName))
def get_devices_from_storage_group(
self, conn, storageGroupInstanceName):
- """Get the associated volume Instance names
+ """Get the associated volume Instance names.
Given the storage group instance name get the associated volume
Instance names
return volumeInstanceNames
- def get_associated_masking_group_from_device(
+ def get_associated_masking_groups_from_device(
self, conn, volumeInstanceName):
+ """Get the associated storage groups from the volume Instance name.
+
+ Given the volume instance name get the associated storage group
+ instance names.
+
+ :param conn: connection the the ecom server
+ :param volumeInstanceName: the volume instance name
+ :returns: list of storage group instance names
+ """
maskingGroupInstanceNames = conn.AssociatorNames(
volumeInstanceName,
ResultClass='CIM_DeviceMaskingGroup',
AssocClass='CIM_OrderedMemberOfCollection')
if len(maskingGroupInstanceNames) > 0:
- return maskingGroupInstanceNames[0]
+ return maskingGroupInstanceNames
else:
+ LOG.info(_LI("Volume %(volumeName)s not in any storage group."),
+ {'volumeName': volumeInstanceName})
return None
def remove_and_reset_members(
self, conn, controllerConfigService, volumeInstance,
- fastPolicyName, volumeName):
+ fastPolicyName, volumeName, connector=None):
"""Part of unmap device or rollback.
Removes volume from the Device Masking Group that belongs to a
:param volumeInstance: the volume Instance
:param fastPolicyName: the fast policy name (if it exists)
:param volumeName: the volume name
- :returns: list volumeInstanceNames list of volume instance names
+ :param connector: the connector object
+ :returns: storage group instance name
"""
- rc = -1
- maskingGroupInstanceName = (
- self.get_associated_masking_group_from_device(
- conn, volumeInstance.path))
+ 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
+ else:
+ storageGroupInstanceNames = (
+ self.get_associated_masking_groups_from_device(
+ conn, volumeInstance.path))
+ if storageGroupInstanceNames:
+ storageGroupInstanceName = storageGroupInstanceNames[0]
+ else:
+ return None
volumeInstanceNames = self.get_devices_from_storage_group(
- conn, maskingGroupInstanceName)
+ conn, storageGroupInstanceName)
storageSystemInstanceName = self.utils.find_storage_system(
conn, controllerConfigService)
- isTieringPolicySupported = False
- if fastPolicyName is not None:
- tierPolicyServiceInstanceName = self.utils.get_tier_policy_service(
- conn, storageSystemInstanceName)
-
- isTieringPolicySupported = self.fast.is_tiering_policy_enabled(
- conn, tierPolicyServiceInstanceName)
- LOG.debug(
- "FAST policy enabled on %(storageSystem)s: %(isSupported)s"
- % {'storageSystem': storageSystemInstanceName,
- 'isSupported': isTieringPolicySupported})
-
numVolInMaskingView = len(volumeInstanceNames)
LOG.debug(
- "There are %(numVol)d volumes in the masking view %(maskingGroup)s"
- % {'numVol': numVolInMaskingView,
- 'maskingGroup': maskingGroupInstanceName})
-
- if numVolInMaskingView == 1: # last volume in the storage group
- # delete masking view
- mvInstanceName = self.get_masking_view_from_storage_group(
- conn, maskingGroupInstanceName)
- LOG.debug(
- "Last volume in the storage group, deleting masking view "
- "%(mvInstanceName)s"
- % {'mvInstanceName': mvInstanceName})
- conn.DeleteInstance(mvInstanceName)
-
- # disassociate storage group from FAST policy
- if fastPolicyName is not None and isTieringPolicySupported is True:
- tierPolicyInstanceName = self.fast.get_tier_policy_by_name(
- conn, storageSystemInstanceName['Name'], fastPolicyName)
-
- LOG.info(_LI(
- "policy:%(policy)s, policy service:%(service)s, "
- "masking group=%(maskingGroup)s")
- % {'policy': tierPolicyInstanceName,
- 'service': tierPolicyServiceInstanceName,
- 'maskingGroup': maskingGroupInstanceName})
-
- self.fast.delete_storage_group_from_tier_policy_rule(
- conn, tierPolicyServiceInstanceName,
- maskingGroupInstanceName, tierPolicyInstanceName)
-
- rc = self.provision.remove_device_from_storage_group(
- conn, controllerConfigService, maskingGroupInstanceName,
+ "There are %(numVol)d volumes in the storage group "
+ "%(maskingGroup)s",
+ {'numVol': numVolInMaskingView,
+ 'maskingGroup': storageGroupInstanceName})
+ isTieringPolicySupported, tierPolicyServiceInstanceName = (
+ self._get_tiering_info(conn, storageSystemInstanceName,
+ fastPolicyName))
+ if numVolInMaskingView == 1:
+ # Last volume in the storage group.
+ self._last_volume_delete_masking_view(
+ conn, storageGroupInstanceName)
+ self._get_and_remove_rule_association(
+ conn, fastPolicyName,
+ isTieringPolicySupported,
+ tierPolicyServiceInstanceName,
+ storageSystemInstanceName['name'],
+ storageGroupInstanceName)
+
+ self.provision.remove_device_from_storage_group(
+ conn, controllerConfigService, storageGroupInstanceName,
volumeInstance.path, volumeName)
LOG.debug(
- "Remove the last volume %(volumeName)s completed successfully."
- % {'volumeName': volumeName})
+ "Remove the last volume %(volumeName)s completed "
+ "successfully.",
+ {'volumeName': volumeName})
- # Delete storage group
- conn.DeleteInstance(maskingGroupInstanceName)
+ # Delete storage group.
+ conn.DeleteInstance(storageGroupInstanceName)
if isTieringPolicySupported:
self._cleanup_tiering(
conn, controllerConfigService, fastPolicyName,
volumeInstance, volumeName)
else:
- # not the last volume
+ # Not the last volume so remove it from storage group in
+ # the masking view.
LOG.debug("start: number of volumes in masking storage group: "
- "%(numVol)d" % {'numVol': len(volumeInstanceNames)})
- rc = self.provision.remove_device_from_storage_group(
- conn, controllerConfigService, maskingGroupInstanceName,
+ "%(numVol)d", {'numVol': len(volumeInstanceNames)})
+ self.provision.remove_device_from_storage_group(
+ conn, controllerConfigService, storageGroupInstanceName,
volumeInstance.path, volumeName)
LOG.debug(
"RemoveMembers for volume %(volumeName)s completed "
- "successfully." % {'volumeName': volumeName})
-
- # if FAST POLICY enabled, move the volume to the default SG
+ "successfully.", {'volumeName': volumeName})
+ # 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)
- # validation
volumeInstanceNames = self.get_devices_from_storage_group(
- conn, maskingGroupInstanceName)
+ conn, storageGroupInstanceName)
LOG.debug(
- "end: number of volumes in masking storage group: %(numVol)d"
- % {'numVol': len(volumeInstanceNames)})
+ "end: number of volumes in masking storage group: %(numVol)d",
+ {'numVol': len(volumeInstanceNames)})
- return rc
+ return storageGroupInstanceName
def _cleanup_tiering(
self, conn, controllerConfigService, fastPolicyName,
volumeInstance, volumeName):
- """Cleanup tiering
+ """Clean up tiering.
:param conn: the ecom connection
:param controllerConfigService: the controller configuration service
self.fast.add_volume_to_default_storage_group_for_fast_policy(
conn, controllerConfigService, volumeInstance, volumeName,
fastPolicyName))
- # check default storage group number of volumes
+ # Check default storage group number of volumes.
volumeInstanceNames = self.get_devices_from_storage_group(
conn, defaultStorageGroupInstanceName)
LOG.debug(
targetWwns.append(targetPortInstanceName['Name'])
return targetWwns
- def get_masking_view_by_volume(self, conn, volumeInstance):
+ def get_masking_view_by_volume(self, conn, volumeInstance, connector):
"""Given volume, retrieve the masking view instance name.
- :param volume: the volume instance
- :param mvInstanceName: masking view instance name
+ :param volumeInstance: the volume instance
+ :param connector: the connector object
+ :returns mvInstanceName: masking view instance name
"""
- sgInstanceName = self.get_associated_masking_group_from_device(
- conn, volumeInstance.path)
- mvInstanceName = self.get_masking_view_from_storage_group(
- conn, sgInstanceName)
- LOG.debug("Found Masking View %(mv)s: " % {'mv': mvInstanceName})
+
+ storageSystemName = volumeInstance['SystemName']
+ controllerConfigService = (
+ self.utils.find_controller_configuration_service(
+ conn, storageSystemName))
+ volumeName = volumeInstance['ElementName']
+ mvInstanceName = (
+ self._get_sg_or_mv_associated_with_initiator(
+ conn, controllerConfigService, volumeInstance.path,
+ volumeName, connector, False))
return mvInstanceName
def get_masking_views_by_port_group(self, conn, portGroupInstanceName):
else:
LOG.warning(_LW("No port group found in masking view %(mv)s"),
{'mv': maskingViewInstanceName})
+
+ def _get_sg_associated_with_connector(
+ self, conn, controllerConfigService, volumeInstanceName,
+ volumeName, connector):
+ """Get storage group associated with connector.
+
+ If the connector gets passed then extra logic required to
+ get storage group.
+
+ :param conn: the ecom connection
+ :param controllerConfigService: storage system instance name
+ :param volumeInstanceName
+ :param volumeName
+ :param connector
+ :returns: storageGroupInstanceName(can be None)
+ """
+ return self._get_sg_or_mv_associated_with_initiator(
+ conn, controllerConfigService, volumeInstanceName,
+ volumeName, connector, True)
+
+ def _get_tiering_info(
+ self, conn, storageSystemInstanceName, fastPolicyName):
+ """Get tiering specifics.
+
+ :param conn: the ecom connection
+ :param storageSystemInstanceName: storage system instance name
+ :param fastPolicyName
+
+ :returns: isTieringPolicySupported, tierPolicyServiceInstanceName
+
+ """
+ isTieringPolicySupported = False
+ tierPolicyServiceInstanceName = None
+ if fastPolicyName is not None:
+ tierPolicyServiceInstanceName = self.utils.get_tier_policy_service(
+ conn, storageSystemInstanceName)
+
+ isTieringPolicySupported = self.fast.is_tiering_policy_enabled(
+ conn, tierPolicyServiceInstanceName)
+ LOG.debug(
+ "FAST policy enabled on %(storageSystem)s: %(isSupported)s",
+ {'storageSystem': storageSystemInstanceName,
+ 'isSupported': isTieringPolicySupported})
+
+ return isTieringPolicySupported, tierPolicyServiceInstanceName
+
+ def _last_volume_delete_masking_view(
+ self, conn, storageGroupInstanceName):
+ """Delete the masking view.
+
+ delete the masking view if the volume is the last one in the
+ storage group
+
+ :param conn: the ecom connection
+ :param storageGroupInstanceName: storage group instance name
+ """
+ # Delete masking view.
+ mvInstanceName = self.get_masking_view_from_storage_group(
+ conn, storageGroupInstanceName)
+ if mvInstanceName is not None:
+ LOG.debug(
+ "Last volume in the storage group, deleting masking view "
+ "%(mvInstanceName)s",
+ {'mvInstanceName': mvInstanceName})
+ conn.DeleteInstance(mvInstanceName)
+
+ def _get_and_remove_rule_association(
+ self, conn, fastPolicyName, isTieringPolicySupported,
+ tierPolicyServiceInstanceName, storageSystemName,
+ storageGroupInstanceName):
+ """Remove the storage group from the policy rule.
+
+ :param conn: the ecom connection
+ :param isTieringPolicySupported: boolean
+ :param tierPolicyServiceInstanceName: the tier policy instance name
+ :param storageSystemName: storage system name
+ :param storageGroupInstanceName: the storage group instance name
+ """
+ # Disassociate storage group from FAST policy.
+ if fastPolicyName is not None and isTieringPolicySupported is True:
+ tierPolicyInstanceName = self.fast.get_tier_policy_by_name(
+ conn, storageSystemName, fastPolicyName)
+
+ LOG.info(_LI(
+ "policy:%(policy)s, policy service:%(service)s, "
+ "masking group=%(maskingGroup)s"),
+ {'policy': tierPolicyInstanceName,
+ 'service': tierPolicyServiceInstanceName,
+ 'maskingGroup': storageGroupInstanceName})
+
+ self.fast.delete_storage_group_from_tier_policy_rule(
+ conn, tierPolicyServiceInstanceName,
+ storageGroupInstanceName, tierPolicyInstanceName)
+
+ def get_initiator_group_from_masking_view(
+ self, conn, maskingViewInstanceName):
+ """Get initiator group in a masking view.
+
+ :param maskingViewInstanceName: masking view instance name
+ :returns: initiatorGroupInstanceName or None if it is not found
+ """
+ initiatorGroupInstanceNames = conn.AssociatorNames(
+ maskingViewInstanceName, ResultClass='SE_InitiatorMaskingGroup')
+ if len(initiatorGroupInstanceNames) > 0:
+ LOG.debug("Found initiator group %(pg)s in masking view %(mv)s.",
+ {'pg': initiatorGroupInstanceNames[0],
+ 'mv': maskingViewInstanceName})
+ return initiatorGroupInstanceNames[0]
+ else:
+ LOG.warn(_LW("No port group found in masking view %(mv)s."),
+ {'mv': maskingViewInstanceName})
+
+ def _get_sg_or_mv_associated_with_initiator(
+ self, conn, controllerConfigService, volumeInstanceName,
+ volumeName, connector, getSG=True):
+ """Get storage group or masking view associated with connector.
+
+ If the connector gets passed then extra logic required to
+ get storage group.
+
+ :param conn: the ecom connection
+ :param controllerConfigService: storage system instance name
+ :param volumeInstanceName - volume instance name
+ :param volumeName - volume element name
+ :param connector - the connector object
+ :param getSG - True if to get storage group; otherwise get masking
+ :returns: foundInstanceName(can be None)
+ """
+ foundInstanceName = None
+ initiatorNames = self._find_initiator_names(conn, connector)
+ igInstanceNameFromConnector = self._find_initiator_masking_group(
+ conn, controllerConfigService, initiatorNames)
+ # Device can be shared by multi-SGs in a multi-host attach case.
+ storageGroupInstanceNames = (
+ self.get_associated_masking_groups_from_device(
+ conn, volumeInstanceName))
+ LOG.debug("Found storage groups volume "
+ "%(volumeName)s is in: %(storageGroups)s",
+ {'volumeName': volumeName,
+ 'storageGroups': storageGroupInstanceNames})
+ if storageGroupInstanceNames: # not empty
+ # Get the SG by IGs.
+ for sgInstanceName in storageGroupInstanceNames:
+ # Get maskingview from storage group.
+ mvInstanceName = self.get_masking_view_from_storage_group(
+ conn, sgInstanceName)
+ LOG.debug("Found masking view associated with SG "
+ "%(storageGroup)s: %(maskingview)s",
+ {'maskingview': mvInstanceName,
+ 'storageGroup': sgInstanceName})
+ # Get initiator group from masking view.
+ igInstanceName = (
+ self.get_initiator_group_from_masking_view(
+ conn, mvInstanceName))
+ LOG.debug("Initiator Group in masking view %(ig)s: "
+ "IG associated with connector%(igFromConnector)s",
+ {'ig': igInstanceName,
+ 'igFromConnector': igInstanceNameFromConnector})
+ if igInstanceName == igInstanceNameFromConnector:
+ if getSG is True:
+ foundInstanceName = sgInstanceName
+ LOG.debug("Found the storage group associated with "
+ "initiator %(initiator)s: %(storageGroup)s",
+ {'initiator': initiatorNames,
+ 'storageGroup': foundInstanceName})
+ else:
+ foundInstanceName = mvInstanceName
+ LOG.debug("Found the masking view associated with "
+ "initiator %(initiator)s: %(maskingview)s.",
+ {'initiator': initiatorNames,
+ 'maskingview': foundInstanceName})
+
+ break
+ return foundInstanceName
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
- # Find the newly created volume
+ # Find the newly created volume.
volumeDict = self.get_volume_dict_from_job(conn, job['Job'])
return volumeDict, rc
return rc, job
def get_target_endpoints(self, conn, storageHardwareService, hardwareId):
- """Given the hardwareId get the
+ """Given the hardwareId, get the target end points.
:param conn: the connection to the ecom server
:param storageHardwareService: the storage HardwareId Service
self.protocol = prtcl
def find_storage_configuration_service(self, conn, storageSystemName):
- """Given the storage system name, get the storage configuration service
+ """Given the storage system name, get the storage configuration service.
:param conn: connection to the ecom server
:param storageSystemName: the storage system name
if compositeTypeStr.lower() == stripedStr.lower():
compositeType = 3
except KeyError:
- # Default to concatenated if not defined
+ # Default to concatenated if not defined.
pass
return compositeType
def is_volume_bound_to_pool(self, conn, volumeInstance):
- '''Check if volume is bound to a pool.
+ """Check if volume is bound to a pool.
:param conn: the connection information to the ecom server
:param storageServiceInstanceName: the storageSystem instance Name
:returns: foundIsSupportsTieringPolicies - true/false
- '''
+ """
propertiesList = volumeInstance.properties.items()
for properties in propertiesList:
if properties[0] == 'EMCIsBound':
return 'Undetermined'
def get_space_consumed(self, conn, volumeInstance):
- '''Check the space consumed of a volume.
+ """Check the space consumed of a volume.
:param conn: the connection information to the ecom server
:param volumeInstance: the volume Instance
:returns: spaceConsumed
- '''
+ """
foundSpaceConsumed = None
unitnames = conn.References(
volumeInstance, ResultClass='CIM_AllocatedFromStoragePool',
return foundSpaceConsumed
def get_volume_size(self, conn, volumeInstance):
- '''Get the volume size.
+ """Get the volume size.
ConsumableBlocks * BlockSize
:param conn: the connection information to the ecom server
:param volumeInstance: the volume Instance
:returns: volumeSizeOut
- '''
+ """
volumeSizeOut = 'Undetermined'
numBlocks = 0
blockSize = 0
return volumeSizeOut
def determine_member_count(self, sizeStr, memberCount, compositeType):
- '''Determines how many members a volume should contain.
+ """Determines how many members a volume should contain.
Based on the size of the proposed volume, the compositeType and the
memberCount, determine (or validate) how many meta members there
:param compositeType: the composite type
:returns: memberCount - string
:returns: errorDesc - the error description
- '''
+ """
errorDesc = None
if compositeType in 'concatenated' and int(sizeStr) > 240:
newMemberCount = int(sizeStr) / 240
return volumeTypeName
def get_volumes_from_pool(self, conn, poolInstanceName):
- '''Check the space consumed of a volume.
+ """Check the space consumed of a volume.
:param conn: the connection information to the ecom server
:param volumeInstance: the volume Instance
:returns: spaceConsumed
- '''
+ """
return conn.AssociatorNames(
poolInstanceName, AssocClass='CIM_AllocatedFromStoragePool',
ResultClass='CIM_StorageVolume')
def check_is_volume_bound_to_pool(self, conn, volumeInstance):
- '''Check the space consumed of a volume.
+ """Check the space consumed of a volume.
:param conn: the connection information to the ecom server
:param volumeInstance: the volume Instance
:returns: spaceConsumed
- '''
+ """
foundSpaceConsumed = None
unitnames = conn.References(
volumeInstance, ResultClass='CIM_AllocatedFromStoragePool',
return 'Undetermined'
def get_short_protocol_type(self, protocol):
- '''Given the protocol type, return I for iscsi and F for fc
+ """Given the protocol type, return I for iscsi and F for fc
:param protocol: iscsi or fc
:returns: 'I' or 'F'
- '''
+ """
if protocol.lower() == ISCSI.lower():
return 'I'
elif protocol.lower() == FC.lower():
return hardwareIdInstances
def find_ip_protocol_endpoint(self, conn, storageSystemName):
- '''Find the IP protocol endpoint for ISCSI.
+ """Find the IP protocol endpoint for ISCSI.
:param conn: the connection to the ecom server
:param storageSystemName: the storage system name
:returns: foundIpAddress
- '''
+ """
foundIpAddress = None
ipProtocolEndpointInstances = conn.EnumerateInstances(
'CIM_IPProtocolEndpoint')
instance = None
code, desc = arg[0], arg[1]
if code == CIM_ERR_NOT_FOUND:
- # Object doesn't exist any more
+ # Object doesn't exist any more.
instance = None
else:
- # Something else that we cannot recover from has happened
+ # Something else that we cannot recover from has happened.
LOG.error(_LE("Exception: %s"), six.text_type(desc))
exceptionMessage = (_(
"Cannot verify the existence of object:"