From: Xing Yang Date: Sat, 4 Apr 2015 22:25:48 +0000 (-0400) Subject: Create initiator id if not exist in VMAX driver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=d36ac8277dfe26e18ec7fdd6ebb782fd83df38d5;p=openstack-build%2Fcinder-build.git Create initiator id if not exist in VMAX driver This problem was discovered in a customer's environment. If the initiator id (hardware id SMI-S instance) does not exist on the array, the attach volume operation will fail. In this patch, the initiator id will be created if it doesn't exist. Change-Id: I868118528d831a9f49081a6393e64eb7a414b36f Closes-Bug: #1440427 --- diff --git a/cinder/tests/test_emc_vmax.py b/cinder/tests/test_emc_vmax.py index 11b86a638..d335053b5 100644 --- a/cinder/tests/test_emc_vmax.py +++ b/cinder/tests/test_emc_vmax.py @@ -240,7 +240,7 @@ class EMCVMAXCommonData(object): initiatorgroup_name = \ 'OS-fakehost-IG' initiatorgroup_creationclass = 'SE_InitiatorMaskingGroup' - + iscsi_initiator = 'iqn.1993-08.org.debian' storageextent_creationclass = 'CIM_StorageExtent' initiator1 = 'iqn.1993-08.org.debian: 01: 1a2b3c4d5f6g' stconf_service_creationclass = 'Symm_StorageConfigurationService' @@ -462,7 +462,7 @@ class FakeEcomConnection(object): Type=None, EMCSRP=None, EMCSLO=None, EMCWorkload=None, EMCCollections=None, InitiatorMaskingGroup=None, DeviceMaskingGroup=None, TargetMaskingGroup=None, - ProtocolController=None): + ProtocolController=None, StorageID=None, IDType=None): rc = 0L myjob = SE_ConcreteJob() @@ -510,6 +510,12 @@ class FakeEcomConnection(object): rsd = SE_ReplicationSettingData() rsd['DefaultInstance'] = SE_ReplicationSettingData() return rc, rsd + if MethodName == 'CreateStorageHardwareID': + ret = {} + rc = 0L + ret['HardwareID'] = self.data.iscsi_initiator + return rc, ret + job = {'Job': myjob} return rc, job @@ -1611,6 +1617,20 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): def fake_is_v3(self, conn, serialNumber): return False + def test_create_hardware_ids(self): + conn = self.fake_ecom_connection() + connector = { + 'ip': '10.0.0.2', + 'initiator': self.data.iscsi_initiator, + 'host': 'fakehost'} + initiatorNames = ( + self.driver.common.masking._find_initiator_names(conn, connector)) + storageHardwareIDInstanceNames = ( + self.driver.common.masking._create_hardware_ids( + conn, initiatorNames, self.data.storage_system)) + self.assertEqual(storageHardwareIDInstanceNames[0], + self.data.iscsi_initiator) + def test_format_system_name(self): v2array = ['SYMMETRIX', '000195900551', 'U', 'gold'] systemnameV2 = self.driver.utils._format_system_name(v2array[0], diff --git a/cinder/volume/drivers/emc/emc_vmax_common.py b/cinder/volume/drivers/emc/emc_vmax_common.py index a2d818fb1..6cc4e34cc 100644 --- a/cinder/volume/drivers/emc/emc_vmax_common.py +++ b/cinder/volume/drivers/emc/emc_vmax_common.py @@ -3480,7 +3480,7 @@ class EMCVMAXCommon(object): baseVolumeName = "TargetBaseVol" volume = {'size': int(self.utils.convert_bits_to_gbs( volumeSizeInbits))} - rc, baseVolumeDict, storageSystemName = ( + _rc, baseVolumeDict, storageSystemName = ( self._create_composite_volume( volume, baseVolumeName, volumeSizeInbits, extraSpecs)) @@ -3518,7 +3518,7 @@ class EMCVMAXCommon(object): self.conn, storageSystemName)) compositeType = self.utils.get_composite_type( extraSpecs[COMPOSITETYPE]) - rc, modifiedVolumeDict = ( + _rc, modifiedVolumeDict = ( self._modify_and_get_composite_volume_instance( self.conn, elementCompositionService, diff --git a/cinder/volume/drivers/emc/emc_vmax_fc.py b/cinder/volume/drivers/emc/emc_vmax_fc.py index f52b2e791..d02aafc4b 100644 --- a/cinder/volume/drivers/emc/emc_vmax_fc.py +++ b/cinder/volume/drivers/emc/emc_vmax_fc.py @@ -184,7 +184,8 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver): :returns: dict -- the target_wwns and initiator_target_map if the zone is to be removed, otherwise empty """ - data = {} + data = {'driver_volume_type': 'fibre_channel', + 'data': {}} loc = volume['provider_location'] name = eval(loc) storage_system = name['keybindings']['SystemName'] @@ -193,8 +194,6 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver): 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( diff --git a/cinder/volume/drivers/emc/emc_vmax_masking.py b/cinder/volume/drivers/emc/emc_vmax_masking.py index 64f218e93..eb32e9df2 100644 --- a/cinder/volume/drivers/emc/emc_vmax_masking.py +++ b/cinder/volume/drivers/emc/emc_vmax_masking.py @@ -776,7 +776,6 @@ class EMCVMAXMasking(object): :param storageSystemName: the storage system name (String) :returns: foundInitiatorGroupInstanceName """ - failedRet = None initiatorNames = self._find_initiator_names(conn, connector) LOG.debug("The initiator name(s) are: %(initiatorNames)s.", {'initiatorNames': initiatorNames}) @@ -793,12 +792,20 @@ class EMCVMAXMasking(object): self._get_storage_hardware_id_instance_names( conn, initiatorNames, storageSystemName)) if not storageHardwareIDInstanceNames: - LOG.error(_LE( + LOG.info(_LI( "Initiator Name(s) %(initiatorNames)s are not on array " "%(storageSystemName)s."), {'initiatorNames': initiatorNames, 'storageSystemName': storageSystemName}) - return failedRet + storageHardwareIDInstanceNames = ( + self._create_hardware_ids(conn, initiatorNames, + storageSystemName)) + if not storageHardwareIDInstanceNames: + msg = (_("Failed to create hardware id(s) on " + "%(storageSystemName)s.") + % {'storageSystemName': storageSystemName}) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) foundInitiatorGroupInstanceName = self._create_initiator_Group( conn, controllerConfigService, igGroupName, @@ -1343,12 +1350,20 @@ class EMCVMAXMasking(object): self._get_storage_hardware_id_instance_names( conn, initiatorNames, storageSystemName)) if not storageHardwareIDInstanceNames: - LOG.error(_LE( + LOG.info(_LI( "Initiator Name(s) %(initiatorNames)s are not on " - "array %(storageSystemName)s."), + "array %(storageSystemName)s. "), {'initiatorNames': initiatorNames, 'storageSystemName': storageSystemName}) - return False + storageHardwareIDInstanceNames = ( + self._create_hardware_ids(conn, initiatorNames, + storageSystemName)) + if not storageHardwareIDInstanceNames: + LOG.error(_LE( + "Failed to create hardware id(s) on " + "%(storageSystemName)s."), + {'storageSystemName': storageSystemName}) + return False foundInitiatorGroupFromConnector = ( self._create_initiator_Group( @@ -2247,3 +2262,28 @@ class EMCVMAXMasking(object): LOG.error(exceptionMessage) raise exception.VolumeBackendAPIException( data=exceptionMessage) + + def _create_hardware_ids( + self, conn, initiatorNames, storageSystemName): + """Create hardwareIds for initiator(s). + + :param conn: the connection to the ecom server + :param initiatorNames: the list of initiator names + :param storageSystemName: the storage system name + :returns: list -- foundHardwareIDsInstanceNames + """ + foundHardwareIDsInstanceNames = [] + + hardwareIdManagementService = ( + self.utils.find_storage_hardwareid_service( + conn, storageSystemName)) + for initiatorName in initiatorNames: + hardwareIdInstanceName = ( + self.utils.create_storage_hardwareId_instance_name( + conn, hardwareIdManagementService, initiatorName)) + LOG.debug( + "Created hardwareId Instance: %(hardwareIdInstanceName)s.", + {'hardwareIdInstanceName': hardwareIdInstanceName}) + foundHardwareIDsInstanceNames.append(hardwareIdInstanceName) + + return foundHardwareIDsInstanceNames diff --git a/cinder/volume/drivers/emc/emc_vmax_utils.py b/cinder/volume/drivers/emc/emc_vmax_utils.py index 481f2f32e..8636a69b4 100644 --- a/cinder/volume/drivers/emc/emc_vmax_utils.py +++ b/cinder/volume/drivers/emc/emc_vmax_utils.py @@ -1891,3 +1891,32 @@ class EMCVMAXUtils(object): LOG.debug("Clone is licensed and enabled.") return True return False + + def create_storage_hardwareId_instance_name( + self, conn, hardwareIdManagementService, initiator): + """Create storage hardware ID instance name based on the given wwpn. + + :param conn: connection to the ecom server + :param hardwareIdManagementService: the hardware ID management service + :param initiator: initiator(IQN or WWPN) to create the hardware ID + instance + :returns: hardwareIdList + """ + hardwareIdList = None + hardwareIdType = 2 + rc, ret = conn.InvokeMethod( + 'CreateStorageHardwareID', + hardwareIdManagementService, + StorageID=initiator, + IDType=self.get_num(hardwareIdType, '16')) + + if 'HardwareID' in ret: + LOG.debug("Created hardware ID instance for initiator:" + "%(initiator)s rc=%(rc)d, ret=%(ret)s", + {'initiator': initiator, 'rc': rc, 'ret': ret}) + hardwareIdList = ret['HardwareID'] + else: + LOG.warn(_LW("CreateStorageHardwareID failed. initiator: " + "%(initiator)s, rc=%(rc)d, ret=%(ret)s."), + {'initiator': initiator, 'rc': rc, 'ret': ret}) + return hardwareIdList