From: Xing Yang Date: Fri, 28 Aug 2015 18:56:13 +0000 (-0400) Subject: Fix a merge problem in VMAX driver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=abc6abb1738a8ade607467397751571a30d0e6f5;p=openstack-build%2Fcinder-build.git Fix a merge problem in VMAX driver SMI-S v8.0.3 support was added to VMAX driver, but some of the code was merged out. This patch adds them back. (Pulled from gate, cinder can no longer pass unit tests) Change-Id: Ie2cd2ba12d72d27e6ea71de86911cfca83d105c0 Closes-Bug: #1487616 --- diff --git a/cinder/tests/unit/test_emc_vmax.py b/cinder/tests/unit/test_emc_vmax.py index a64478149..41be1e0a4 100644 --- a/cinder/tests/unit/test_emc_vmax.py +++ b/cinder/tests/unit/test_emc_vmax.py @@ -292,7 +292,18 @@ class EMCVMAXCommonData(object): provider_location_multi_pool = {'classname': 'Symm_StorageVolume', 'keybindings': keybindings, 'version': '2.2.0'} - + block_size = 512 + majorVersion = 1 + minorVersion = 2 + revNumber = 3 + block_size = 512 + + metaHead_volume = {'DeviceID': 10, + 'ConsumableBlocks': 1000} + meta_volume1 = {'DeviceID': 11, + 'ConsumableBlocks': 200} + meta_volume2 = {'DeviceID': 12, + 'ConsumableBlocks': 300} properties = {'ConsumableBlocks': '12345', 'BlockSize': '512'} @@ -310,7 +321,7 @@ class EMCVMAXCommonData(object): 'status': 'available', 'host': fake_host, 'NumberOfBlocks': 100, - 'BlockSize': 512 + 'BlockSize': block_size } test_volume_v2 = {'name': 'vol1', @@ -327,7 +338,7 @@ class EMCVMAXCommonData(object): 'status': 'available', 'host': fake_host, 'NumberOfBlocks': 100, - 'BlockSize': 512 + 'BlockSize': block_size } test_volume_v3 = {'name': 'vol1', @@ -344,7 +355,7 @@ class EMCVMAXCommonData(object): 'status': 'available', 'host': fake_host_v3, 'NumberOfBlocks': 100, - 'BlockSize': 512 + 'BlockSize': block_size } test_volume_CG = {'name': 'volInCG', @@ -502,7 +513,8 @@ class FakeEcomConnection(object): Type=None, EMCSRP=None, EMCSLO=None, EMCWorkload=None, EMCCollections=None, InitiatorMaskingGroup=None, DeviceMaskingGroup=None, TargetMaskingGroup=None, - ProtocolController=None, StorageID=None, IDType=None): + ProtocolController=None, StorageID=None, IDType=None, + WaitForCopyState=None): rc = 0 myjob = SE_ConcreteJob() @@ -526,7 +538,7 @@ class FakeEcomConnection(object): myjob['status'] = 'failure' elif TheElements and TheElements[0]['DeviceID'] == '99999' and ( - MethodName == 'EMCReturnToStoragePool'): + MethodName == 'ReturnElementsToStoragePool'): rc = 10 myjob['status'] = 'failure' elif HardwareId: @@ -560,6 +572,13 @@ class FakeEcomConnection(object): ret['EMCInformationSource'] = 3 ret['EMCRemainingSLOCapacity'] = self.data.remainingSLOCapacity return rc, ret + elif MethodName == 'GetCompositeElements': + ret = {} + rc = 0 + ret['OutElements'] = [self.data.metaHead_volume, + self.data.meta_volume1, + self.data.meta_volume2] + return rc, ret job = {'Job': myjob} return rc, job @@ -602,6 +621,8 @@ class FakeEcomConnection(object): result = self._enum_repservcpbls() elif name == 'SE_StorageSynchronized_SV_SV': result = self._enum_storageSyncSvSv() + elif name == 'Symm_SRPStoragePool': + result = self._enum_srpstoragepool() else: result = self._default_enum() return result @@ -612,6 +633,8 @@ class FakeEcomConnection(object): result = self._enum_pool_details() elif name == 'SE_StorageHardwareID': result = self._enum_storhdwids() + elif name == 'SE_ManagementServerSoftwareIdentity': + result = self._enum_sw_identity() else: result = self._default_enum() return result @@ -1001,7 +1024,7 @@ class FakeEcomConnection(object): def _getinstance_pool(self, objectpath): pool = {} pool['CreationClassName'] = 'Symm_VirtualProvisioningPool' - pool['ElementName'] = 'gold' + pool['ElementName'] = self.data.poolname pool['SystemName'] = self.data.storage_system pool['TotalManagedSpace'] = self.data.totalmanagedspace_bits pool['EMCSubscribedCapacity'] = self.data.subscribedcapacity_bits @@ -1018,6 +1041,7 @@ class FakeEcomConnection(object): srpstoragepool = SYMM_SrpStoragePool() srpstoragepool['CreationClassName'] = ( self.data.srpstoragepool_creationclass) + srpstoragepool['ElementName'] = 'SRP_1' classcimproperty = Fake_CIMProperty() totalManagedSpace = ( @@ -1268,6 +1292,31 @@ class FakeEcomConnection(object): vols.append(failed_vol) + volumeHead = EMC_StorageVolume() + volumeHead.classname = 'Symm_StorageVolume' + blockSize = self.data.block_size + volumeHead['ConsumableBlocks'] = ( + self.data.metaHead_volume['ConsumableBlocks']) + volumeHead['BlockSize'] = blockSize + volumeHead['DeviceID'] = self.data.metaHead_volume['DeviceID'] + vols.append(volumeHead) + + metaMember1 = EMC_StorageVolume() + metaMember1.classname = 'Symm_StorageVolume' + metaMember1['ConsumableBlocks'] = ( + self.data.meta_volume1['ConsumableBlocks']) + metaMember1['BlockSize'] = blockSize + metaMember1['DeviceID'] = self.data.meta_volume1['DeviceID'] + vols.append(metaMember1) + + metaMember2 = EMC_StorageVolume() + metaMember2.classname = 'Symm_StorageVolume' + metaMember2['ConsumableBlocks'] = ( + self.data.meta_volume2['ConsumableBlocks']) + metaMember2['BlockSize'] = blockSize + metaMember2['DeviceID'] = self.data.meta_volume2['DeviceID'] + vols.append(metaMember2) + return vols def _enum_initiatorMaskingGroup(self): @@ -1518,6 +1567,15 @@ class FakeEcomConnection(object): svInstances.append(svInstance) return svInstances + def _enum_sw_identity(self): + swIdentities = [] + swIdentity = {} + swIdentity['MajorVersion'] = self.data.majorVersion + swIdentity['MinorVersion'] = self.data.minorVersion + swIdentity['RevisionNumber'] = self.data.revNumber + swIdentities.append(swIdentity) + return swIdentities + def _default_enum(self): names = [] name = {} @@ -1732,6 +1790,27 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): def fake_is_v3(self, conn, serialNumber): return False + def test_unbind_and_get_volume_from_storage_pool(self): + conn = self.fake_ecom_connection() + common = self.driver.common + common.utils.is_volume_bound_to_pool = mock.Mock( + return_value='False') + storageConfigService = ( + common.utils.find_storage_configuration_service( + conn, self.data.storage_system)) + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeName = "unbind-vol" + extraSpecs = {'volume_backend_name': 'GOLD_BE', + 'isV3': False} + volumeInstance = ( + common._unbind_and_get_volume_from_storage_pool( + conn, storageConfigService, + volumeInstanceName, volumeName, extraSpecs)) + self.assertEqual(self.data.storage_system, + volumeInstance['SystemName']) + self.assertEqual('1', volumeInstance['ElementName']) + def test_create_hardware_ids(self): conn = self.fake_ecom_connection() connector = { @@ -1746,18 +1825,39 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): self.assertEqual(self.data.iscsi_initiator, storageHardwareIDInstanceNames[0]) - def test_format_system_name(self): - v2array = ['SYMMETRIX', '000195900551', 'U', 'gold'] - systemnameV2 = self.driver.utils._format_system_name(v2array[0], - v2array[1], - '+') - self.assertEqual('SYMMETRIX+000195900551', systemnameV2) - - v3array = ['SYMMETRIX', '000197200056', 'SRP_1'] - systemnameV3 = self.driver.utils._format_system_name(v3array[0], - v3array[1], - '-+-') - self.assertEqual('SYMMETRIX-+-000197200056', systemnameV3) + def test_get_pool_instance_and_system_name(self): + conn = self.fake_ecom_connection() + # V2 - old '+' separator + storagesystem = {} + storagesystem['SystemName'] = self.data.storage_system + storagesystem['Name'] = self.data.storage_system + pools = conn.EnumerateInstanceNames("EMC_VirtualProvisioningPool") + poolname = 'gold' + poolinstancename, systemname = ( + self.driver.common.utils._get_pool_instance_and_system_name( + conn, pools, storagesystem, poolname)) + self.assertEqual(self.data.storage_system, systemname) + self.assertEqual(self.data.storagepoolid, + poolinstancename['InstanceID']) + # V3 - note: V2 can also have the '-+-' separator + storagesystem = {} + storagesystem['SystemName'] = self.data.storage_system_v3 + storagesystem['Name'] = self.data.storage_system_v3 + pools = conn.EnumerateInstanceNames('Symm_SRPStoragePool') + poolname = 'SRP_1' + poolinstancename, systemname = ( + self.driver.common.utils._get_pool_instance_and_system_name( + conn, pools, storagesystem, poolname)) + self.assertEqual(self.data.storage_system_v3, systemname) + self.assertEqual('SYMMETRIX-+-000197200056-+-SRP_1', + poolinstancename['InstanceID']) + # Invalid poolname + poolname = 'bogus' + poolinstancename, systemname = ( + self.driver.common.utils._get_pool_instance_and_system_name( + conn, pools, storagesystem, poolname)) + self.assertIsNone(poolinstancename) + self.assertEqual(self.data.storage_system_v3, systemname) def test_get_hardware_type(self): iqn_initiator = 'iqn.1992-04.com.emc: 50000973f006dd80' @@ -1982,19 +2082,19 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): volume2 = EMC_StorageVolume() volume2['name'] = 'myVol' volume2['provider_location'] = six.text_type(provider_location2) - verify_orig = self.driver.common.utils.get_existing_instance - self.driver.common.utils.get_existing_instance = mock.Mock( + verify_orig = self.driver.common.conn.GetInstance + self.driver.common.conn.GetInstance = mock.Mock( return_value=None) findlun2 = self.driver.common._find_lun(volume2) # Not found. self.assertIsNone(findlun2) - instancename2 = self.driver.utils.get_instance_name( + self.driver.utils.get_instance_name( provider_location2['classname'], keybindings2) - self.driver.common.utils.get_existing_instance.assert_called_once_with( - self.driver.common.conn, instancename2) - self.driver.common.utils.get_existing_instance.reset_mock() - self.driver.common.utils.get_existing_instance = verify_orig + self.driver.common.conn.GetInstance.assert_called_once_with( + keybindings2) + self.driver.common.conn.GetInstance.reset_mock() + self.driver.common.conn.GetInstance = verify_orig keybindings3 = {'CreationClassName': u'Symm_StorageVolume', 'SystemName': u'SYMMETRIX+000195900551', @@ -2731,7 +2831,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -2766,7 +2866,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -2827,7 +2927,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( FakeDB, @@ -3038,7 +3138,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -3149,6 +3249,74 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase): conn, volumeInstance, originalName) self.assertEqual(originalName, volumeInstance['ElementName']) + def test_get_smi_version(self): + conn = self.fake_ecom_connection() + utils = self.driver.common.utils + version = utils.get_smi_version(conn) + expected = int(str(self.data.majorVersion) + + str(self.data.minorVersion) + + str(self.data.revNumber)) + self.assertEqual(version, expected) + + def test_get_pool_name(self): + conn = self.fake_ecom_connection() + utils = self.driver.common.utils + poolInstanceName = {} + poolInstanceName['InstanceID'] = "SATA_GOLD1" + poolInstanceName['CreationClassName'] = 'Symm_VirtualProvisioningPool' + poolName = utils.get_pool_name(conn, poolInstanceName) + self.assertEqual(poolName, self.data.poolname) + + def test_get_meta_members_capacity_in_byte(self): + conn = self.fake_ecom_connection() + utils = self.driver.common.utils + memberVolumeInstanceNames = [] + volumeHead = EMC_StorageVolume() + volumeHead.classname = 'Symm_StorageVolume' + blockSize = self.data.block_size + volumeHead['ConsumableBlocks'] = ( + self.data.metaHead_volume['ConsumableBlocks']) + volumeHead['BlockSize'] = blockSize + volumeHead['DeviceID'] = self.data.metaHead_volume['DeviceID'] + memberVolumeInstanceNames.append(volumeHead) + metaMember1 = EMC_StorageVolume() + metaMember1.classname = 'Symm_StorageVolume' + metaMember1['ConsumableBlocks'] = ( + self.data.meta_volume1['ConsumableBlocks']) + metaMember1['BlockSize'] = blockSize + metaMember1['DeviceID'] = self.data.meta_volume1['DeviceID'] + memberVolumeInstanceNames.append(metaMember1) + metaMember2 = EMC_StorageVolume() + metaMember2.classname = 'Symm_StorageVolume' + metaMember2['ConsumableBlocks'] = ( + self.data.meta_volume2['ConsumableBlocks']) + metaMember2['BlockSize'] = blockSize + metaMember2['DeviceID'] = self.data.meta_volume2['DeviceID'] + memberVolumeInstanceNames.append(metaMember2) + capacities = utils.get_meta_members_capacity_in_byte( + conn, memberVolumeInstanceNames) + headSize = ( + volumeHead['ConsumableBlocks'] - + metaMember1['ConsumableBlocks'] - + metaMember2['ConsumableBlocks']) + expected = [headSize * blockSize, + metaMember1['ConsumableBlocks'] * blockSize, + metaMember2['ConsumableBlocks'] * blockSize] + self.assertEqual(capacities, expected) + + def test_get_composite_elements(self): + conn = self.fake_ecom_connection() + utils = self.driver.common.utils + volumeInstanceName = ( + conn.EnumerateInstanceNames("EMC_StorageVolume")[0]) + volumeInstance = conn.GetInstance(volumeInstanceName) + memberVolumeInstanceNames = utils.get_composite_elements( + conn, volumeInstance) + expected = [self.data.metaHead_volume, + self.data.meta_volume1, + self.data.meta_volume2] + self.assertEqual(memberVolumeInstanceNames, expected) + def test_get_volume_model_updates(self): utils = self.driver.common.utils status = 'status-string' @@ -3549,7 +3717,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -3587,7 +3755,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase): @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -3637,7 +3805,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -4338,7 +4506,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase): 'status': 'available', 'host': self.data.fake_host, 'NumberOfBlocks': 100, - 'BlockSize': 512 + 'BlockSize': self.data.block_size } common = self.driver.common common._initial_setup = mock.Mock( @@ -4371,7 +4539,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase): 'status': 'available', 'host': self.data.fake_host, 'NumberOfBlocks': 100, - 'BlockSize': 512 + 'BlockSize': self.data.block_size } common = self.driver.common common._initial_setup = mock.Mock( @@ -4750,7 +4918,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -4792,7 +4960,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase): @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -4861,7 +5029,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase): return_value=(None, EMCVMAXCommonData.storage_system)) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, - 'get_meta_members_capacity_in_bit', + 'get_meta_members_capacity_in_byte', return_value=[1234567, 7654321]) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, @@ -5164,16 +5332,12 @@ class EMCV3DriverTestCase(test.TestCase): 'isV3': True, 'portgroupname': 'OS-portgroup-PG'} - @mock.patch.object( - emc_vmax_utils.EMCVMAXUtils, - 'isArrayV3', - return_value=True) @mock.patch.object( emc_vmax_utils.EMCVMAXUtils, 'find_storageSystem', - return_value=None) + return_value={'Name': EMCVMAXCommonData.storage_system_v3}) def test_get_volume_stats_v3( - self, mock_storage_system, mock_is_v3): + self, mock_storage_system): self.driver.get_volume_stats(True) @mock.patch.object( @@ -5320,7 +5484,7 @@ class EMCV3DriverTestCase(test.TestCase): cloneVol['volume_type_id'] = 'abc' cloneVol['provider_location'] = None cloneVol['NumberOfBlocks'] = 100 - cloneVol['BlockSize'] = 512 + cloneVol['BlockSize'] = self.data.block_size cloneVol['host'] = self.data.fake_host_v3 self.driver.common._initial_setup = mock.Mock( return_value=self.default_extraspec()) diff --git a/cinder/volume/drivers/emc/emc_vmax_common.py b/cinder/volume/drivers/emc/emc_vmax_common.py index ae9701d06..35ff88afc 100644 --- a/cinder/volume/drivers/emc/emc_vmax_common.py +++ b/cinder/volume/drivers/emc/emc_vmax_common.py @@ -58,6 +58,7 @@ STRIPECOUNT = 'storagetype:stripecount' MEMBERCOUNT = 'storagetype:membercount' STRIPED = 'striped' CONCATENATED = 'concatenated' +SMI_VERSION_8 = 800 # V3 SLO = 'storagetype:slo' WORKLOAD = 'storagetype:workload' @@ -1316,13 +1317,25 @@ class EMCVMAXCommon(object): if isinstance(loc, six.string_types): name = eval(loc) + keys = name['keybindings'] + systemName = keys['SystemName'] + + prefix1 = 'SYMMETRIX+' + prefix2 = 'SYMMETRIX-+-' + smiversion = self.utils.get_smi_version(self.conn) + if smiversion > SMI_VERSION_8 and prefix1 in systemName: + keys['SystemName'] = systemName.replace(prefix1, prefix2) + name['keybindings'] = keys instancename = self.utils.get_instance_name( name['classname'], name['keybindings']) - - # Handle the case where volume cannot be found. - foundVolumeinstance = self.utils.get_existing_instance( - self.conn, instancename) + # Allow for an external app to delete the volume. + LOG.debug("Volume instance name: %(in)s", + {'in': instancename}) + try: + foundVolumeinstance = self.conn.GetInstance(instancename) + except Exception: + foundVolumeinstance = None if foundVolumeinstance is None: LOG.debug("Volume %(volumename)s not found on the array.", @@ -1830,7 +1843,7 @@ class EMCVMAXCommon(object): if 'True' in isVolumeBound: appendVolumeInstance = ( self._unbind_and_get_volume_from_storage_pool( - conn, storageConfigService, assocPoolInstanceName, + conn, storageConfigService, appendVolumeInstance.path, 'appendVolume', extraSpecs)) return appendVolumeInstance @@ -1857,27 +1870,32 @@ class EMCVMAXCommon(object): return volumeInstance def _unbind_and_get_volume_from_storage_pool( - self, conn, storageConfigService, poolInstanceName, + self, conn, storageConfigService, volumeInstanceName, volumeName, extraSpecs): """Unbind a volume from a pool and return the unbound volume. :param conn: the connection information to the ecom server :param storageConfigService: the storage config service instance name - :param poolInstanceName: the pool instance name :param volumeInstanceName: the volume instance name :param volumeName: string the volumeName :param extraSpecs: extra specifications :returns: unboundVolumeInstance -- the unbound volume instance """ - - _rc, job = ( + _rc, _job = ( self.provision.unbind_volume_from_storage_pool( - conn, storageConfigService, poolInstanceName, - volumeInstanceName, + conn, storageConfigService, volumeInstanceName, volumeName, extraSpecs)) - volumeDict = self.provision.get_volume_dict_from_job(conn, job['Job']) - volumeInstance = self.utils.find_volume_instance( - self.conn, volumeDict, volumeName) + # Check that the volume in unbound + volumeInstance = conn.GetInstance(volumeInstanceName) + isVolumeBound = self.utils.is_volume_bound_to_pool( + conn, volumeInstance) + if 'False' not in isVolumeBound: + exceptionMessage = (_( + "Failed to unbind volume %(volume)s") + % {'volume': volumeInstanceName}) + LOG.error(exceptionMessage) + raise exception.VolumeBackendAPIException(data=exceptionMessage) + return volumeInstance def _modify_and_get_composite_volume_instance( @@ -3411,9 +3429,9 @@ class EMCVMAXCommon(object): 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)) - volumeCapacities = self.utils.get_meta_members_capacity_in_bit( + self.utils.get_composite_elements( + self.conn, sourceInstance)) + volumeCapacities = self.utils.get_meta_members_capacity_in_byte( self.conn, metaMemberInstanceNames) LOG.debug("Volume capacities: %(metasizes)s.", {'metasizes': volumeCapacities}) diff --git a/cinder/volume/drivers/emc/emc_vmax_https.py b/cinder/volume/drivers/emc/emc_vmax_https.py index 154f48b5e..89a728fe7 100644 --- a/cinder/volume/drivers/emc/emc_vmax_https.py +++ b/cinder/volume/drivers/emc/emc_vmax_https.py @@ -332,14 +332,14 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None, msg = (_("Bad Status line returned: %(arg)s.") % {'arg': arg}) raise pywbem.cim_http.Error(msg) - except socket.sslerror as arg: - msg = (_("SSL error: %(arg)s.") - % {'arg': arg}) - raise pywbem.cim_http.Error(msg) except socket.error as arg: msg = (_("Socket error: %(arg)s.") % {'arg': arg}) raise pywbem.cim_http.Error(msg) + except socket.sslerror as arg: + msg = (_("SSL error: %(arg)s.") + % {'arg': arg}) + raise pywbem.cim_http.Error(msg) break diff --git a/cinder/volume/drivers/emc/emc_vmax_provision.py b/cinder/volume/drivers/emc/emc_vmax_provision.py index 6a485e0b8..0a85b0024 100644 --- a/cinder/volume/drivers/emc/emc_vmax_provision.py +++ b/cinder/volume/drivers/emc/emc_vmax_provision.py @@ -64,7 +64,7 @@ class EMCVMAXProvision(object): theElements = [volumeInstanceName] rc, job = conn.InvokeMethod( - 'EMCReturnToStoragePool', storageConfigservice, + 'ReturnElementsToStoragePool', storageConfigservice, TheElements=theElements) if rc != 0: @@ -338,14 +338,13 @@ class EMCVMAXProvision(object): time.time())}) def unbind_volume_from_storage_pool( - self, conn, storageConfigService, poolInstanceName, + self, conn, storageConfigService, volumeInstanceName, volumeName, extraSpecs): """Unbind a volume from a pool and return the unbound volume. :param conn: the connection information to the ecom server :param storageConfigService: the storage configuration service instance name - :param poolInstanceName: the pool instance name :param volumeInstanceName: the volume instance name :param volumeName: the volume name :param extraSpecs: additional info @@ -358,7 +357,6 @@ class EMCVMAXProvision(object): rc, job = conn.InvokeMethod( 'EMCUnBindElement', storageConfigService, - InPool=poolInstanceName, TheElement=volumeInstanceName) if rc != 0: @@ -1088,7 +1086,8 @@ class EMCVMAXProvision(object): RelationshipName=relationName, SourceGroup=srcGroupInstanceName, TargetGroup=tgtGroupInstanceName, - SyncType=self.utils.get_num(8, '16')) + SyncType=self.utils.get_num(8, '16'), + WaitForCopyState=self.utils.get_num(4, '16')) if rc != 0: rc, errordesc = self.utils.wait_for_job_complete(conn, job, diff --git a/cinder/volume/drivers/emc/emc_vmax_utils.py b/cinder/volume/drivers/emc/emc_vmax_utils.py index 722c33ef8..d4b9f0190 100644 --- a/cinder/volume/drivers/emc/emc_vmax_utils.py +++ b/cinder/volume/drivers/emc/emc_vmax_utils.py @@ -987,13 +987,14 @@ class EMCVMAXUtils(object): LOG.debug( "storagePoolName: %(poolName)s, storageSystemName: %(array)s.", {'poolName': storagePoolName, 'array': storageSystemName}) - poolInstanceNames = conn.EnumerateInstanceNames( - 'EMC_VirtualProvisioningPool') + storageSystemInstanceName = self.find_storageSystem(conn, + storageSystemName) + poolInstanceNames = conn.AssociatorNames( + storageSystemInstanceName, + ResultClass='EMC_VirtualProvisioningPool') for poolInstanceName in poolInstanceNames: - poolName, systemName = ( - self.parse_pool_instance_id(poolInstanceName['InstanceID'])) - if (poolName == storagePoolName and - storageSystemName in systemName): + poolName = self.get_pool_name(conn, poolInstanceName) + if (poolName == storagePoolName): # Check that the pool hasn't been recently deleted. instance = self.get_existing_instance(conn, poolInstanceName) if instance is None: @@ -1385,27 +1386,13 @@ class EMCVMAXUtils(object): :returns: foundPoolInstanceName :returns: string -- systemNameStr """ - foundPoolInstanceName = None vpoolInstanceNames = conn.AssociatorNames( storageSystemInstanceName, ResultClass='EMC_VirtualProvisioningPool') - for vpoolInstanceName in vpoolInstanceNames: - poolInstanceId = vpoolInstanceName['InstanceID'] - # Example: SYMMETRIX+000195900551+TP+Sol_Innov - poolnameStr, systemNameStr = self.parse_pool_instance_id( - poolInstanceId) - if poolnameStr is not None and systemNameStr is not None: - if six.text_type(poolNameInStr) == six.text_type(poolnameStr): - # check that the pool hasn't recently been deleted. - try: - conn.GetInstance(vpoolInstanceName) - foundPoolInstanceName = vpoolInstanceName - except Exception: - foundPoolInstanceName = None - break - - return foundPoolInstanceName, systemNameStr + return self._get_pool_instance_and_system_name( + conn, vpoolInstanceNames, storageSystemInstanceName, + poolNameInStr) def get_pool_and_system_name_v3( self, conn, storageSystemInstanceName, poolNameInStr): @@ -1417,21 +1404,36 @@ class EMCVMAXUtils(object): :returns: foundPoolInstanceName :returns: string -- systemNameStr """ - foundPoolInstanceName = None srpPoolInstanceNames = conn.AssociatorNames( storageSystemInstanceName, ResultClass='Symm_SRPStoragePool') - for srpPoolInstanceName in srpPoolInstanceNames: - poolInstanceID = srpPoolInstanceName['InstanceID'] + return self._get_pool_instance_and_system_name( + conn, srpPoolInstanceNames, storageSystemInstanceName, + poolNameInStr) + + def _get_pool_instance_and_system_name( + self, conn, poolInstanceNames, storageSystemInstanceName, + poolname): + """Get the pool instance and the system name + + :param conn: the ecom connection + :param poolInstanceNames: list of pool instances + :param poolname: pool name (string) + :returns: foundPoolInstanceName, systemname + """ + foundPoolInstanceName = None + poolnameStr = None + systemNameStr = storageSystemInstanceName['Name'] + for poolInstanceName in poolInstanceNames: # Example: SYMMETRIX-+-000196700535-+-SR-+-SRP_1 - poolnameStr, systemNameStr = self.parse_pool_instance_id_v3( - poolInstanceID) - if poolnameStr is not None and systemNameStr is not None: - if six.text_type(poolNameInStr) == six.text_type(poolnameStr): + # Example: SYMMETRIX+000195900551+TP+Sol_Innov + poolnameStr = self.get_pool_name(conn, poolInstanceName) + if poolnameStr is not None: + if six.text_type(poolname) == six.text_type(poolnameStr): try: - conn.GetInstance(srpPoolInstanceName) - foundPoolInstanceName = srpPoolInstanceName + conn.GetInstance(poolInstanceName) + foundPoolInstanceName = poolInstanceName except Exception: foundPoolInstanceName = None break @@ -1609,21 +1611,28 @@ class EMCVMAXUtils(object): LOG.debug("metaMembers: %(members)s.", {'members': metaMembers}) return metaMembers - def get_meta_members_capacity_in_bit(self, conn, volumeInstanceNames): - """Get the capacity in bits of all meta device member volumes. + def get_meta_members_capacity_in_byte(self, conn, volumeInstanceNames): + """Get the capacity in byte of all meta device member volumes. :param conn: the ecom connection :param volumeInstanceNames: array contains meta device member volumes :returns: array contains capacities of each member device in bits """ - capacitiesInBit = [] + capacitiesInByte = [] + headVolume = conn.GetInstance(volumeInstanceNames[0]) + totalSizeInByte = ( + headVolume['ConsumableBlocks'] * headVolume['BlockSize']) + volumeInstanceNames.pop(0) for volumeInstanceName in volumeInstanceNames: volumeInstance = conn.GetInstance(volumeInstanceName) numOfBlocks = volumeInstance['ConsumableBlocks'] blockSize = volumeInstance['BlockSize'] - volumeSizeInbits = numOfBlocks * blockSize - capacitiesInBit.append(volumeSizeInbits) - return capacitiesInBit + volumeSizeInByte = numOfBlocks * blockSize + capacitiesInByte.append(volumeSizeInByte) + totalSizeInByte = totalSizeInByte - volumeSizeInByte + + capacitiesInByte.insert(0, totalSizeInByte) + return capacitiesInByte def get_existing_instance(self, conn, instanceName): """Check that the instance name still exists and return the instance. @@ -2283,3 +2292,54 @@ class EMCVMAXUtils(object): LOG.info(_LI("No volume found for CG: %(cg)s."), {'cg': cgId}) return volume_model_updates + + def get_smi_version(self, conn): + """Get the SMI_S version. + + :param conn: the connection to the ecom server + :returns: string -- version + """ + intVersion = 0 + swIndentityInstances = conn.EnumerateInstances( + 'SE_ManagementServerSoftwareIdentity') + if swIndentityInstances: + swIndentityInstance = swIndentityInstances[0] + majorVersion = swIndentityInstance['MajorVersion'] + minorVersion = swIndentityInstance['MinorVersion'] + revisionNumber = swIndentityInstance['RevisionNumber'] + + intVersion = int(six.text_type(majorVersion) + + six.text_type(minorVersion) + + six.text_type(revisionNumber)) + + LOG.debug("Major version: %(majV)lu, Minor version: %(minV)lu, " + "Revision number: %(revNum)lu, Version: %(intV)lu.", + {'majV': majorVersion, + 'minV': minorVersion, + 'revNum': revisionNumber, + 'intV': intVersion}) + return intVersion + + def get_composite_elements( + self, conn, volumeInstance): + """Get the meta members of a composite volume. + + :param conn: ECOM connection + :param volumeInstance: the volume instance + :returns memberVolumes: a list of meta members + """ + memberVolumes = None + storageSystemName = volumeInstance['SystemName'] + elementCompositionService = self.find_element_composition_service( + conn, storageSystemName) + rc, ret = conn.InvokeMethod( + 'GetCompositeElements', + elementCompositionService, + TheElement=volumeInstance.path) + + if 'OutElements' in ret: + LOG.debug("Get composite elements of volume " + "%(volume)s rc=%(rc)d, ret=%(ret)s", + {'volume': volumeInstance.path, 'rc': rc, 'ret': ret}) + memberVolumes = ret['OutElements'] + return memberVolumes