Merge "Support SMI-S provider v8.0.3 in VMAX driver"
This commit is contained in:
commit
427af64e4b
@ -292,6 +292,7 @@ class EMCVMAXCommonData(object):
|
||||
properties = {'ConsumableBlocks': '12345',
|
||||
'BlockSize': '512'}
|
||||
|
||||
block_size = 512
|
||||
test_volume = {'name': 'vol1',
|
||||
'size': 1,
|
||||
'volume_name': 'vol1',
|
||||
@ -306,7 +307,7 @@ class EMCVMAXCommonData(object):
|
||||
'status': 'available',
|
||||
'host': 'fake-host',
|
||||
'NumberOfBlocks': 100,
|
||||
'BlockSize': 512
|
||||
'BlockSize': block_size
|
||||
}
|
||||
|
||||
test_volume_v2 = {'name': 'vol1',
|
||||
@ -323,7 +324,7 @@ class EMCVMAXCommonData(object):
|
||||
'status': 'available',
|
||||
'host': 'fake-host',
|
||||
'NumberOfBlocks': 100,
|
||||
'BlockSize': 512
|
||||
'BlockSize': block_size
|
||||
}
|
||||
|
||||
test_volume_v3 = {'name': 'vol1',
|
||||
@ -340,9 +341,17 @@ class EMCVMAXCommonData(object):
|
||||
'status': 'available',
|
||||
'host': 'fake-host',
|
||||
'NumberOfBlocks': 100,
|
||||
'BlockSize': 512
|
||||
'BlockSize': block_size
|
||||
}
|
||||
|
||||
metaHead_volume = {'DeviceID': 10,
|
||||
'ConsumableBlocks': 1000
|
||||
}
|
||||
meta_volume1 = {'DeviceID': 11,
|
||||
'ConsumableBlocks': 200
|
||||
}
|
||||
meta_volume2 = {'DeviceID': 12,
|
||||
'ConsumableBlocks': 300
|
||||
}
|
||||
test_volume_CG = {'name': 'volInCG',
|
||||
'consistencygroup_id': 'abc',
|
||||
'size': 1,
|
||||
@ -433,6 +442,9 @@ class EMCVMAXCommonData(object):
|
||||
'storagetype:slo': u'Bronze',
|
||||
'storagetype:array': u'0123456789',
|
||||
'isV3': True}
|
||||
majorVersion = 1
|
||||
minorVersion = 2
|
||||
revNumber = 3
|
||||
|
||||
|
||||
class FakeLookupService(object):
|
||||
@ -464,7 +476,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()
|
||||
@ -489,7 +502,7 @@ class FakeEcomConnection(object):
|
||||
|
||||
elif TheElements and \
|
||||
TheElements[0]['DeviceID'] == '99999' and \
|
||||
MethodName == 'EMCReturnToStoragePool':
|
||||
MethodName == 'ReturnElementsToStoragePool':
|
||||
rc = 10
|
||||
myjob['status'] = 'failure'
|
||||
elif HardwareId:
|
||||
@ -517,6 +530,13 @@ class FakeEcomConnection(object):
|
||||
rc = 0
|
||||
ret['HardwareID'] = self.data.iscsi_initiator
|
||||
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
|
||||
@ -559,6 +579,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
|
||||
@ -569,6 +591,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
|
||||
@ -958,7 +982,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
|
||||
@ -975,6 +999,7 @@ class FakeEcomConnection(object):
|
||||
srpstoragepool = SYMM_SrpStoragePool()
|
||||
srpstoragepool['CreationClassName'] = (
|
||||
self.data.srpstoragepool_creationclass)
|
||||
srpstoragepool['ElementName'] = 'SRP_1'
|
||||
|
||||
classcimproperty = Fake_CIMProperty()
|
||||
totalManagedSpace = (
|
||||
@ -1211,6 +1236,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):
|
||||
@ -1461,6 +1511,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 = {}
|
||||
@ -1686,18 +1745,39 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
||||
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],
|
||||
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'
|
||||
@ -1914,19 +1994,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',
|
||||
@ -2650,7 +2730,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,
|
||||
@ -2685,7 +2765,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,
|
||||
@ -2746,7 +2826,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,
|
||||
@ -2906,7 +2986,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,
|
||||
@ -3017,6 +3097,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 _cleanup(self):
|
||||
if self.config_file_path:
|
||||
bExists = os.path.exists(self.config_file_path)
|
||||
@ -3391,7 +3539,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,
|
||||
@ -3429,7 +3577,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,
|
||||
@ -3479,7 +3627,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,
|
||||
@ -4182,7 +4330,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(
|
||||
@ -4215,7 +4363,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(
|
||||
@ -4599,7 +4747,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,
|
||||
@ -4637,7 +4785,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,
|
||||
@ -4706,7 +4854,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,
|
||||
@ -5165,7 +5313,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
|
||||
self.driver.create_cloned_volume(cloneVol, self.data.test_volume)
|
||||
|
||||
@mock.patch.object(
|
||||
|
@ -55,6 +55,7 @@ STRIPECOUNT = 'storagetype:stripecount'
|
||||
MEMBERCOUNT = 'storagetype:membercount'
|
||||
STRIPED = 'striped'
|
||||
CONCATENATED = 'concatenated'
|
||||
SMI_VERSION_8 = 800
|
||||
# V3
|
||||
SLO = 'storagetype:slo'
|
||||
WORKLOAD = 'storagetype:workload'
|
||||
@ -1319,13 +1320,23 @@ 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)
|
||||
try:
|
||||
foundVolumeinstance = self.conn.GetInstance(instancename)
|
||||
except Exception:
|
||||
foundVolumeinstance = None
|
||||
|
||||
if foundVolumeinstance is None:
|
||||
LOG.debug("Volume %(volumename)s not found on the array.",
|
||||
@ -1835,8 +1846,8 @@ class EMCVMAXCommon(object):
|
||||
if 'True' in isVolumeBound:
|
||||
appendVolumeInstance = (
|
||||
self._unbind_and_get_volume_from_storage_pool(
|
||||
conn, storageConfigService, assocPoolInstanceName,
|
||||
appendVolumeInstance.path, 'appendVolume', extraSpecs))
|
||||
conn, storageConfigService, appendVolumeInstance.path,
|
||||
'appendVolume', extraSpecs))
|
||||
|
||||
return appendVolumeInstance
|
||||
|
||||
@ -1862,27 +1873,33 @@ class EMCVMAXCommon(object):
|
||||
return volumeInstance
|
||||
|
||||
def _unbind_and_get_volume_from_storage_pool(
|
||||
self, conn, storageConfigService, poolInstanceName,
|
||||
volumeInstanceName, volumeName, extraSpecs):
|
||||
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 is 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(
|
||||
@ -3334,12 +3351,8 @@ class EMCVMAXCommon(object):
|
||||
controllerConfigurationService,
|
||||
volumeInstance.path, volumeName, extraSpecs)
|
||||
|
||||
LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool "
|
||||
"ConfigService: %(service)s TheElement: %(vol_instance)s "
|
||||
"DeviceId: %(deviceId)s.",
|
||||
{'service': storageConfigService,
|
||||
'name': volumeName,
|
||||
'vol_instance': volumeInstance.path,
|
||||
LOG.debug("Deleting Volume: %(name)s with deviceId: %(deviceId)s.",
|
||||
{'name': volumeName,
|
||||
'deviceId': deviceId})
|
||||
try:
|
||||
rc = self.provision.delete_volume_from_pool(
|
||||
@ -3466,9 +3479,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})
|
||||
|
@ -38,9 +38,10 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
|
||||
2.1.2 - Clean up failed clones (bug #1440154)
|
||||
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
||||
2.2.0 - Add manage/unmanage
|
||||
2.2.1 - Support for SE 8.0.3
|
||||
"""
|
||||
|
||||
VERSION = "2.2.0"
|
||||
VERSION = "2.2.1"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
@ -14,18 +14,18 @@
|
||||
# under the License.
|
||||
|
||||
import base64
|
||||
import httplib
|
||||
import os
|
||||
import socket
|
||||
import ssl
|
||||
import string
|
||||
import struct
|
||||
import urllib
|
||||
|
||||
from eventlet import patcher
|
||||
import OpenSSL
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from six.moves import urllib
|
||||
|
||||
from cinder.i18n import _, _LI
|
||||
|
||||
@ -74,7 +74,7 @@ def get_default_ca_certs():
|
||||
class OpenSSLConnectionDelegator(object):
|
||||
"""An OpenSSL.SSL.Connection delegator.
|
||||
|
||||
Supplies an additional 'makefile' method which http_client requires
|
||||
Supplies an additional 'makefile' method which httplib requires
|
||||
and is not present in OpenSSL.SSL.Connection.
|
||||
Note: Since it is not possible to inherit from OpenSSL.SSL.Connection
|
||||
a delegator must be used.
|
||||
@ -89,7 +89,7 @@ class OpenSSLConnectionDelegator(object):
|
||||
return socket._fileobject(self.connection, *args, **kwargs)
|
||||
|
||||
|
||||
class HTTPSConnection(http_client.HTTPSConnection):
|
||||
class HTTPSConnection(httplib.HTTPSConnection):
|
||||
def __init__(self, host, port=None, key_file=None, cert_file=None,
|
||||
strict=None, ca_certs=None, no_verification=False):
|
||||
if not pywbemAvailable:
|
||||
@ -101,9 +101,9 @@ class HTTPSConnection(http_client.HTTPSConnection):
|
||||
else:
|
||||
excp_lst = ()
|
||||
try:
|
||||
http_client.HTTPSConnection.__init__(self, host, port,
|
||||
key_file=key_file,
|
||||
cert_file=cert_file)
|
||||
httplib.HTTPSConnection.__init__(self, host, port,
|
||||
key_file=key_file,
|
||||
cert_file=cert_file)
|
||||
|
||||
self.key_file = None if key_file is None else key_file
|
||||
self.cert_file = None if cert_file is None else cert_file
|
||||
@ -255,7 +255,7 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
||||
"""Send request over HTTP.
|
||||
|
||||
Send XML data over HTTP to the specified url. Return the
|
||||
response in XML. Uses Python's build-in http_client. x509 may be a
|
||||
response in XML. Uses Python's build-in httplib. x509 may be a
|
||||
dictionary containing the location of the SSL certificate and key
|
||||
files.
|
||||
"""
|
||||
@ -274,7 +274,7 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
||||
localAuthHeader = None
|
||||
tryLimit = 5
|
||||
|
||||
if isinstance(data, six.text_type):
|
||||
if isinstance(data, unicode):
|
||||
data = data.encode('utf-8')
|
||||
data = '<?xml version="1.0" encoding="utf-8" ?>\n' + data
|
||||
|
||||
@ -309,10 +309,10 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
||||
h.putheader('PegasusAuthorization', 'Local "%s"' % locallogin)
|
||||
|
||||
for hdr in headers:
|
||||
if isinstance(hdr, six.text_type):
|
||||
if isinstance(hdr, unicode):
|
||||
hdr = hdr.encode('utf-8')
|
||||
s = map(lambda x: string.strip(x), string.split(hdr, ":", 1))
|
||||
h.putheader(urllib.parse.quote(s[0]), urllib.parse.quote(s[1]))
|
||||
h.putheader(urllib.quote(s[0]), urllib.quote(s[1]))
|
||||
|
||||
try:
|
||||
h.endheaders()
|
||||
@ -328,7 +328,7 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
||||
if response.status != 200:
|
||||
raise pywbem.cim_http.Error('HTTP error')
|
||||
|
||||
except http_client.BadStatusLine as arg:
|
||||
except httplib.BadStatusLine as arg:
|
||||
msg = (_("Bad Status line returned: %(arg)s.")
|
||||
% {'arg': arg})
|
||||
raise pywbem.cim_http.Error(msg)
|
||||
|
@ -46,9 +46,10 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
|
||||
2.1.2 - Clean up failed clones (bug #1440154)
|
||||
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
||||
2.2.0 - Add manage/unmanage
|
||||
2.2.1 - Support for SE 8.0.3
|
||||
"""
|
||||
|
||||
VERSION = "2.2.0"
|
||||
VERSION = "2.2.1"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
@ -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,
|
||||
volumeInstanceName, volumeName, extraSpecs):
|
||||
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:
|
||||
@ -1070,14 +1068,16 @@ class EMCVMAXProvision(object):
|
||||
'relationName': relationName,
|
||||
'srcGroup': srcGroupInstanceName,
|
||||
'tgtGroup': tgtGroupInstanceName})
|
||||
# 8 for clone.
|
||||
# SyncType 8 - clone.
|
||||
# CopyState 4 - Synchronized.
|
||||
rc, job = conn.InvokeMethod(
|
||||
'CreateGroupReplica',
|
||||
replicationService,
|
||||
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,
|
||||
|
@ -1224,13 +1224,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:
|
||||
@ -1622,27 +1623,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):
|
||||
@ -1654,27 +1641,54 @@ 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 storageSystemInstanceName: storage system instance name
|
||||
:param poolname: pool name (string)
|
||||
:returns: foundPoolInstanceName, systemNameStr
|
||||
"""
|
||||
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):
|
||||
try:
|
||||
conn.GetInstance(srpPoolInstanceName)
|
||||
foundPoolInstanceName = srpPoolInstanceName
|
||||
except Exception:
|
||||
foundPoolInstanceName = None
|
||||
# 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):
|
||||
foundPoolInstanceName = poolInstanceName
|
||||
break
|
||||
|
||||
return foundPoolInstanceName, systemNameStr
|
||||
|
||||
def _get_pool_name(self, conn, poolInstanceName):
|
||||
"""The pool name from the instance
|
||||
|
||||
:param conn: the ecom connection
|
||||
:param poolInstanceName: the pool instance
|
||||
:returns: poolnameStr
|
||||
"""
|
||||
poolnameStr = None
|
||||
try:
|
||||
poolInstance = conn.GetInstance(poolInstanceName)
|
||||
poolnameStr = poolInstance['ElementName']
|
||||
except Exception:
|
||||
pass
|
||||
return poolnameStr
|
||||
|
||||
def find_storageSystem(self, conn, arrayStr):
|
||||
"""Find an array instance name given the array name.
|
||||
|
||||
@ -1831,21 +1845,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.
|
||||
@ -2112,3 +2133,48 @@ class EMCVMAXUtils(object):
|
||||
{'source': sourceDeviceId, 'storageSystem': storageSystem})
|
||||
|
||||
return foundSyncInstanceName
|
||||
|
||||
def get_smi_version(self, conn):
|
||||
intVersion = 0
|
||||
swIndentityInstances = conn.EnumerateInstances(
|
||||
'SE_ManagementServerSoftwareIdentity')
|
||||
if swIndentityInstances:
|
||||
swIndentityInstance = swIndentityInstances[0]
|
||||
majorVersion = swIndentityInstance['MajorVersion']
|
||||
minorVersion = swIndentityInstance['MinorVersion']
|
||||
revisionNumber = swIndentityInstance['RevisionNumber']
|
||||
|
||||
intVersion = int(str(majorVersion) + str(minorVersion)
|
||||
+ str(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
|
||||
|
Loading…
Reference in New Issue
Block a user