]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix a merge problem in VMAX driver
authorXing Yang <xing.yang@emc.com>
Fri, 28 Aug 2015 18:56:13 +0000 (14:56 -0400)
committerJohn Griffith <john.griffith8@gmail.com>
Mon, 31 Aug 2015 20:51:37 +0000 (20:51 +0000)
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

cinder/tests/unit/test_emc_vmax.py
cinder/volume/drivers/emc/emc_vmax_common.py
cinder/volume/drivers/emc/emc_vmax_https.py
cinder/volume/drivers/emc/emc_vmax_provision.py
cinder/volume/drivers/emc/emc_vmax_utils.py

index a6447814958d909487255daaf2a9d873bfcc9c41..41be1e0a42927e8fd1bfc9ed27ad3a29eb3d5da1 100644 (file)
@@ -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())
index ae9701d067e4f3094f56a2d2e14a177bc00fdf84..35ff88afcf67634cc4568921ddc0dd4c91ffd816 100644 (file)
@@ -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})
index 154f48b5eb3fa24250e5e739b383db0c1b125547..89a728fe7262207cd6a2c1e9f12a38bbbf6ad8ea 100644 (file)
@@ -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
 
index 6a485e0b88d8116f36aa09ce74c0268f1b46ef1e..0a85b00241d2221c37dd64929e199ec76c7a81d3 100644 (file)
@@ -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,
index 722c33ef81c2ba7daac2e4621f0eaab1b095f138..d4b9f0190d9b1e96655d2818f738194b4a154ed9 100644 (file)
@@ -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