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',
|
properties = {'ConsumableBlocks': '12345',
|
||||||
'BlockSize': '512'}
|
'BlockSize': '512'}
|
||||||
|
|
||||||
|
block_size = 512
|
||||||
test_volume = {'name': 'vol1',
|
test_volume = {'name': 'vol1',
|
||||||
'size': 1,
|
'size': 1,
|
||||||
'volume_name': 'vol1',
|
'volume_name': 'vol1',
|
||||||
@ -306,7 +307,7 @@ class EMCVMAXCommonData(object):
|
|||||||
'status': 'available',
|
'status': 'available',
|
||||||
'host': 'fake-host',
|
'host': 'fake-host',
|
||||||
'NumberOfBlocks': 100,
|
'NumberOfBlocks': 100,
|
||||||
'BlockSize': 512
|
'BlockSize': block_size
|
||||||
}
|
}
|
||||||
|
|
||||||
test_volume_v2 = {'name': 'vol1',
|
test_volume_v2 = {'name': 'vol1',
|
||||||
@ -323,7 +324,7 @@ class EMCVMAXCommonData(object):
|
|||||||
'status': 'available',
|
'status': 'available',
|
||||||
'host': 'fake-host',
|
'host': 'fake-host',
|
||||||
'NumberOfBlocks': 100,
|
'NumberOfBlocks': 100,
|
||||||
'BlockSize': 512
|
'BlockSize': block_size
|
||||||
}
|
}
|
||||||
|
|
||||||
test_volume_v3 = {'name': 'vol1',
|
test_volume_v3 = {'name': 'vol1',
|
||||||
@ -340,9 +341,17 @@ class EMCVMAXCommonData(object):
|
|||||||
'status': 'available',
|
'status': 'available',
|
||||||
'host': 'fake-host',
|
'host': 'fake-host',
|
||||||
'NumberOfBlocks': 100,
|
'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',
|
test_volume_CG = {'name': 'volInCG',
|
||||||
'consistencygroup_id': 'abc',
|
'consistencygroup_id': 'abc',
|
||||||
'size': 1,
|
'size': 1,
|
||||||
@ -433,6 +442,9 @@ class EMCVMAXCommonData(object):
|
|||||||
'storagetype:slo': u'Bronze',
|
'storagetype:slo': u'Bronze',
|
||||||
'storagetype:array': u'0123456789',
|
'storagetype:array': u'0123456789',
|
||||||
'isV3': True}
|
'isV3': True}
|
||||||
|
majorVersion = 1
|
||||||
|
minorVersion = 2
|
||||||
|
revNumber = 3
|
||||||
|
|
||||||
|
|
||||||
class FakeLookupService(object):
|
class FakeLookupService(object):
|
||||||
@ -464,7 +476,8 @@ class FakeEcomConnection(object):
|
|||||||
Type=None, EMCSRP=None, EMCSLO=None, EMCWorkload=None,
|
Type=None, EMCSRP=None, EMCSLO=None, EMCWorkload=None,
|
||||||
EMCCollections=None, InitiatorMaskingGroup=None,
|
EMCCollections=None, InitiatorMaskingGroup=None,
|
||||||
DeviceMaskingGroup=None, TargetMaskingGroup=None,
|
DeviceMaskingGroup=None, TargetMaskingGroup=None,
|
||||||
ProtocolController=None, StorageID=None, IDType=None):
|
ProtocolController=None, StorageID=None, IDType=None,
|
||||||
|
WaitForCopyState=None):
|
||||||
|
|
||||||
rc = 0
|
rc = 0
|
||||||
myjob = SE_ConcreteJob()
|
myjob = SE_ConcreteJob()
|
||||||
@ -489,7 +502,7 @@ class FakeEcomConnection(object):
|
|||||||
|
|
||||||
elif TheElements and \
|
elif TheElements and \
|
||||||
TheElements[0]['DeviceID'] == '99999' and \
|
TheElements[0]['DeviceID'] == '99999' and \
|
||||||
MethodName == 'EMCReturnToStoragePool':
|
MethodName == 'ReturnElementsToStoragePool':
|
||||||
rc = 10
|
rc = 10
|
||||||
myjob['status'] = 'failure'
|
myjob['status'] = 'failure'
|
||||||
elif HardwareId:
|
elif HardwareId:
|
||||||
@ -517,6 +530,13 @@ class FakeEcomConnection(object):
|
|||||||
rc = 0
|
rc = 0
|
||||||
ret['HardwareID'] = self.data.iscsi_initiator
|
ret['HardwareID'] = self.data.iscsi_initiator
|
||||||
return rc, ret
|
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}
|
job = {'Job': myjob}
|
||||||
return rc, job
|
return rc, job
|
||||||
@ -559,6 +579,8 @@ class FakeEcomConnection(object):
|
|||||||
result = self._enum_repservcpbls()
|
result = self._enum_repservcpbls()
|
||||||
elif name == 'SE_StorageSynchronized_SV_SV':
|
elif name == 'SE_StorageSynchronized_SV_SV':
|
||||||
result = self._enum_storageSyncSvSv()
|
result = self._enum_storageSyncSvSv()
|
||||||
|
elif name == 'Symm_SRPStoragePool':
|
||||||
|
result = self._enum_srpstoragepool()
|
||||||
else:
|
else:
|
||||||
result = self._default_enum()
|
result = self._default_enum()
|
||||||
return result
|
return result
|
||||||
@ -569,6 +591,8 @@ class FakeEcomConnection(object):
|
|||||||
result = self._enum_pool_details()
|
result = self._enum_pool_details()
|
||||||
elif name == 'SE_StorageHardwareID':
|
elif name == 'SE_StorageHardwareID':
|
||||||
result = self._enum_storhdwids()
|
result = self._enum_storhdwids()
|
||||||
|
elif name == 'SE_ManagementServerSoftwareIdentity':
|
||||||
|
result = self._enum_sw_identity()
|
||||||
else:
|
else:
|
||||||
result = self._default_enum()
|
result = self._default_enum()
|
||||||
return result
|
return result
|
||||||
@ -958,7 +982,7 @@ class FakeEcomConnection(object):
|
|||||||
def _getinstance_pool(self, objectpath):
|
def _getinstance_pool(self, objectpath):
|
||||||
pool = {}
|
pool = {}
|
||||||
pool['CreationClassName'] = 'Symm_VirtualProvisioningPool'
|
pool['CreationClassName'] = 'Symm_VirtualProvisioningPool'
|
||||||
pool['ElementName'] = 'gold'
|
pool['ElementName'] = self.data.poolname
|
||||||
pool['SystemName'] = self.data.storage_system
|
pool['SystemName'] = self.data.storage_system
|
||||||
pool['TotalManagedSpace'] = self.data.totalmanagedspace_bits
|
pool['TotalManagedSpace'] = self.data.totalmanagedspace_bits
|
||||||
pool['EMCSubscribedCapacity'] = self.data.subscribedcapacity_bits
|
pool['EMCSubscribedCapacity'] = self.data.subscribedcapacity_bits
|
||||||
@ -975,6 +999,7 @@ class FakeEcomConnection(object):
|
|||||||
srpstoragepool = SYMM_SrpStoragePool()
|
srpstoragepool = SYMM_SrpStoragePool()
|
||||||
srpstoragepool['CreationClassName'] = (
|
srpstoragepool['CreationClassName'] = (
|
||||||
self.data.srpstoragepool_creationclass)
|
self.data.srpstoragepool_creationclass)
|
||||||
|
srpstoragepool['ElementName'] = 'SRP_1'
|
||||||
|
|
||||||
classcimproperty = Fake_CIMProperty()
|
classcimproperty = Fake_CIMProperty()
|
||||||
totalManagedSpace = (
|
totalManagedSpace = (
|
||||||
@ -1211,6 +1236,31 @@ class FakeEcomConnection(object):
|
|||||||
|
|
||||||
vols.append(failed_vol)
|
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
|
return vols
|
||||||
|
|
||||||
def _enum_initiatorMaskingGroup(self):
|
def _enum_initiatorMaskingGroup(self):
|
||||||
@ -1461,6 +1511,15 @@ class FakeEcomConnection(object):
|
|||||||
svInstances.append(svInstance)
|
svInstances.append(svInstance)
|
||||||
return svInstances
|
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):
|
def _default_enum(self):
|
||||||
names = []
|
names = []
|
||||||
name = {}
|
name = {}
|
||||||
@ -1686,18 +1745,39 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
self.assertEqual(storageHardwareIDInstanceNames[0],
|
self.assertEqual(storageHardwareIDInstanceNames[0],
|
||||||
self.data.iscsi_initiator)
|
self.data.iscsi_initiator)
|
||||||
|
|
||||||
def test_format_system_name(self):
|
def test_get_pool_instance_and_system_name(self):
|
||||||
v2array = ['SYMMETRIX', '000195900551', 'U', 'gold']
|
conn = self.fake_ecom_connection()
|
||||||
systemnameV2 = self.driver.utils._format_system_name(v2array[0],
|
# V2 - old '+' separator
|
||||||
v2array[1],
|
storagesystem = {}
|
||||||
'+')
|
storagesystem['SystemName'] = self.data.storage_system
|
||||||
self.assertEqual('SYMMETRIX+000195900551', systemnameV2)
|
storagesystem['Name'] = self.data.storage_system
|
||||||
|
pools = conn.EnumerateInstanceNames("EMC_VirtualProvisioningPool")
|
||||||
v3array = ['SYMMETRIX', '000197200056', 'SRP_1']
|
poolname = 'gold'
|
||||||
systemnameV3 = self.driver.utils._format_system_name(v3array[0],
|
poolinstancename, systemname = (
|
||||||
v3array[1],
|
self.driver.common.utils._get_pool_instance_and_system_name(
|
||||||
'-+-')
|
conn, pools, storagesystem, poolname))
|
||||||
self.assertEqual('SYMMETRIX-+-000197200056', systemnameV3)
|
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):
|
def test_get_hardware_type(self):
|
||||||
iqn_initiator = 'iqn.1992-04.com.emc: 50000973f006dd80'
|
iqn_initiator = 'iqn.1992-04.com.emc: 50000973f006dd80'
|
||||||
@ -1914,19 +1994,19 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
volume2 = EMC_StorageVolume()
|
volume2 = EMC_StorageVolume()
|
||||||
volume2['name'] = 'myVol'
|
volume2['name'] = 'myVol'
|
||||||
volume2['provider_location'] = six.text_type(provider_location2)
|
volume2['provider_location'] = six.text_type(provider_location2)
|
||||||
verify_orig = self.driver.common.utils.get_existing_instance
|
verify_orig = self.driver.common.conn.GetInstance
|
||||||
self.driver.common.utils.get_existing_instance = mock.Mock(
|
self.driver.common.conn.GetInstance = mock.Mock(
|
||||||
return_value=None)
|
return_value=None)
|
||||||
findlun2 = self.driver.common._find_lun(volume2)
|
findlun2 = self.driver.common._find_lun(volume2)
|
||||||
# Not found.
|
# Not found.
|
||||||
self.assertIsNone(findlun2)
|
self.assertIsNone(findlun2)
|
||||||
instancename2 = self.driver.utils.get_instance_name(
|
self.driver.utils.get_instance_name(
|
||||||
provider_location2['classname'],
|
provider_location2['classname'],
|
||||||
keybindings2)
|
keybindings2)
|
||||||
self.driver.common.utils.get_existing_instance.assert_called_once_with(
|
self.driver.common.conn.GetInstance.assert_called_once_with(
|
||||||
self.driver.common.conn, instancename2)
|
keybindings2)
|
||||||
self.driver.common.utils.get_existing_instance.reset_mock()
|
self.driver.common.conn.GetInstance.reset_mock()
|
||||||
self.driver.common.utils.get_existing_instance = verify_orig
|
self.driver.common.conn.GetInstance = verify_orig
|
||||||
|
|
||||||
keybindings3 = {'CreationClassName': u'Symm_StorageVolume',
|
keybindings3 = {'CreationClassName': u'Symm_StorageVolume',
|
||||||
'SystemName': u'SYMMETRIX+000195900551',
|
'SystemName': u'SYMMETRIX+000195900551',
|
||||||
@ -2650,7 +2730,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -2685,7 +2765,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567])
|
return_value=[1234567])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -2746,7 +2826,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
FakeDB,
|
FakeDB,
|
||||||
@ -2906,7 +2986,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -3017,6 +3097,74 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
|||||||
conn, volumeInstance, originalName)
|
conn, volumeInstance, originalName)
|
||||||
self.assertEqual(originalName, volumeInstance['ElementName'])
|
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):
|
def _cleanup(self):
|
||||||
if self.config_file_path:
|
if self.config_file_path:
|
||||||
bExists = os.path.exists(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))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -3429,7 +3577,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567])
|
return_value=[1234567])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -3479,7 +3627,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -4182,7 +4330,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
|
|||||||
'status': 'available',
|
'status': 'available',
|
||||||
'host': self.data.fake_host,
|
'host': self.data.fake_host,
|
||||||
'NumberOfBlocks': 100,
|
'NumberOfBlocks': 100,
|
||||||
'BlockSize': 512
|
'BlockSize': self.data.block_size
|
||||||
}
|
}
|
||||||
common = self.driver.common
|
common = self.driver.common
|
||||||
common._initial_setup = mock.Mock(
|
common._initial_setup = mock.Mock(
|
||||||
@ -4215,7 +4363,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
|
|||||||
'status': 'available',
|
'status': 'available',
|
||||||
'host': self.data.fake_host,
|
'host': self.data.fake_host,
|
||||||
'NumberOfBlocks': 100,
|
'NumberOfBlocks': 100,
|
||||||
'BlockSize': 512
|
'BlockSize': self.data.block_size
|
||||||
}
|
}
|
||||||
common = self.driver.common
|
common = self.driver.common
|
||||||
common._initial_setup = mock.Mock(
|
common._initial_setup = mock.Mock(
|
||||||
@ -4599,7 +4747,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -4637,7 +4785,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567])
|
return_value=[1234567])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -4706,7 +4854,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
|||||||
return_value=(None, EMCVMAXCommonData.storage_system))
|
return_value=(None, EMCVMAXCommonData.storage_system))
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
'get_meta_members_capacity_in_bit',
|
'get_meta_members_capacity_in_byte',
|
||||||
return_value=[1234567, 7654321])
|
return_value=[1234567, 7654321])
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
emc_vmax_utils.EMCVMAXUtils,
|
emc_vmax_utils.EMCVMAXUtils,
|
||||||
@ -5165,7 +5313,7 @@ class EMCV3DriverTestCase(test.TestCase):
|
|||||||
cloneVol['volume_type_id'] = 'abc'
|
cloneVol['volume_type_id'] = 'abc'
|
||||||
cloneVol['provider_location'] = None
|
cloneVol['provider_location'] = None
|
||||||
cloneVol['NumberOfBlocks'] = 100
|
cloneVol['NumberOfBlocks'] = 100
|
||||||
cloneVol['BlockSize'] = 512
|
cloneVol['BlockSize'] = self.data.block_size
|
||||||
self.driver.create_cloned_volume(cloneVol, self.data.test_volume)
|
self.driver.create_cloned_volume(cloneVol, self.data.test_volume)
|
||||||
|
|
||||||
@mock.patch.object(
|
@mock.patch.object(
|
||||||
|
@ -55,6 +55,7 @@ STRIPECOUNT = 'storagetype:stripecount'
|
|||||||
MEMBERCOUNT = 'storagetype:membercount'
|
MEMBERCOUNT = 'storagetype:membercount'
|
||||||
STRIPED = 'striped'
|
STRIPED = 'striped'
|
||||||
CONCATENATED = 'concatenated'
|
CONCATENATED = 'concatenated'
|
||||||
|
SMI_VERSION_8 = 800
|
||||||
# V3
|
# V3
|
||||||
SLO = 'storagetype:slo'
|
SLO = 'storagetype:slo'
|
||||||
WORKLOAD = 'storagetype:workload'
|
WORKLOAD = 'storagetype:workload'
|
||||||
@ -1319,13 +1320,23 @@ class EMCVMAXCommon(object):
|
|||||||
|
|
||||||
if isinstance(loc, six.string_types):
|
if isinstance(loc, six.string_types):
|
||||||
name = eval(loc)
|
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(
|
instancename = self.utils.get_instance_name(
|
||||||
name['classname'], name['keybindings'])
|
name['classname'], name['keybindings'])
|
||||||
|
|
||||||
# Handle the case where volume cannot be found.
|
# Handle the case where volume cannot be found.
|
||||||
foundVolumeinstance = self.utils.get_existing_instance(
|
try:
|
||||||
self.conn, instancename)
|
foundVolumeinstance = self.conn.GetInstance(instancename)
|
||||||
|
except Exception:
|
||||||
|
foundVolumeinstance = None
|
||||||
|
|
||||||
if foundVolumeinstance is None:
|
if foundVolumeinstance is None:
|
||||||
LOG.debug("Volume %(volumename)s not found on the array.",
|
LOG.debug("Volume %(volumename)s not found on the array.",
|
||||||
@ -1835,8 +1846,8 @@ class EMCVMAXCommon(object):
|
|||||||
if 'True' in isVolumeBound:
|
if 'True' in isVolumeBound:
|
||||||
appendVolumeInstance = (
|
appendVolumeInstance = (
|
||||||
self._unbind_and_get_volume_from_storage_pool(
|
self._unbind_and_get_volume_from_storage_pool(
|
||||||
conn, storageConfigService, assocPoolInstanceName,
|
conn, storageConfigService, appendVolumeInstance.path,
|
||||||
appendVolumeInstance.path, 'appendVolume', extraSpecs))
|
'appendVolume', extraSpecs))
|
||||||
|
|
||||||
return appendVolumeInstance
|
return appendVolumeInstance
|
||||||
|
|
||||||
@ -1862,27 +1873,33 @@ class EMCVMAXCommon(object):
|
|||||||
return volumeInstance
|
return volumeInstance
|
||||||
|
|
||||||
def _unbind_and_get_volume_from_storage_pool(
|
def _unbind_and_get_volume_from_storage_pool(
|
||||||
self, conn, storageConfigService, poolInstanceName,
|
self, conn, storageConfigService, volumeInstanceName,
|
||||||
volumeInstanceName, volumeName, extraSpecs):
|
volumeName, extraSpecs):
|
||||||
"""Unbind a volume from a pool and return the unbound volume.
|
"""Unbind a volume from a pool and return the unbound volume.
|
||||||
|
|
||||||
:param conn: the connection information to the ecom server
|
:param conn: the connection information to the ecom server
|
||||||
:param storageConfigService: the storage config service instance name
|
:param storageConfigService: the storage config service instance name
|
||||||
:param poolInstanceName: the pool instance name
|
|
||||||
:param volumeInstanceName: the volume instance name
|
:param volumeInstanceName: the volume instance name
|
||||||
:param volumeName: string the volumeName
|
:param volumeName: string the volumeName
|
||||||
:param extraSpecs: extra specifications
|
:param extraSpecs: extra specifications
|
||||||
:returns: unboundVolumeInstance -- the unbound volume instance
|
:returns: unboundVolumeInstance -- the unbound volume instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_rc, job = (
|
rc, job = (
|
||||||
self.provision.unbind_volume_from_storage_pool(
|
self.provision.unbind_volume_from_storage_pool(
|
||||||
conn, storageConfigService, poolInstanceName,
|
conn, storageConfigService, volumeInstanceName,
|
||||||
volumeInstanceName,
|
|
||||||
volumeName, extraSpecs))
|
volumeName, extraSpecs))
|
||||||
volumeDict = self.provision.get_volume_dict_from_job(conn, job['Job'])
|
# Check that the volume is unbound
|
||||||
volumeInstance = self.utils.find_volume_instance(
|
volumeInstance = conn.GetInstance(volumeInstanceName)
|
||||||
self.conn, volumeDict, volumeName)
|
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
|
return volumeInstance
|
||||||
|
|
||||||
def _modify_and_get_composite_volume_instance(
|
def _modify_and_get_composite_volume_instance(
|
||||||
@ -3334,12 +3351,8 @@ class EMCVMAXCommon(object):
|
|||||||
controllerConfigurationService,
|
controllerConfigurationService,
|
||||||
volumeInstance.path, volumeName, extraSpecs)
|
volumeInstance.path, volumeName, extraSpecs)
|
||||||
|
|
||||||
LOG.debug("Delete Volume: %(name)s Method: EMCReturnToStoragePool "
|
LOG.debug("Deleting Volume: %(name)s with deviceId: %(deviceId)s.",
|
||||||
"ConfigService: %(service)s TheElement: %(vol_instance)s "
|
{'name': volumeName,
|
||||||
"DeviceId: %(deviceId)s.",
|
|
||||||
{'service': storageConfigService,
|
|
||||||
'name': volumeName,
|
|
||||||
'vol_instance': volumeInstance.path,
|
|
||||||
'deviceId': deviceId})
|
'deviceId': deviceId})
|
||||||
try:
|
try:
|
||||||
rc = self.provision.delete_volume_from_pool(
|
rc = self.provision.delete_volume_from_pool(
|
||||||
@ -3466,9 +3479,9 @@ class EMCVMAXCommon(object):
|
|||||||
else: # Composite volume with meta device members.
|
else: # Composite volume with meta device members.
|
||||||
# Check if the meta members capacity.
|
# Check if the meta members capacity.
|
||||||
metaMemberInstanceNames = (
|
metaMemberInstanceNames = (
|
||||||
self.utils.get_meta_members_of_composite_volume(
|
self.utils.get_composite_elements(
|
||||||
self.conn, metaHeadInstanceName))
|
self.conn, sourceInstance))
|
||||||
volumeCapacities = self.utils.get_meta_members_capacity_in_bit(
|
volumeCapacities = self.utils.get_meta_members_capacity_in_byte(
|
||||||
self.conn, metaMemberInstanceNames)
|
self.conn, metaMemberInstanceNames)
|
||||||
LOG.debug("Volume capacities: %(metasizes)s.",
|
LOG.debug("Volume capacities: %(metasizes)s.",
|
||||||
{'metasizes': volumeCapacities})
|
{'metasizes': volumeCapacities})
|
||||||
|
@ -38,9 +38,10 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
|
|||||||
2.1.2 - Clean up failed clones (bug #1440154)
|
2.1.2 - Clean up failed clones (bug #1440154)
|
||||||
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
||||||
2.2.0 - Add manage/unmanage
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
@ -14,18 +14,18 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import httplib
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import string
|
import string
|
||||||
import struct
|
import struct
|
||||||
|
import urllib
|
||||||
|
|
||||||
from eventlet import patcher
|
from eventlet import patcher
|
||||||
import OpenSSL
|
import OpenSSL
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
from six.moves import http_client
|
|
||||||
from six.moves import urllib
|
|
||||||
|
|
||||||
from cinder.i18n import _, _LI
|
from cinder.i18n import _, _LI
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ def get_default_ca_certs():
|
|||||||
class OpenSSLConnectionDelegator(object):
|
class OpenSSLConnectionDelegator(object):
|
||||||
"""An OpenSSL.SSL.Connection delegator.
|
"""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.
|
and is not present in OpenSSL.SSL.Connection.
|
||||||
Note: Since it is not possible to inherit from OpenSSL.SSL.Connection
|
Note: Since it is not possible to inherit from OpenSSL.SSL.Connection
|
||||||
a delegator must be used.
|
a delegator must be used.
|
||||||
@ -89,7 +89,7 @@ class OpenSSLConnectionDelegator(object):
|
|||||||
return socket._fileobject(self.connection, *args, **kwargs)
|
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,
|
def __init__(self, host, port=None, key_file=None, cert_file=None,
|
||||||
strict=None, ca_certs=None, no_verification=False):
|
strict=None, ca_certs=None, no_verification=False):
|
||||||
if not pywbemAvailable:
|
if not pywbemAvailable:
|
||||||
@ -101,9 +101,9 @@ class HTTPSConnection(http_client.HTTPSConnection):
|
|||||||
else:
|
else:
|
||||||
excp_lst = ()
|
excp_lst = ()
|
||||||
try:
|
try:
|
||||||
http_client.HTTPSConnection.__init__(self, host, port,
|
httplib.HTTPSConnection.__init__(self, host, port,
|
||||||
key_file=key_file,
|
key_file=key_file,
|
||||||
cert_file=cert_file)
|
cert_file=cert_file)
|
||||||
|
|
||||||
self.key_file = None if key_file is None else key_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
|
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 request over HTTP.
|
||||||
|
|
||||||
Send XML data over HTTP to the specified url. Return the
|
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
|
dictionary containing the location of the SSL certificate and key
|
||||||
files.
|
files.
|
||||||
"""
|
"""
|
||||||
@ -274,7 +274,7 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
|||||||
localAuthHeader = None
|
localAuthHeader = None
|
||||||
tryLimit = 5
|
tryLimit = 5
|
||||||
|
|
||||||
if isinstance(data, six.text_type):
|
if isinstance(data, unicode):
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
data = '<?xml version="1.0" encoding="utf-8" ?>\n' + data
|
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)
|
h.putheader('PegasusAuthorization', 'Local "%s"' % locallogin)
|
||||||
|
|
||||||
for hdr in headers:
|
for hdr in headers:
|
||||||
if isinstance(hdr, six.text_type):
|
if isinstance(hdr, unicode):
|
||||||
hdr = hdr.encode('utf-8')
|
hdr = hdr.encode('utf-8')
|
||||||
s = map(lambda x: string.strip(x), string.split(hdr, ":", 1))
|
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:
|
try:
|
||||||
h.endheaders()
|
h.endheaders()
|
||||||
@ -328,7 +328,7 @@ def wbem_request(url, data, creds, headers=None, debug=0, x509=None,
|
|||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
raise pywbem.cim_http.Error('HTTP error')
|
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.")
|
msg = (_("Bad Status line returned: %(arg)s.")
|
||||||
% {'arg': arg})
|
% {'arg': arg})
|
||||||
raise pywbem.cim_http.Error(msg)
|
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.2 - Clean up failed clones (bug #1440154)
|
||||||
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
2.1.3 - Fixed a problem with FAST support (bug #1435069)
|
||||||
2.2.0 - Add manage/unmanage
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class EMCVMAXProvision(object):
|
|||||||
theElements = [volumeInstanceName]
|
theElements = [volumeInstanceName]
|
||||||
|
|
||||||
rc, job = conn.InvokeMethod(
|
rc, job = conn.InvokeMethod(
|
||||||
'EMCReturnToStoragePool', storageConfigservice,
|
'ReturnElementsToStoragePool', storageConfigservice,
|
||||||
TheElements=theElements)
|
TheElements=theElements)
|
||||||
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
@ -338,14 +338,13 @@ class EMCVMAXProvision(object):
|
|||||||
time.time())})
|
time.time())})
|
||||||
|
|
||||||
def unbind_volume_from_storage_pool(
|
def unbind_volume_from_storage_pool(
|
||||||
self, conn, storageConfigService, poolInstanceName,
|
self, conn, storageConfigService, volumeInstanceName,
|
||||||
volumeInstanceName, volumeName, extraSpecs):
|
volumeName, extraSpecs):
|
||||||
"""Unbind a volume from a pool and return the unbound volume.
|
"""Unbind a volume from a pool and return the unbound volume.
|
||||||
|
|
||||||
:param conn: the connection information to the ecom server
|
:param conn: the connection information to the ecom server
|
||||||
:param storageConfigService: the storage configuration service
|
:param storageConfigService: the storage configuration service
|
||||||
instance name
|
instance name
|
||||||
:param poolInstanceName: the pool instance name
|
|
||||||
:param volumeInstanceName: the volume instance name
|
:param volumeInstanceName: the volume instance name
|
||||||
:param volumeName: the volume name
|
:param volumeName: the volume name
|
||||||
:param extraSpecs: additional info
|
:param extraSpecs: additional info
|
||||||
@ -358,7 +357,6 @@ class EMCVMAXProvision(object):
|
|||||||
rc, job = conn.InvokeMethod(
|
rc, job = conn.InvokeMethod(
|
||||||
'EMCUnBindElement',
|
'EMCUnBindElement',
|
||||||
storageConfigService,
|
storageConfigService,
|
||||||
InPool=poolInstanceName,
|
|
||||||
TheElement=volumeInstanceName)
|
TheElement=volumeInstanceName)
|
||||||
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
@ -1070,14 +1068,16 @@ class EMCVMAXProvision(object):
|
|||||||
'relationName': relationName,
|
'relationName': relationName,
|
||||||
'srcGroup': srcGroupInstanceName,
|
'srcGroup': srcGroupInstanceName,
|
||||||
'tgtGroup': tgtGroupInstanceName})
|
'tgtGroup': tgtGroupInstanceName})
|
||||||
# 8 for clone.
|
# SyncType 8 - clone.
|
||||||
|
# CopyState 4 - Synchronized.
|
||||||
rc, job = conn.InvokeMethod(
|
rc, job = conn.InvokeMethod(
|
||||||
'CreateGroupReplica',
|
'CreateGroupReplica',
|
||||||
replicationService,
|
replicationService,
|
||||||
RelationshipName=relationName,
|
RelationshipName=relationName,
|
||||||
SourceGroup=srcGroupInstanceName,
|
SourceGroup=srcGroupInstanceName,
|
||||||
TargetGroup=tgtGroupInstanceName,
|
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:
|
if rc != 0:
|
||||||
rc, errordesc = self.utils.wait_for_job_complete(conn, job,
|
rc, errordesc = self.utils.wait_for_job_complete(conn, job,
|
||||||
|
@ -1224,13 +1224,14 @@ class EMCVMAXUtils(object):
|
|||||||
LOG.debug(
|
LOG.debug(
|
||||||
"storagePoolName: %(poolName)s, storageSystemName: %(array)s.",
|
"storagePoolName: %(poolName)s, storageSystemName: %(array)s.",
|
||||||
{'poolName': storagePoolName, 'array': storageSystemName})
|
{'poolName': storagePoolName, 'array': storageSystemName})
|
||||||
poolInstanceNames = conn.EnumerateInstanceNames(
|
storageSystemInstanceName = self.find_storageSystem(conn,
|
||||||
'EMC_VirtualProvisioningPool')
|
storageSystemName)
|
||||||
|
poolInstanceNames = conn.AssociatorNames(
|
||||||
|
storageSystemInstanceName,
|
||||||
|
ResultClass='EMC_VirtualProvisioningPool')
|
||||||
for poolInstanceName in poolInstanceNames:
|
for poolInstanceName in poolInstanceNames:
|
||||||
poolName, systemName = (
|
poolName = self._get_pool_name(conn, poolInstanceName)
|
||||||
self.parse_pool_instance_id(poolInstanceName['InstanceID']))
|
if (poolName == storagePoolName):
|
||||||
if (poolName == storagePoolName and
|
|
||||||
storageSystemName in systemName):
|
|
||||||
# Check that the pool hasn't been recently deleted.
|
# Check that the pool hasn't been recently deleted.
|
||||||
instance = self.get_existing_instance(conn, poolInstanceName)
|
instance = self.get_existing_instance(conn, poolInstanceName)
|
||||||
if instance is None:
|
if instance is None:
|
||||||
@ -1622,27 +1623,13 @@ class EMCVMAXUtils(object):
|
|||||||
:returns: foundPoolInstanceName
|
:returns: foundPoolInstanceName
|
||||||
:returns: string -- systemNameStr
|
:returns: string -- systemNameStr
|
||||||
"""
|
"""
|
||||||
foundPoolInstanceName = None
|
|
||||||
vpoolInstanceNames = conn.AssociatorNames(
|
vpoolInstanceNames = conn.AssociatorNames(
|
||||||
storageSystemInstanceName,
|
storageSystemInstanceName,
|
||||||
ResultClass='EMC_VirtualProvisioningPool')
|
ResultClass='EMC_VirtualProvisioningPool')
|
||||||
|
|
||||||
for vpoolInstanceName in vpoolInstanceNames:
|
return self._get_pool_instance_and_system_name(
|
||||||
poolInstanceId = vpoolInstanceName['InstanceID']
|
conn, vpoolInstanceNames, storageSystemInstanceName,
|
||||||
# Example: SYMMETRIX+000195900551+TP+Sol_Innov
|
poolNameInStr)
|
||||||
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
|
|
||||||
|
|
||||||
def get_pool_and_system_name_v3(
|
def get_pool_and_system_name_v3(
|
||||||
self, conn, storageSystemInstanceName, poolNameInStr):
|
self, conn, storageSystemInstanceName, poolNameInStr):
|
||||||
@ -1654,27 +1641,54 @@ class EMCVMAXUtils(object):
|
|||||||
:returns: foundPoolInstanceName
|
:returns: foundPoolInstanceName
|
||||||
:returns: string -- systemNameStr
|
:returns: string -- systemNameStr
|
||||||
"""
|
"""
|
||||||
foundPoolInstanceName = None
|
|
||||||
srpPoolInstanceNames = conn.AssociatorNames(
|
srpPoolInstanceNames = conn.AssociatorNames(
|
||||||
storageSystemInstanceName,
|
storageSystemInstanceName,
|
||||||
ResultClass='Symm_SRPStoragePool')
|
ResultClass='Symm_SRPStoragePool')
|
||||||
|
|
||||||
for srpPoolInstanceName in srpPoolInstanceNames:
|
return self._get_pool_instance_and_system_name(
|
||||||
poolInstanceID = srpPoolInstanceName['InstanceID']
|
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
|
# Example: SYMMETRIX-+-000196700535-+-SR-+-SRP_1
|
||||||
poolnameStr, systemNameStr = self.parse_pool_instance_id_v3(
|
# Example: SYMMETRIX+000195900551+TP+Sol_Innov
|
||||||
poolInstanceID)
|
poolnameStr = self._get_pool_name(conn, poolInstanceName)
|
||||||
if poolnameStr is not None and systemNameStr is not None:
|
if poolnameStr is not None:
|
||||||
if six.text_type(poolNameInStr) == six.text_type(poolnameStr):
|
if six.text_type(poolname) == six.text_type(poolnameStr):
|
||||||
try:
|
foundPoolInstanceName = poolInstanceName
|
||||||
conn.GetInstance(srpPoolInstanceName)
|
|
||||||
foundPoolInstanceName = srpPoolInstanceName
|
|
||||||
except Exception:
|
|
||||||
foundPoolInstanceName = None
|
|
||||||
break
|
break
|
||||||
|
|
||||||
return foundPoolInstanceName, systemNameStr
|
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):
|
def find_storageSystem(self, conn, arrayStr):
|
||||||
"""Find an array instance name given the array name.
|
"""Find an array instance name given the array name.
|
||||||
|
|
||||||
@ -1831,21 +1845,28 @@ class EMCVMAXUtils(object):
|
|||||||
LOG.debug("metaMembers: %(members)s.", {'members': metaMembers})
|
LOG.debug("metaMembers: %(members)s.", {'members': metaMembers})
|
||||||
return metaMembers
|
return metaMembers
|
||||||
|
|
||||||
def get_meta_members_capacity_in_bit(self, conn, volumeInstanceNames):
|
def get_meta_members_capacity_in_byte(self, conn, volumeInstanceNames):
|
||||||
"""Get the capacity in bits of all meta device member volumes.
|
"""Get the capacity in byte of all meta device member volumes.
|
||||||
|
|
||||||
:param conn: the ecom connection
|
:param conn: the ecom connection
|
||||||
:param volumeInstanceNames: array contains meta device member volumes
|
:param volumeInstanceNames: array contains meta device member volumes
|
||||||
:returns: array contains capacities of each member device in bits
|
: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:
|
for volumeInstanceName in volumeInstanceNames:
|
||||||
volumeInstance = conn.GetInstance(volumeInstanceName)
|
volumeInstance = conn.GetInstance(volumeInstanceName)
|
||||||
numOfBlocks = volumeInstance['ConsumableBlocks']
|
numOfBlocks = volumeInstance['ConsumableBlocks']
|
||||||
blockSize = volumeInstance['BlockSize']
|
blockSize = volumeInstance['BlockSize']
|
||||||
volumeSizeInbits = numOfBlocks * blockSize
|
volumeSizeInByte = numOfBlocks * blockSize
|
||||||
capacitiesInBit.append(volumeSizeInbits)
|
capacitiesInByte.append(volumeSizeInByte)
|
||||||
return capacitiesInBit
|
totalSizeInByte = totalSizeInByte - volumeSizeInByte
|
||||||
|
|
||||||
|
capacitiesInByte.insert(0, totalSizeInByte)
|
||||||
|
return capacitiesInByte
|
||||||
|
|
||||||
def get_existing_instance(self, conn, instanceName):
|
def get_existing_instance(self, conn, instanceName):
|
||||||
"""Check that the instance name still exists and return the instance.
|
"""Check that the instance name still exists and return the instance.
|
||||||
@ -2112,3 +2133,48 @@ class EMCVMAXUtils(object):
|
|||||||
{'source': sourceDeviceId, 'storageSystem': storageSystem})
|
{'source': sourceDeviceId, 'storageSystem': storageSystem})
|
||||||
|
|
||||||
return foundSyncInstanceName
|
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…
x
Reference in New Issue
Block a user