]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add multiple pools support to VMAX driver
authorXing Yang <xing.yang@emc.com>
Wed, 10 Jun 2015 00:57:32 +0000 (20:57 -0400)
committerXing Yang <xing.yang@emc.com>
Mon, 3 Aug 2015 20:17:48 +0000 (16:17 -0400)
This patch adds multiple pools support to the VMAX driver.

Also changed \ to () in a few places.

implements blueprint emc-vmax-multiple-pools

Change-Id: Iae0c658c808168fa5279b8dbcc6734632a98642d

cinder/tests/unit/test_emc_vmax.py
cinder/volume/drivers/emc/emc_vmax_common.py
cinder/volume/drivers/emc/emc_vmax_fast.py
cinder/volume/drivers/emc/emc_vmax_fc.py
cinder/volume/drivers/emc/emc_vmax_https.py
cinder/volume/drivers/emc/emc_vmax_iscsi.py
cinder/volume/drivers/emc/emc_vmax_masking.py
cinder/volume/drivers/emc/emc_vmax_provision.py
cinder/volume/drivers/emc/emc_vmax_provision_v3.py
cinder/volume/drivers/emc/emc_vmax_utils.py

index 768f68bb069669a77c8c64f50100b4ab363874e9..4652eb88914dbb60fcc3087db8ebf87b282dcbaa 100644 (file)
@@ -231,15 +231,13 @@ class EMCVMAXCommonData(object):
     storage_system = 'SYMMETRIX+000195900551'
     storage_system_v3 = 'SYMMETRIX-+-000197200056'
     port_group = 'OS-portgroup-PG'
-    lunmaskctrl_id = \
-        'SYMMETRIX+000195900551+OS-fakehost-gold-MV'
-    lunmaskctrl_name = \
-        'OS-fakehost-gold-MV'
-
-    initiatorgroup_id = \
-        'SYMMETRIX+000195900551+OS-fakehost-IG'
-    initiatorgroup_name = \
-        'OS-fakehost-IG'
+    lunmaskctrl_id = (
+        'SYMMETRIX+000195900551+OS-fakehost-gold-MV')
+    lunmaskctrl_name = 'OS-fakehost-gold-MV'
+
+    initiatorgroup_id = (
+        'SYMMETRIX+000195900551+OS-fakehost-IG')
+    initiatorgroup_name = 'OS-fakehost-IG'
     initiatorgroup_creationclass = 'SE_InitiatorMaskingGroup'
     iscsi_initiator = 'iqn.1993-08.org.debian'
     storageextent_creationclass = 'CIM_StorageExtent'
@@ -273,6 +271,9 @@ class EMCVMAXCommonData(object):
     totalmanagedspace_gbs = 931
     subscribedcapacity_gbs = 466
     fake_host = 'HostX@Backend#gold+1234567891011'
+    fake_host_v3 = 'HostX@Backend#Bronze+SRP_1+1234567891011'
+    fake_host_2_v3 = 'HostY@Backend#SRP_1+1234567891011'
+
     unit_creationclass = 'CIM_ProtocolControllerForUnit'
     storage_type = 'gold'
     keybindings = {'CreationClassName': u'Symm_StorageVolume',
@@ -288,11 +289,13 @@ class EMCVMAXCommonData(object):
                          'keybindings': keybindings}
     provider_location2 = {'classname': 'Symm_StorageVolume',
                           'keybindings': keybindings2}
+    provider_location_multi_pool = {'classname': 'Symm_StorageVolume',
+                                    'keybindings': keybindings,
+                                    'version': '2.2.0'}
 
     properties = {'ConsumableBlocks': '12345',
                   'BlockSize': '512'}
 
-    block_size = 512
     test_volume = {'name': 'vol1',
                    'size': 1,
                    'volume_name': 'vol1',
@@ -305,9 +308,9 @@ class EMCVMAXCommonData(object):
                    'volume_type_id': 'abc',
                    'provider_location': six.text_type(provider_location),
                    'status': 'available',
-                   'host': 'fake-host',
+                   'host': fake_host,
                    'NumberOfBlocks': 100,
-                   'BlockSize': block_size
+                   'BlockSize': 512
                    }
 
     test_volume_v2 = {'name': 'vol1',
@@ -322,9 +325,9 @@ class EMCVMAXCommonData(object):
                       'volume_type_id': 'abc',
                       'provider_location': six.text_type(provider_location),
                       'status': 'available',
-                      'host': 'fake-host',
+                      'host': fake_host,
                       'NumberOfBlocks': 100,
-                      'BlockSize': block_size
+                      'BlockSize': 512
                       }
 
     test_volume_v3 = {'name': 'vol1',
@@ -339,19 +342,11 @@ class EMCVMAXCommonData(object):
                       'volume_type_id': 'abc',
                       'provider_location': six.text_type(provider_location),
                       'status': 'available',
-                      'host': 'fake-host',
+                      'host': fake_host_v3,
                       'NumberOfBlocks': 100,
-                      'BlockSize': block_size
+                      'BlockSize': 512
                       }
-    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,
@@ -366,9 +361,26 @@ class EMCVMAXCommonData(object):
                       'volume_type_id': 'abc',
                       'provider_location': six.text_type(provider_location),
                       'status': 'available',
-                      'host': 'fake-host'
+                      'host': fake_host
                       }
 
+    test_volume_CG_v3 = {'name': 'volInCG',
+                         'consistencygroup_id': 'abc',
+                         'size': 1,
+                         'volume_name': 'volInCG',
+                         'id': 'volInCG',
+                         'device_id': '1',
+                         'provider_auth': None,
+                         'project_id': 'project',
+                         'display_name': 'volInCG',
+                         'display_description':
+                         'test volume in Consistency group',
+                         'volume_type_id': 'abc',
+                         'provider_location':
+                         six.text_type(provider_location),
+                         'status': 'available',
+                         'host': fake_host_v3}
+
     test_failed_volume = {'name': 'failed_vol',
                           'size': 1,
                           'volume_name': 'failed_vol',
@@ -378,7 +390,8 @@ class EMCVMAXCommonData(object):
                           'project_id': 'project',
                           'display_name': 'failed_vol',
                           'display_description': 'test failed volume',
-                          'volume_type_id': 'abc'}
+                          'volume_type_id': 'abc',
+                          'host': fake_host}
 
     failed_delete_vol = {'name': 'failed_delete_vol',
                          'size': '-1',
@@ -390,8 +403,9 @@ class EMCVMAXCommonData(object):
                          'display_name': 'failed delete vol',
                          'display_description': 'failed delete volume',
                          'volume_type_id': 'abc',
-                         'provider_location': six.text_type(provider_location2)
-                         }
+                         'provider_location':
+                         six.text_type(provider_location2),
+                         'host': fake_host}
 
     test_source_volume = {'size': 1,
                           'volume_type_id': 'sourceid',
@@ -403,19 +417,35 @@ class EMCVMAXCommonData(object):
                           'provider_auth': None,
                           'project_id':
                           'project', 'id': '2',
+                          'host': fake_host,
                           'provider_location':
                           six.text_type(provider_location),
                           'display_description': 'snapshot source volume'}
 
+    test_source_volume_v3 = {'size': 1,
+                             'volume_type_id': 'sourceid',
+                             'display_name': 'sourceVolume',
+                             'name': 'sourceVolume',
+                             'id': 'sourceVolume',
+                             'device_id': '1',
+                             'volume_name': 'vmax-154326',
+                             'provider_auth': None,
+                             'project_id':
+                             'project', 'id': '2',
+                             'host': fake_host_v3,
+                             'provider_location':
+                             six.text_type(provider_location),
+                             'display_description': 'snapshot source volume'}
+
     test_CG = {'name': 'myCG1',
                'id': '12345abcde',
                'volume_type_id': 'abc',
-               'status': 'available',
-               'host': 'fake-host'
+               'status': 'available'
                }
     test_snapshot = {'name': 'myCG1',
                      'id': '12345abcde',
-                     'status': 'available'
+                     'status': 'available',
+                     'host': fake_host
                      }
     test_CG_snapshot = {'name': 'testSnap',
                         'id': '12345abcde',
@@ -425,13 +455,12 @@ class EMCVMAXCommonData(object):
                         }
     location_info = {'location_info': '000195900551#silver#None',
                      'storage_protocol': 'ISCSI'}
+    location_info_v3 = {'location_info': '1234567891011#SRP_1#Bronze#DSS',
+                        'storage_protocol': 'FC'}
     test_host = {'capabilities': location_info,
                  'host': 'fake_host'}
-
-    location_info_v3 = {'location_info': '0123456789#SRP_1#Bronze#DSS',
-                        'storage_protocol': 'FC'}
     test_host_v3 = {'capabilities': location_info_v3,
-                    'host': 'fake_v3_host'}
+                    'host': fake_host_2_v3}
     initiatorNames = ["123456789012345", "123456789054321"]
     test_ctxt = {}
     new_type = {}
@@ -440,11 +469,10 @@ class EMCVMAXCommonData(object):
                    'volume_backend_name': 'V3_BE',
                    'storagetype:workload': u'DSS',
                    'storagetype:slo': u'Bronze',
-                   'storagetype:array': u'0123456789',
-                   'isV3': True}
-    majorVersion = 1
-    minorVersion = 2
-    revNumber = 3
+                   'storagetype:array': u'1234567891011',
+                   'isV3': True,
+                   'portgroupname': u'OS-portgroup-PG'}
+    remainingSLOCapacity = '123456789'
 
 
 class FakeLookupService(object):
@@ -476,8 +504,7 @@ 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,
-                     WaitForCopyState=None):
+                     ProtocolController=None, StorageID=None, IDType=None):
 
         rc = 0
         myjob = SE_ConcreteJob()
@@ -486,8 +513,8 @@ class FakeEcomConnection(object):
         myjob['status'] = 'success'
         myjob['type'] = ElementName
 
-        if Size == -1073741824 and \
-                MethodName == 'CreateOrModifyCompositeElement':
+        if Size == -1073741824 and (
+                MethodName == 'CreateOrModifyCompositeElement'):
             rc = 0
             myjob = SE_ConcreteJob()
             myjob.classname = 'SE_ConcreteJob'
@@ -495,14 +522,13 @@ class FakeEcomConnection(object):
             myjob['status'] = 'success'
             myjob['type'] = 'failed_delete_vol'
 
-        if ElementName == 'failed_vol' and \
-                MethodName == 'CreateOrModifyElementFromStoragePool':
+        if ElementName == 'failed_vol' and (
+                MethodName == 'CreateOrModifyElementFromStoragePool'):
             rc = 10
             myjob['status'] = 'failure'
 
-        elif TheElements and \
-                TheElements[0]['DeviceID'] == '99999' and \
-                MethodName == 'ReturnElementsToStoragePool':
+        elif TheElements and TheElements[0]['DeviceID'] == '99999' and (
+                MethodName == 'EMCReturnToStoragePool'):
             rc = 10
             myjob['status'] = 'failure'
         elif HardwareId:
@@ -519,8 +545,8 @@ class FakeEcomConnection(object):
             endpoints.append(endpoint2)
             targetendpoints['TargetEndpoints'] = endpoints
             return rc, targetendpoints
-        elif ReplicationType and \
-                MethodName == 'GetDefaultReplicationSettingData':
+        elif ReplicationType and (
+                MethodName == 'GetDefaultReplicationSettingData'):
             rc = 0
             rsd = SE_ReplicationSettingData()
             rsd['DefaultInstance'] = SE_ReplicationSettingData()
@@ -530,12 +556,11 @@ class FakeEcomConnection(object):
             rc = 0
             ret['HardwareID'] = self.data.iscsi_initiator
             return rc, ret
-        elif MethodName == 'GetCompositeElements':
+        if MethodName == 'GetSupportedSizeRange':
             ret = {}
             rc = 0
-            ret['OutElements'] = [self.data.metaHead_volume,
-                                  self.data.meta_volume1,
-                                  self.data.meta_volume2]
+            ret['EMCInformationSource'] = 3
+            ret['EMCRemainingSLOCapacity'] = self.data.remainingSLOCapacity
             return rc, ret
 
         job = {'Job': myjob}
@@ -579,8 +604,6 @@ 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
@@ -591,8 +614,6 @@ 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
@@ -982,7 +1003,7 @@ class FakeEcomConnection(object):
     def _getinstance_pool(self, objectpath):
         pool = {}
         pool['CreationClassName'] = 'Symm_VirtualProvisioningPool'
-        pool['ElementName'] = self.data.poolname
+        pool['ElementName'] = 'gold'
         pool['SystemName'] = self.data.storage_system
         pool['TotalManagedSpace'] = self.data.totalmanagedspace_bits
         pool['EMCSubscribedCapacity'] = self.data.subscribedcapacity_bits
@@ -999,7 +1020,6 @@ class FakeEcomConnection(object):
         srpstoragepool = SYMM_SrpStoragePool()
         srpstoragepool['CreationClassName'] = (
             self.data.srpstoragepool_creationclass)
-        srpstoragepool['ElementName'] = 'SRP_1'
 
         classcimproperty = Fake_CIMProperty()
         totalManagedSpace = (
@@ -1093,28 +1113,38 @@ class FakeEcomConnection(object):
 
     def _enum_stconfsvcs(self):
         conf_services = []
-        conf_service = {}
-        conf_service['SystemName'] = self.data.storage_system
-        conf_service['CreationClassName'] = \
-            self.data.stconf_service_creationclass
-        conf_services.append(conf_service)
+        conf_service1 = {}
+        conf_service1['SystemName'] = self.data.storage_system
+        conf_service1['CreationClassName'] = (
+            self.data.stconf_service_creationclass)
+        conf_services.append(conf_service1)
+        conf_service2 = {}
+        conf_service2['SystemName'] = self.data.storage_system_v3
+        conf_service2['CreationClassName'] = (
+            self.data.stconf_service_creationclass)
+        conf_services.append(conf_service2)
         return conf_services
 
     def _enum_ctrlconfsvcs(self):
         conf_services = []
         conf_service = {}
         conf_service['SystemName'] = self.data.storage_system
-        conf_service['CreationClassName'] = \
-            self.data.ctrlconf_service_creationclass
+        conf_service['CreationClassName'] = (
+            self.data.ctrlconf_service_creationclass)
         conf_services.append(conf_service)
+        conf_service1 = {}
+        conf_service1['SystemName'] = self.data.storage_system_v3
+        conf_service1['CreationClassName'] = (
+            self.data.ctrlconf_service_creationclass)
+        conf_services.append(conf_service1)
         return conf_services
 
     def _enum_elemcompsvcs(self):
         comp_services = []
         comp_service = {}
         comp_service['SystemName'] = self.data.storage_system
-        comp_service['CreationClassName'] = \
-            self.data.elementcomp_service_creationclass
+        comp_service['CreationClassName'] = (
+            self.data.elementcomp_service_creationclass)
         comp_services.append(comp_service)
         return comp_services
 
@@ -1122,8 +1152,8 @@ class FakeEcomConnection(object):
         reloc_services = []
         reloc_service = {}
         reloc_service['SystemName'] = self.data.storage_system
-        reloc_service['CreationClassName'] = \
-            self.data.storreloc_service_creationclass
+        reloc_service['CreationClassName'] = (
+            self.data.storreloc_service_creationclass)
         reloc_services.append(reloc_service)
         return reloc_services
 
@@ -1131,8 +1161,8 @@ class FakeEcomConnection(object):
         replic_services = []
         replic_service = {}
         replic_service['SystemName'] = self.data.storage_system
-        replic_service['CreationClassName'] = \
-            self.data.replication_service_creationclass
+        replic_service['CreationClassName'] = (
+            self.data.replication_service_creationclass)
         replic_services.append(replic_service)
         replic_service2 = {}
         replic_service2['SystemName'] = self.data.storage_system_v3
@@ -1144,8 +1174,8 @@ class FakeEcomConnection(object):
     def _enum_pools(self):
         pools = []
         pool = {}
-        pool['InstanceID'] = self.data.storage_system + '+U+' + \
-            self.data.storage_type
+        pool['InstanceID'] = (
+            self.data.storage_system + '+U+' + self.data.storage_type)
         pool['CreationClassName'] = 'Symm_VirtualProvisioningPool'
         pool['ElementName'] = 'gold'
         pools.append(pool)
@@ -1154,8 +1184,8 @@ class FakeEcomConnection(object):
     def _enum_pool_details(self):
         pools = []
         pool = {}
-        pool['InstanceID'] = self.data.storage_system + '+U+' + \
-            self.data.storage_type
+        pool['InstanceID'] = (
+            self.data.storage_system + '+U+' + self.data.storage_type)
         pool['CreationClassName'] = 'Symm_VirtualProvisioningPool'
         pool['TotalManagedSpace'] = 12345678
         pool['RemainingManagedSpace'] = 123456
@@ -1213,8 +1243,8 @@ class FakeEcomConnection(object):
         # Added vol to vol.path
         failed_delete_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
         failed_delete_vol.path = failed_delete_vol
-        failed_delete_vol.path.classname = \
-            failed_delete_vol['CreationClassName']
+        failed_delete_vol.path.classname = (
+            failed_delete_vol['CreationClassName'])
         vols.append(failed_delete_vol)
 
         failed_vol = EMC_StorageVolume()
@@ -1226,8 +1256,7 @@ class FakeEcomConnection(object):
         # Added vol to vol.path
         failed_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
         failed_vol.path = failed_vol
-        failed_vol.path.classname = \
-            failed_vol['CreationClassName']
+        failed_vol.path.classname = failed_vol['CreationClassName']
 
         name_failed = {}
         name_failed['classname'] = 'Symm_StorageVolume'
@@ -1241,31 +1270,6 @@ 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):
@@ -1516,15 +1520,6 @@ 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 = {}
@@ -1541,7 +1536,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         self.tempdir = tempfile.mkdtemp()
         super(EMCVMAXISCSIDriverNoFastTestCase, self).setUp()
         self.config_file_path = None
-        self.config_file_1364232 = None
         self.create_fake_config_file_no_fast()
         self.addCleanup(self._cleanup)
 
@@ -1581,19 +1575,20 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         doc.writexml(f)
         f.close()
 
-    def create_fake_config_file_no_fast_with_add_ons(self):
+    def create_fake_config_file_no_fast_with_interval_retries(self):
 
         doc = minidom.Document()
         emc = doc.createElement("EMC")
         doc.appendChild(emc)
         doc = self.add_array_info(doc, emc)
         doc = self.add_interval_and_retries(doc, emc)
-        filename = 'cinder_emc_config_ISCSINoFAST.xml'
-        self.config_file_path = self.tempdir + '/' + filename
+        filename = 'cinder_emc_config_ISCSINoFAST_int_ret.xml'
+        config_file_path = self.tempdir + '/' + filename
 
         f = open(self.config_file_path, 'w')
         doc.writexml(f)
         f.close()
+        return config_file_path
 
     def create_fake_config_file_no_fast_with_interval(self):
 
@@ -1602,12 +1597,13 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         doc.appendChild(emc)
         doc = self.add_array_info(doc, emc)
         doc = self.add_interval_only(doc, emc)
-        filename = 'cinder_emc_config_ISCSINoFAST.xml'
-        self.config_file_path = self.tempdir + '/' + filename
+        filename = 'cinder_emc_config_ISCSINoFAST_int.xml'
+        config_file_path = self.tempdir + '/' + filename
 
         f = open(self.config_file_path, 'w')
         doc.writexml(f)
         f.close()
+        return config_file_path
 
     def create_fake_config_file_no_fast_with_retries(self):
 
@@ -1616,12 +1612,13 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         doc.appendChild(emc)
         doc = self.add_array_info(doc, emc)
         doc = self.add_retries_only(doc, emc)
-        filename = 'cinder_emc_config_ISCSINoFAST.xml'
-        self.config_file_path = self.tempdir + '/' + filename
+        filename = 'cinder_emc_config_ISCSINoFAST_ret.xml'
+        config_file_path = self.tempdir + '/' + filename
 
         f = open(self.config_file_path, 'w')
         doc.writexml(f)
         f.close()
+        return config_file_path
 
     def add_array_info(self, doc, emc):
         array = doc.createElement("Array")
@@ -1663,7 +1660,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         pool.appendChild(pooltext)
 
         array = doc.createElement("Array")
-        arraytext = doc.createTextNode("0123456789")
+        arraytext = doc.createTextNode("1234567891011")
         emc.appendChild(array)
         array.appendChild(arraytext)
 
@@ -1702,8 +1699,8 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     # fix for https://bugs.launchpad.net/cinder/+bug/1364232
     def create_fake_config_file_1364232(self):
         filename = 'cinder_emc_config_1364232.xml'
-        self.config_file_1364232 = self.tempdir + '/' + filename
-        text_file = open(self.config_file_1364232, "w")
+        config_file_1364232 = self.tempdir + '/' + filename
+        text_file = open(config_file_1364232, "w")
         text_file.write("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
                         "<EcomServerIp>10.10.10.10</EcomServerIp>\n"
                         "<EcomServerPort>5988</EcomServerPort>\n"
@@ -1719,6 +1716,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
                         "</Pool>\n<FastPolicy>SILVER1</FastPolicy>\n"
                         "</EMC>")
         text_file.close()
+        return config_file_1364232
 
     def fake_ecom_connection(self):
         conn = FakeEcomConnection()
@@ -1750,39 +1748,18 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         self.assertEqual(storageHardwareIDInstanceNames[0],
                          self.data.iscsi_initiator)
 
-    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_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_hardware_type(self):
         iqn_initiator = 'iqn.1992-04.com.emc: 50000973f006dd80'
@@ -1916,6 +1893,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     def test_wait_for_sync(self):
         mysync = 'fakesync'
         conn = self.fake_ecom_connection()
+
         self.driver.utils._is_sync_complete = mock.Mock(
             return_value=True)
         rc = self.driver.utils.wait_for_sync(conn, mysync)
@@ -1940,11 +1918,15 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     def test_wait_for_sync_extra_specs(self):
         mysync = 'fakesync'
         conn = self.fake_ecom_connection()
-        self.create_fake_config_file_no_fast_with_add_ons()
+        file_name = (
+            self.create_fake_config_file_no_fast_with_interval_retries())
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+        extraSpecs = self.driver.common._set_v2_extra_specs(extraSpecs,
+                                                            poolRec)
 
         self.driver.utils._is_sync_complete = mock.Mock(
             return_value=True)
@@ -1970,6 +1952,9 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
             mock.ANY)
         loopingcall.FixedIntervalLoopingCall.reset_mock()
         loopingcall.FixedIntervalLoopingCall = loopingcall_orig
+        bExists = os.path.exists(file_name)
+        if bExists:
+            os.remove(file_name)
 
     # Bug 1395830: _find_lun throws exception when lun is not found.
     def test_find_lun(self):
@@ -1999,19 +1984,19 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         volume2 = EMC_StorageVolume()
         volume2['name'] = 'myVol'
         volume2['provider_location'] = six.text_type(provider_location2)
-        verify_orig = self.driver.common.conn.GetInstance
-        self.driver.common.conn.GetInstance = mock.Mock(
+        verify_orig = self.driver.common.utils.get_existing_instance
+        self.driver.common.utils.get_existing_instance = mock.Mock(
             return_value=None)
         findlun2 = self.driver.common._find_lun(volume2)
         # Not found.
         self.assertIsNone(findlun2)
-        self.driver.utils.get_instance_name(
+        instancename2 = self.driver.utils.get_instance_name(
             provider_location2['classname'],
             keybindings2)
-        self.driver.common.conn.GetInstance.assert_called_once_with(
-            keybindings2)
-        self.driver.common.conn.GetInstance.reset_mock()
-        self.driver.common.conn.GetInstance = verify_orig
+        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
 
         keybindings3 = {'CreationClassName': u'Symm_StorageVolume',
                         'SystemName': u'SYMMETRIX+000195900551',
@@ -2031,9 +2016,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     # Bug 1403160 - make sure the masking view is cleanly deleted
     def test_last_volume_delete_masking_view(self):
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
         conn = self.fake_ecom_connection()
         controllerConfigService = (
             self.driver.utils.find_controller_configuration_service(
@@ -2074,10 +2056,8 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         volumeInstanceName = (
             conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
         volumeName = "1403160-Vol"
-        extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        extraSpecs = {'volume_backend_name': 'GOLD_BE',
+                      'isV3': False}
 
         # Deleting Storage Group failed
         self.assertRaises(
@@ -2372,41 +2352,49 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         self.assertIsNone(foundPoolInstanceName2)
 
     def test_get_volume_stats_1364232(self):
-        self.create_fake_config_file_1364232()
+        file_name = self.create_fake_config_file_1364232()
+
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(file_name)
         self.assertEqual(
-            '000198700439',
-            self.driver.utils.parse_array_name_from_file(
-                self.config_file_1364232))
+            '000198700439', arrayInfo[0]['SerialNumber'])
         self.assertEqual(
-            'FC_SLVR1',
-            self.driver.utils.parse_pool_name_from_file(
-                self.config_file_1364232))
+            'FC_SLVR1', arrayInfo[0]['PoolName'])
         self.assertEqual(
-            'SILVER1',
-            self.driver.utils.parse_fast_policy_name_from_file(
-                self.config_file_1364232))
+            'SILVER1', arrayInfo[0]['FastPolicy'])
         self.assertTrue(
-            'OS-PORTGROUP' in
-            self.driver.utils.parse_file_to_get_port_group_name(
-                self.config_file_1364232))
+            'OS-PORTGROUP' in arrayInfo[0]['PortGroup'])
+        bExists = os.path.exists(file_name)
+        if bExists:
+            os.remove(file_name)
 
     def test_intervals_and_retries_override(
             self):
-        self.create_fake_config_file_no_fast_with_add_ons()
+        file_name = (
+            self.create_fake_config_file_no_fast_with_interval_retries())
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+        extraSpecs = self.driver.common._set_v2_extra_specs(extraSpecs,
+                                                            poolRec)
         self.assertEqual(40,
                          self.driver.utils._get_max_job_retries(extraSpecs))
         self.assertEqual(5,
                          self.driver.utils._get_interval_in_secs(extraSpecs))
 
+        bExists = os.path.exists(file_name)
+        if bExists:
+            os.remove(file_name)
+
     def test_intervals_and_retries_default(self):
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+        extraSpecs = self.driver.common._set_v2_extra_specs(extraSpecs,
+                                                            poolRec)
         self.assertEqual(60,
                          self.driver.utils._get_max_job_retries(extraSpecs))
         self.assertEqual(10,
@@ -2414,34 +2402,44 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
 
     def test_interval_only(self):
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        self.create_fake_config_file_no_fast_with_interval()
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        file_name = self.create_fake_config_file_no_fast_with_interval()
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+        extraSpecs = self.driver.common._set_v2_extra_specs(extraSpecs,
+                                                            poolRec)
         self.assertEqual(60,
                          self.driver.utils._get_max_job_retries(extraSpecs))
         self.assertEqual(20,
                          self.driver.utils._get_interval_in_secs(extraSpecs))
 
+        bExists = os.path.exists(file_name)
+        if bExists:
+            os.remove(file_name)
+
     def test_retries_only(self):
         extraSpecs = {'volume_backend_name': 'ISCSINoFAST'}
-        self.create_fake_config_file_no_fast_with_retries()
-        extraSpecs = (
-            self.driver.common._get_job_extra_specs(self.config_file_path,
-                                                    extraSpecs))
+        file_name = self.create_fake_config_file_no_fast_with_retries()
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+        extraSpecs = self.driver.common._set_v2_extra_specs(extraSpecs,
+                                                            poolRec)
         self.assertEqual(70,
                          self.driver.utils._get_max_job_retries(extraSpecs))
         self.assertEqual(10,
                          self.driver.utils._get_interval_in_secs(extraSpecs))
 
+        bExists = os.path.exists(file_name)
+        if bExists:
+            os.remove(file_name)
+
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
         'isArrayV3',
         return_value=False)
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_array_name_from_file',
-        return_value="123456789")
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
         'get_pool_capacities',
@@ -2458,7 +2456,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
                                       mock_storage_system,
                                       mock_is_fast_enabled,
                                       mock_capacity,
-                                      mock_array,
                                       mock_is_v3):
         self.driver.get_volume_stats(True)
 
@@ -2530,14 +2527,15 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         notfound_delete_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
         notfound_delete_vol['volume_type_id'] = 'abc'
         notfound_delete_vol['provider_location'] = None
+        notfound_delete_vol['host'] = self.data.fake_host
         name = {}
         name['classname'] = 'Symm_StorageVolume'
         keys = {}
         keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
         keys['SystemName'] = notfound_delete_vol['SystemName']
         keys['DeviceID'] = notfound_delete_vol['DeviceID']
-        keys['SystemCreationClassName'] = \
-            notfound_delete_vol['SystemCreationClassName']
+        keys['SystemCreationClassName'] = (
+            notfound_delete_vol['SystemCreationClassName'])
         name['keybindings'] = keys
 
         self.driver.delete_volume(notfound_delete_vol)
@@ -2735,7 +2733,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -2770,7 +2768,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -2831,7 +2829,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         FakeDB,
@@ -3042,7 +3040,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -3153,83 +3151,11 @@ 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)
             if bExists:
                 os.remove(self.config_file_path)
-        if self.config_file_1364232:
-            bExists = os.path.exists(self.config_file_1364232)
-            if bExists:
-                os.remove(self.config_file_1364232)
         shutil.rmtree(self.tempdir)
 
 
@@ -3316,11 +3242,6 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
         emc.appendChild(pool)
         pool.appendChild(pooltext)
 
-        array = doc.createElement("Array")
-        arraytext = doc.createTextNode("0123456789")
-        emc.appendChild(array)
-        array.appendChild(arraytext)
-
         portgroups = doc.createElement("PortGroups")
         portgroups.appendChild(portgroup)
         emc.appendChild(portgroups)
@@ -3349,10 +3270,6 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
     def fake_is_v3(self, conn, serialNumber):
         return False
 
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_array_name_from_file',
-        return_value="123456789")
     @mock.patch.object(
         emc_vmax_fast.EMCVMAXFast,
         'get_capacities_associated_to_policy',
@@ -3373,8 +3290,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
                                    mock_storage_system,
                                    mock_is_fast_enabled,
                                    mock_get_policy,
-                                   mock_capacity,
-                                   mock_array):
+                                   mock_capacity):
         self.driver.get_volume_stats(True)
 
     @mock.patch.object(
@@ -3460,14 +3376,15 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
         notfound_delete_vol['SystemName'] = self.data.storage_system
         notfound_delete_vol['DeviceID'] = notfound_delete_vol['id']
         notfound_delete_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
+        notfound_delete_vol['host'] = self.data.fake_host
         name = {}
         name['classname'] = 'Symm_StorageVolume'
         keys = {}
         keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
         keys['SystemName'] = notfound_delete_vol['SystemName']
         keys['DeviceID'] = notfound_delete_vol['DeviceID']
-        keys['SystemCreationClassName'] = \
-            notfound_delete_vol['SystemCreationClassName']
+        keys['SystemCreationClassName'] = (
+            notfound_delete_vol['SystemCreationClassName'])
         name['keybindings'] = keys
         notfound_delete_vol['volume_type_id'] = 'abc'
         notfound_delete_vol['provider_location'] = None
@@ -3595,7 +3512,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -3633,7 +3550,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -3683,7 +3600,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -3953,11 +3870,6 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
         emc.appendChild(pool)
         pool.appendChild(pooltext)
 
-        array = doc.createElement("Array")
-        arraytext = doc.createTextNode("0123456789")
-        emc.appendChild(array)
-        array.appendChild(arraytext)
-
         timeout = doc.createElement("Timeout")
         timeouttext = doc.createTextNode("0")
         emc.appendChild(timeout)
@@ -3981,14 +3893,6 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
     def fake_is_v3(self, conn, serialNumber):
         return False
 
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'isArrayV3',
-        return_value=False)
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_array_name_from_file',
-        return_value="123456789")
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
         'get_pool_capacities',
@@ -4004,9 +3908,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
     def test_get_volume_stats_no_fast(self,
                                       mock_storage_system,
                                       mock_is_fast_enabled,
-                                      mock_capacity,
-                                      mock_array,
-                                      mock_is_v3):
+                                      mock_capacity):
         self.driver.get_volume_stats(True)
 
     @mock.patch.object(
@@ -4075,14 +3977,15 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
         notfound_delete_vol['SystemName'] = self.data.storage_system
         notfound_delete_vol['DeviceID'] = notfound_delete_vol['id']
         notfound_delete_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
+        notfound_delete_vol['host'] = self.data.fake_host
         name = {}
         name['classname'] = 'Symm_StorageVolume'
         keys = {}
         keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
         keys['SystemName'] = notfound_delete_vol['SystemName']
         keys['DeviceID'] = notfound_delete_vol['DeviceID']
-        keys['SystemCreationClassName'] = \
-            notfound_delete_vol['SystemCreationClassName']
+        keys['SystemCreationClassName'] = (
+            notfound_delete_vol['SystemCreationClassName'])
         name['keybindings'] = keys
         notfound_delete_vol['volume_type_id'] = 'abc'
         notfound_delete_vol['provider_location'] = None
@@ -4312,38 +4215,6 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
         self.driver.delete_cgsnapshot(
             self.data.test_ctxt, self.data.test_CG_snapshot)
 
-    def create_fake_config_file_parse_port_group(self):
-        filename = 'cinder_emc_config_file_parse_port_group.xml'
-        self.config_file_parse_port_group = self.tempdir + '/' + filename
-        text_file = open(self.config_file_parse_port_group, "w")
-        text_file.write(
-            "<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
-            "<EcomServerIp>10.108.246.202</EcomServerIp>\n"
-            "<EcomServerPort>5988</EcomServerPort>\n"
-            "<EcomUserName>admin\t</EcomUserName>\n"
-            "<EcomPassword>#1Password</EcomPassword>\n"
-            "<PortGroups><PortGroup>OS-PORTGROUP1-PG\r\n"
-            "</PortGroup>\n"
-            "<PortGroup></PortGroup>\n"
-            "<PortGroup> </PortGroup>\n"
-            "<PortGroup></PortGroup>\n"
-            "</PortGroups>\n<Array>000198700439"
-            "              \n</Array>\n<Pool>FC_SLVR1\n"
-            "</Pool>\n<FastPolicy>SILVER1</FastPolicy>\n"
-            "</EMC>")
-        text_file.close()
-
-    def test_get_port_group_parser(self):
-        self.create_fake_config_file_parse_port_group()
-        for _var in range(0, 10):
-            self.assertEqual(
-                u'OS-PORTGROUP1-PG',
-                self.driver.utils.parse_file_to_get_port_group_name(
-                    self.config_file_parse_port_group))
-        bExists = os.path.exists(self.config_file_parse_port_group)
-        if bExists:
-            os.remove(self.config_file_parse_port_group)
-
     def test_manage_existing_get_size(self):
         volume = {}
         metadata = {'key': 'array',
@@ -4430,7 +4301,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
                   'status': 'available',
                   'host': self.data.fake_host,
                   'NumberOfBlocks': 100,
-                  'BlockSize': self.data.block_size
+                  'BlockSize': 512
                   }
         common = self.driver.common
         common._initial_setup = mock.Mock(
@@ -4463,7 +4334,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
                   'status': 'available',
                   'host': self.data.fake_host,
                   'NumberOfBlocks': 100,
-                  'BlockSize': self.data.block_size
+                  'BlockSize': 512
                   }
         common = self.driver.common
         common._initial_setup = mock.Mock(
@@ -4556,7 +4427,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
         pool.appendChild(pooltext)
 
         array = doc.createElement("Array")
-        arraytext = doc.createTextNode("0123456789")
+        arraytext = doc.createTextNode("1234567891011")
         emc.appendChild(array)
         array.appendChild(arraytext)
 
@@ -4587,10 +4458,6 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
     def fake_is_v3(self, conn, serialNumber):
         return False
 
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_array_name_from_file',
-        return_value="123456789")
     @mock.patch.object(
         emc_vmax_fast.EMCVMAXFast,
         'get_capacities_associated_to_policy',
@@ -4611,8 +4478,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
                                    mock_storage_system,
                                    mock_is_fast_enabled,
                                    mock_get_policy,
-                                   mock_capacity,
-                                   mock_array):
+                                   mock_capacity):
         self.driver.get_volume_stats(True)
 
     @mock.patch.object(
@@ -4694,14 +4560,15 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
         notfound_delete_vol['SystemName'] = self.data.storage_system
         notfound_delete_vol['DeviceID'] = notfound_delete_vol['id']
         notfound_delete_vol['SystemCreationClassName'] = 'Symm_StorageSystem'
+        notfound_delete_vol['host'] = self.data.fake_host
         name = {}
         name['classname'] = 'Symm_StorageVolume'
         keys = {}
         keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
         keys['SystemName'] = notfound_delete_vol['SystemName']
         keys['DeviceID'] = notfound_delete_vol['DeviceID']
-        keys['SystemCreationClassName'] = \
-            notfound_delete_vol['SystemCreationClassName']
+        keys['SystemCreationClassName'] = (
+            notfound_delete_vol['SystemCreationClassName'])
         name['keybindings'] = keys
         notfound_delete_vol['volume_type_id'] = 'abc'
         notfound_delete_vol['provider_location'] = None
@@ -4846,7 +4713,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -4876,7 +4743,11 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
             mock.Mock(return_value=True))
         self.driver.create_snapshot(self.data.test_volume)
 
-    def test_create_snapshot_fast_failed(self):
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_validate_pool',
+        return_value=('Bogus_Pool'))
+    def test_create_snapshot_fast_failed(self, mock_pool):
         self.data.test_volume['volume_name'] = "vmax-1234567"
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_snapshot,
@@ -4884,7 +4755,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -4953,7 +4824,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
         return_value=(None, EMCVMAXCommonData.storage_system))
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
-        'get_meta_members_capacity_in_byte',
+        'get_meta_members_capacity_in_bit',
         return_value=[1234567, 7654321])
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -5146,9 +5017,11 @@ class EMCV3DriverTestCase(test.TestCase):
         self.tempdir = tempfile.mkdtemp()
         super(EMCV3DriverTestCase, self).setUp()
         self.config_file_path = None
-        self.create_fake_config_file_fast()
+        self.create_fake_config_file_v3()
         self.addCleanup(self._cleanup)
+        self.set_configuration()
 
+    def set_configuration(self):
         configuration = mock.Mock()
         configuration.cinder_emc_config_file = self.config_file_path
         configuration.safe_get.return_value = 'V3'
@@ -5168,7 +5041,7 @@ class EMCV3DriverTestCase(test.TestCase):
         driver.db = FakeDB()
         self.driver = driver
 
-    def create_fake_config_file_fast(self):
+    def create_fake_config_file_v3(self):
 
         doc = minidom.Document()
         emc = doc.createElement("EMC")
@@ -5204,7 +5077,7 @@ class EMCV3DriverTestCase(test.TestCase):
         pool.appendChild(pooltext)
 
         array = doc.createElement("Array")
-        arraytext = doc.createTextNode("0123456789")
+        arraytext = doc.createTextNode("1234567891011")
         emc.appendChild(array)
         array.appendChild(arraytext)
 
@@ -5245,27 +5118,39 @@ class EMCV3DriverTestCase(test.TestCase):
     def fake_is_v3(self, conn, serialNumber):
         return True
 
+    def default_extraspec(self):
+        return {'storagetype:pool': 'SRP_1',
+                'volume_backend_name': 'V3_BE',
+                'storagetype:workload': 'DSS',
+                'storagetype:slo': 'Bronze',
+                'storagetype:array': '1234567891011',
+                'isV3': True,
+                'portgroupname': 'OS-portgroup-PG'}
+
+    def test_initial_setup(self):
+        self.driver.common._register_config_file_from_config_group = (
+            mock.Mock(return_value=self.config_file_path))
+        extraSpecs = (
+            self.driver.common._initial_setup(self.data.test_volume_v3))
+        self.assertEqual('SRP_1', extraSpecs['storagetype:pool'])
+        self.assertEqual('DSS', extraSpecs['storagetype:workload'])
+        self.assertEqual('Bronze', extraSpecs['storagetype:slo'])
+        self.assertEqual('1234567891011', extraSpecs['storagetype:array'])
+        self.assertEqual('OS-portgroup-PG', extraSpecs['portgroupname'])
+        self.assertTrue(extraSpecs['isV3'])
+
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
         'isArrayV3',
         return_value=True)
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_array_name_from_file',
-        return_value="123456789")
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
         'find_storageSystem',
         return_value=None)
     def test_get_volume_stats_v3(
-            self, mock_storage_system, mock_array, mock_is_v3):
+            self, mock_storage_system, mock_is_v3):
         self.driver.get_volume_stats(True)
 
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5275,18 +5160,12 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_create_volume_v3_success(
-            self, _mock_volume_type, mock_storage_system, mock_range):
+            self, _mock_volume_type, mock_storage_system):
+        self.data.test_volume_v3['host'] = self.data.fake_host_v3
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         self.driver.create_volume(self.data.test_volume_v3)
 
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_slo_from_file',
-        return_value='NONE')
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5296,19 +5175,21 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_create_volume_v3_no_slo_success(
-            self, _mock_volume_type, mock_storage_system,
-            mock_range, mock_slo):
-        self.driver.create_volume(self.data.test_volume_v3)
+            self, _mock_volume_type, mock_storage_system):
+        v3_vol = self.data.test_volume_v3
+        v3_vol['host'] = 'HostX@Backend#NONE+SRP_1+1234567891011'
+        extraSpecs = {'storagetype:pool': 'SRP_1',
+                      'volume_backend_name': 'V3_BE',
+                      'storagetype:workload': 'DSS',
+                      'storagetype:slo': 'NONE',
+                      'storagetype:array': '1234567891011',
+                      'isV3': True,
+                      'portgroupname': 'OS-portgroup-PG'}
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=extraSpecs)
+
+        self.driver.create_volume(v3_vol)
 
-    @mock.patch.object(
-        emc_vmax_utils.EMCVMAXUtils,
-        'parse_slo_from_file',
-        return_value='Bogus')
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5318,17 +5199,21 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_create_volume_v3_invalid_slo_failed(
-            self, _mock_volume_type, mock_storage_system,
-            mock_range, mock_slo):
+            self, _mock_volume_type, mock_storage_system):
+        extraSpecs = {'storagetype:pool': 'SRP_1',
+                      'volume_backend_name': 'V3_BE',
+                      'storagetype:workload': 'DSS',
+                      'storagetype:slo': 'Bogus',
+                      'storagetype:array': '1234567891011',
+                      'isV3': True,
+                      'portgroupname': 'OS-portgroup-PG'}
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=extraSpecs)
+
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_volume,
                           self.data.test_volume)
 
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5338,21 +5223,20 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_create_volume_in_CG_v3_success(
-            self, _mock_volume_type, mock_storage_system, mock_range):
-        self.driver.create_volume(self.data.test_volume_CG)
+            self, _mock_volume_type, mock_storage_system):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_volume(self.data.test_volume_CG_v3)
 
     @mock.patch.object(
         volume_types,
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_delete_volume_v3_success(self, _mock_volume_type):
-        self.driver.delete_volume(self.data.test_volume)
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.delete_volume(self.data.test_volume_v3)
 
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5364,29 +5248,28 @@ class EMCV3DriverTestCase(test.TestCase):
     @mock.patch.object(
         FakeDB,
         'volume_get',
-        return_value=EMCVMAXCommonData.test_source_volume)
+        return_value=EMCVMAXCommonData.test_source_volume_v3)
     def test_create_snapshot_v3_success(
-            self, mock_volume_db, mock_type, moke_pool, mock_siz):
-        self.data.test_volume['volume_name'] = "vmax-1234567"
-        self.driver.create_snapshot(self.data.test_volume)
+            self, mock_volume_db, mock_type, moke_pool):
+        self.data.test_volume_v3['volume_name'] = "vmax-1234567"
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_snapshot(self.data.test_volume_v3)
 
     @mock.patch.object(
         FakeDB,
         'volume_get',
-        return_value=EMCVMAXCommonData.test_source_volume)
+        return_value=EMCVMAXCommonData.test_source_volume_v3)
     @mock.patch.object(
         volume_types,
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_delete_snapshot_v3_success(self, mock_volume_type, mock_db):
-        self.data.test_volume['volume_name'] = "vmax-1234567"
-        self.driver.delete_snapshot(self.data.test_volume)
+        self.data.test_volume_v3['volume_name'] = "vmax-1234567"
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.delete_snapshot(self.data.test_volume_v3)
 
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5400,8 +5283,8 @@ class EMCV3DriverTestCase(test.TestCase):
         'volume_get',
         return_value=EMCVMAXCommonData.test_source_volume)
     def test_create_cloned_volume_v3_success(
-            self, mock_volume_db, mock_type, moke_pool, mock_size):
-        self.data.test_volume['volume_name'] = "vmax-1234567"
+            self, mock_volume_db, mock_type, moke_pool):
+        self.data.test_volume_v3['volume_name'] = "vmax-1234567"
         cloneVol = {}
         cloneVol['name'] = 'vol1'
         cloneVol['id'] = '10'
@@ -5412,8 +5295,11 @@ class EMCV3DriverTestCase(test.TestCase):
         cloneVol['volume_type_id'] = 'abc'
         cloneVol['provider_location'] = None
         cloneVol['NumberOfBlocks'] = 100
-        cloneVol['BlockSize'] = self.data.block_size
-        self.driver.create_cloned_volume(cloneVol, self.data.test_volume)
+        cloneVol['BlockSize'] = 512
+        cloneVol['host'] = self.data.fake_host_v3
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_cloned_volume(cloneVol, self.data.test_volume_v3)
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -5426,7 +5312,7 @@ class EMCV3DriverTestCase(test.TestCase):
     def test_create_CG_v3_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.create_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_volume_CG_v3)
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -5468,6 +5354,8 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_migrate_volume_v3_success(self, _mock_volume_type):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         self.driver.migrate_volume(self.data.test_ctxt, self.data.test_volume,
                                    self.data.test_host)
 
@@ -5490,8 +5378,10 @@ class EMCV3DriverTestCase(test.TestCase):
     def test_retype_volume_v3_success(
             self, _mock_volume_type, mock_fast_settings,
             mock_storage_group, mock_found_SG):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         self.assertTrue(self.driver.retype(
-            self.data.test_ctxt, self.data.test_volume, self.data.new_type,
+            self.data.test_ctxt, self.data.test_volume_v3, self.data.new_type,
             self.data.diff, self.data.test_host_v3))
 
     @mock.patch.object(
@@ -5504,8 +5394,10 @@ class EMCV3DriverTestCase(test.TestCase):
         return_value={'volume_backend_name': 'V3_BE'})
     def test_retype_volume_same_host_failure(
             self, _mock_volume_type, mock_fast_settings):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         self.assertFalse(self.driver.retype(
-            self.data.test_ctxt, self.data.test_volume, self.data.new_type,
+            self.data.test_ctxt, self.data.test_volume_v3, self.data.new_type,
             self.data.diff, self.data.test_host_v3))
 
     @mock.patch.object(
@@ -5623,8 +5515,10 @@ class EMCV3DriverTestCase(test.TestCase):
         common = self.driver.common
         common.get_target_wwns = mock.Mock(
             return_value=EMCVMAXCommonData.target_wwns)
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         data = self.driver.initialize_connection(
-            self.data.test_volume, self.data.connector)
+            self.data.test_volume_v3, self.data.connector)
         # Test the no lookup service, pre-zoned case.
         common.get_target_wwns.assert_called_once_with(
             EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
@@ -5640,6 +5534,8 @@ class EMCV3DriverTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'V3_BE'})
     def test_map_v3_failed(self, _mock_volume_type, mock_wrap_device):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.initialize_connection,
                           self.data.test_volume,
@@ -5670,7 +5566,9 @@ class EMCV3DriverTestCase(test.TestCase):
         common = self.driver.common
         common.get_target_wwns = mock.Mock(
             return_value=EMCVMAXCommonData.target_wwns)
-        data = self.driver.terminate_connection(self.data.test_volume,
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        data = self.driver.terminate_connection(self.data.test_volume_v3,
                                                 self.data.connector)
         common.get_target_wwns.assert_called_once_with(
             EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
@@ -5678,11 +5576,6 @@ class EMCV3DriverTestCase(test.TestCase):
         self.assertEqual(numTargetWwns, len(data['data']))
 
     # Bug https://bugs.launchpad.net/cinder/+bug/1440154
-    @mock.patch.object(
-        emc_vmax_provision_v3.EMCVMAXProvisionV3,
-        '_get_supported_size_range_for_SLO',
-        return_value={'MaximumVolumeSize': '30000000000',
-                      'MinimumVolumeSize': '100000'})
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
         '_get_pool_and_storage_system',
@@ -5694,7 +5587,7 @@ class EMCV3DriverTestCase(test.TestCase):
     @mock.patch.object(
         FakeDB,
         'volume_get',
-        return_value=EMCVMAXCommonData.test_source_volume)
+        return_value=EMCVMAXCommonData.test_source_volume_v3)
     @mock.patch.object(
         emc_vmax_provision_v3.EMCVMAXProvisionV3,
         'create_element_replica')
@@ -5704,7 +5597,7 @@ class EMCV3DriverTestCase(test.TestCase):
         return_value=(None, None))
     def test_create_clone_v3_assert_clean_up_target_volume(
             self, mock_sync, mock_create_replica, mock_volume_db,
-            mock_type, moke_pool, mock_size):
+            mock_type, moke_pool):
         self.data.test_volume['volume_name'] = "vmax-1234567"
         e = exception.VolumeBackendAPIException('CreateElementReplica Ex')
         common = self.driver.common
@@ -5713,17 +5606,18 @@ class EMCV3DriverTestCase(test.TestCase):
         common._create_v3_volume = (
             mock.Mock(return_value=(0, volumeDict, self.data.storage_system)))
         conn = self.fake_ecom_connection()
+        storageConfigService = []
         storageConfigService = {}
         storageConfigService['SystemName'] = EMCVMAXCommonData.storage_system
-        storageConfigService['CreationClassName'] = \
-            self.data.stconf_service_creationclass
+        storageConfigService['CreationClassName'] = (
+            self.data.stconf_service_creationclass)
         common._delete_from_pool_v3 = mock.Mock(return_value=0)
         mock_create_replica.side_effect = e
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_cloned_volume,
-                          self.data.test_volume,
-                          EMCVMAXCommonData.test_source_volume)
-        extraSpecs = common._initial_setup(self.data.test_volume)
+                          self.data.test_volume_v3,
+                          EMCVMAXCommonData.test_source_volume_v3)
+        extraSpecs = common._initial_setup(self.data.test_volume_v3)
         targetInstance = (
             conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
         storageGroupName = common.utils.get_v3_storage_group_name('SRP_1',
@@ -5737,6 +5631,930 @@ class EMCV3DriverTestCase(test.TestCase):
                                                        storageGroupName,
                                                        extraSpecs)
 
+    def test_get_remaining_slo_capacity_wlp(self):
+        conn = self.fake_ecom_connection()
+        array_info = {'Workload': u'DSS', 'SLO': u'Bronze'}
+        storagesystem = self.data.storage_system_v3
+        srpPoolInstanceName = {}
+        srpPoolInstanceName['InstanceID'] = (
+            self.data.storage_system_v3 + '+U+' + 'SRP_1')
+        srpPoolInstanceName['CreationClassName'] = (
+            'Symm_VirtualProvisioningPool')
+        srpPoolInstanceName['ElementName'] = 'SRP_1'
+
+        remainingCapacityGb = (
+            self.driver.common.provisionv3._get_remaining_slo_capacity_wlp(
+                conn, srpPoolInstanceName, array_info, storagesystem))
+        remainingSLOCapacityGb = self.driver.common.utils.convert_bits_to_gbs(
+            self.data.remainingSLOCapacity)
+        self.assertEqual(remainingSLOCapacityGb, remainingCapacityGb)
+
+    def _cleanup(self):
+        bExists = os.path.exists(self.config_file_path)
+        if bExists:
+            os.remove(self.config_file_path)
+        shutil.rmtree(self.tempdir)
+
+
+class EMCV2MultiPoolDriverTestCase(test.TestCase):
+
+    def setUp(self):
+        self.data = EMCVMAXCommonData()
+        self.vol_v2 = self.data.test_volume_v2
+        self.vol_v2['provider_location'] = (
+            six.text_type(self.data.provider_location_multi_pool))
+        self.tempdir = tempfile.mkdtemp()
+        super(EMCV2MultiPoolDriverTestCase, self).setUp()
+        self.config_file_path = None
+        self.create_fake_config_file_multi_pool()
+        self.addCleanup(self._cleanup)
+
+        configuration = mock.Mock()
+        configuration.safe_get.return_value = 'MULTI_POOL'
+        configuration.cinder_emc_config_file = self.config_file_path
+        configuration.config_group = 'MULTI_POOL'
+
+        self.stubs.Set(emc_vmax_iscsi.EMCVMAXISCSIDriver,
+                       'smis_do_iscsi_discovery',
+                       self.fake_do_iscsi_discovery)
+        self.stubs.Set(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
+                       self.fake_ecom_connection)
+        instancename = FakeCIMInstanceName()
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
+                       instancename.fake_getinstancename)
+        self.stubs.Set(time, 'sleep',
+                       self.fake_sleep)
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
+                       self.fake_is_v3)
+
+        driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
+        driver.db = FakeDB()
+        self.driver = driver
+        self.driver.utils = emc_vmax_utils.EMCVMAXUtils(object)
+
+    def create_fake_config_file_multi_pool(self):
+        doc = minidom.Document()
+        emc = doc.createElement("EMC")
+        doc.appendChild(emc)
+
+        eComServers = doc.createElement("EcomServers")
+        emc.appendChild(eComServers)
+
+        eComServer = doc.createElement("EcomServer")
+        eComServers.appendChild(eComServer)
+
+        ecomserverip = doc.createElement("EcomServerIp")
+        eComServer.appendChild(ecomserverip)
+        ecomserveriptext = doc.createTextNode("1.1.1.1")
+        ecomserverip.appendChild(ecomserveriptext)
+
+        ecomserverport = doc.createElement("EcomServerPort")
+        eComServer.appendChild(ecomserverport)
+        ecomserverporttext = doc.createTextNode("10")
+        ecomserverport.appendChild(ecomserverporttext)
+
+        ecomusername = doc.createElement("EcomUserName")
+        eComServer.appendChild(ecomusername)
+        ecomusernametext = doc.createTextNode("user")
+        ecomusername.appendChild(ecomusernametext)
+
+        ecompassword = doc.createElement("EcomPassword")
+        eComServer.appendChild(ecompassword)
+        ecompasswordtext = doc.createTextNode("pass")
+        ecompassword.appendChild(ecompasswordtext)
+
+        arrays = doc.createElement("Arrays")
+        eComServer.appendChild(arrays)
+
+        array = doc.createElement("Array")
+        arrays.appendChild(array)
+
+        serialNo = doc.createElement("SerialNumber")
+        array.appendChild(serialNo)
+        serialNoText = doc.createTextNode("1234567891011")
+        serialNo.appendChild(serialNoText)
+
+        portgroups = doc.createElement("PortGroups")
+        array.appendChild(portgroups)
+
+        portgroup = doc.createElement("PortGroup")
+        portgroups.appendChild(portgroup)
+        portgrouptext = doc.createTextNode(self.data.port_group)
+        portgroup.appendChild(portgrouptext)
+
+        pools = doc.createElement("Pools")
+        array.appendChild(pools)
+
+        pool = doc.createElement("Pool")
+        pools.appendChild(pool)
+        poolName = doc.createElement("PoolName")
+        pool.appendChild(poolName)
+        poolNameText = doc.createTextNode("gold")
+        poolName.appendChild(poolNameText)
+
+        pool2 = doc.createElement("Pool")
+        pools.appendChild(pool2)
+        pool2Name = doc.createElement("PoolName")
+        pool2.appendChild(pool2Name)
+        pool2NameText = doc.createTextNode("SATA_BRONZE1")
+        pool2Name.appendChild(pool2NameText)
+        pool2FastPolicy = doc.createElement("FastPolicy")
+        pool2.appendChild(pool2FastPolicy)
+        pool2FastPolicyText = doc.createTextNode("BRONZE1")
+        pool2FastPolicy.appendChild(pool2FastPolicyText)
+
+        filename = 'cinder_emc_config_V2_MULTI_POOL.xml'
+        self.config_file_path = self.tempdir + '/' + filename
+
+        f = open(self.config_file_path, 'w')
+        doc.writexml(f)
+        f.close()
+
+    def fake_ecom_connection(self):
+        self.conn = FakeEcomConnection()
+        return self.conn
+
+    def fake_do_iscsi_discovery(self, volume):
+        output = []
+        item = '10.10.0.50: 3260,1 iqn.1992-04.com.emc: 50000973f006dd80'
+        output.append(item)
+        return output
+
+    def fake_sleep(self, seconds):
+        return
+
+    def fake_is_v3(self, conn, serialNumber):
+        return False
+
+    def default_extraspec(self):
+        return {'storagetype:pool': u'gold',
+                'volume_backend_name': 'MULTI_POOL_BE',
+                'storagetype:fastpolicy': None,
+                'storagetype:compositetype': u'concatenated',
+                'storagetype:membercount': 1,
+                'storagetype:array': u'1234567891011',
+                'isV3': False,
+                'portgroupname': u'OS-portgroup-PG'}
+
+    def test_initial_setup(self):
+        self.driver.common._register_config_file_from_config_group = (
+            mock.Mock(return_value=self.config_file_path))
+        extraSpecs = self.driver.common._initial_setup(self.vol_v2)
+        self.assertEqual('gold', extraSpecs['storagetype:pool'])
+        self.assertEqual(None, extraSpecs['storagetype:fastpolicy'])
+        self.assertEqual('concatenated',
+                         extraSpecs['storagetype:compositetype'])
+        self.assertEqual('1234567891011', extraSpecs['storagetype:array'])
+        self.assertEqual('OS-portgroup-PG', extraSpecs['portgroupname'])
+        self.assertFalse(extraSpecs['isV3'])
+
+    def test_validate_pool(self):
+        v2_valid_pool = self.data.test_volume_v2.copy()
+        # Pool aware scheduler enabled
+        v2_valid_pool['host'] = self.data.fake_host
+        pool = self.driver.common._validate_pool(v2_valid_pool)
+        self.assertEqual('gold+1234567891011', pool)
+
+        # Cannot get the pool from the host
+        v2_valid_pool['host'] = 'HostX@Backend'
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.common._validate_pool,
+                          v2_valid_pool)
+
+        # Legacy test. Provider Location does not have the version
+        v2_valid_pool['host'] = self.data.fake_host
+        v2_valid_pool['provider_location'] = self.data.provider_location
+        pool = self.driver.common._validate_pool(v2_valid_pool)
+        self.assertIsNone(pool)
+
+    def test_array_info_multi_pool(self):
+
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        self.assertTrue(len(arrayInfo) == 2)
+        for arrayInfoRec in arrayInfo:
+            self.assertEqual(
+                '1234567891011', arrayInfoRec['SerialNumber'])
+            self.assertTrue(
+                self.data.port_group in arrayInfoRec['PortGroup'])
+            self.assertTrue(
+                self.data.poolname in arrayInfoRec['PoolName'] or
+                'SATA_BRONZE1' in arrayInfoRec['PoolName'])
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_create_volume_multi_pool_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.vol_v2['provider_location'] = None
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_volume(self.vol_v2)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_delete_volume_multi_pool_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.delete_volume(self.vol_v2)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_create_volume_in_CG_multi_pool_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.data.test_volume_CG['provider_location'] = None
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_volume(self.data.test_volume_CG)
+
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_retype_volume_multi_pool_success(
+            self, _mock_volume_type):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.retype(
+            self.data.test_ctxt, self.vol_v2, self.data.new_type,
+            self.data.diff, self.data.test_host)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    # There is only one unique array in the conf file
+    def test_create_CG_multi_pool_success(
+            self, _mock_volume_type, _mock_storage_system):
+        self.driver.create_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_members_of_replication_group',
+        return_value=None)
+    @mock.patch.object(
+        FakeDB,
+        'volume_get_all_by_group',
+        return_value=None)
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_delete_CG_no_volumes_multi_pool_success(
+            self, _mock_volume_type, _mock_storage_system,
+            _mock_db_volumes, _mock_members):
+        self.driver.delete_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_POOL_BE'})
+    def test_delete_CG_with_volumes_multi_pool_success(
+            self, _mock_volume_type, _mock_storage_system):
+        self.driver.delete_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    def _cleanup(self):
+        bExists = os.path.exists(self.config_file_path)
+        if bExists:
+            os.remove(self.config_file_path)
+        shutil.rmtree(self.tempdir)
+
+
+class EMCV3MultiSloDriverTestCase(test.TestCase):
+
+    def setUp(self):
+        self.data = EMCVMAXCommonData()
+        self.vol_v3 = self.data.test_volume_v3
+        self.vol_v3['provider_location'] = (
+            six.text_type(self.data.provider_location_multi_pool))
+
+        self.tempdir = tempfile.mkdtemp()
+        super(EMCV3MultiSloDriverTestCase, self).setUp()
+        self.config_file_path = None
+        self.create_fake_config_file_multi_slo_v3()
+        self.addCleanup(self._cleanup)
+        self.set_configuration()
+
+    def set_configuration(self):
+        configuration = mock.Mock()
+        configuration.safe_get.return_value = 'MULTI_SLO_V3'
+        configuration.cinder_emc_config_file = self.config_file_path
+        configuration.config_group = 'MULTI_SLO_V3'
+
+        self.stubs.Set(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
+                       self.fake_ecom_connection)
+        instancename = FakeCIMInstanceName()
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
+                       instancename.fake_getinstancename)
+        self.stubs.Set(time, 'sleep',
+                       self.fake_sleep)
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
+                       self.fake_is_v3)
+
+        driver = emc_vmax_fc.EMCVMAXFCDriver(configuration=configuration)
+        driver.db = FakeDB()
+        self.driver = driver
+        self.driver.utils = emc_vmax_utils.EMCVMAXUtils(object)
+
+    def create_fake_config_file_multi_slo_v3(self):
+        doc = minidom.Document()
+        emc = doc.createElement("EMC")
+        doc.appendChild(emc)
+
+        eComServers = doc.createElement("EcomServers")
+        emc.appendChild(eComServers)
+
+        eComServer = doc.createElement("EcomServer")
+        eComServers.appendChild(eComServer)
+
+        ecomserverip = doc.createElement("EcomServerIp")
+        eComServer.appendChild(ecomserverip)
+        ecomserveriptext = doc.createTextNode("1.1.1.1")
+        ecomserverip.appendChild(ecomserveriptext)
+
+        ecomserverport = doc.createElement("EcomServerPort")
+        eComServer.appendChild(ecomserverport)
+        ecomserverporttext = doc.createTextNode("10")
+        ecomserverport.appendChild(ecomserverporttext)
+
+        ecomusername = doc.createElement("EcomUserName")
+        eComServer.appendChild(ecomusername)
+        ecomusernametext = doc.createTextNode("user")
+        ecomusername.appendChild(ecomusernametext)
+
+        ecompassword = doc.createElement("EcomPassword")
+        eComServer.appendChild(ecompassword)
+        ecompasswordtext = doc.createTextNode("pass")
+        ecompassword.appendChild(ecompasswordtext)
+
+        arrays = doc.createElement("Arrays")
+        eComServer.appendChild(arrays)
+
+        array = doc.createElement("Array")
+        arrays.appendChild(array)
+
+        serialNo = doc.createElement("SerialNumber")
+        array.appendChild(serialNo)
+        serialNoText = doc.createTextNode("1234567891011")
+        serialNo.appendChild(serialNoText)
+
+        portgroups = doc.createElement("PortGroups")
+        array.appendChild(portgroups)
+
+        portgroup = doc.createElement("PortGroup")
+        portgroups.appendChild(portgroup)
+        portgrouptext = doc.createTextNode(self.data.port_group)
+        portgroup.appendChild(portgrouptext)
+
+        vpools = doc.createElement("Pools")
+        array.appendChild(vpools)
+        vpool = doc.createElement("Pool")
+        vpools.appendChild(vpool)
+        poolName = doc.createElement("PoolName")
+        vpool.appendChild(poolName)
+        poolNameText = doc.createTextNode("SRP_1")
+        poolName.appendChild(poolNameText)
+        poolslo = doc.createElement("SLO")
+        vpool.appendChild(poolslo)
+        poolsloText = doc.createTextNode("Bronze")
+        poolslo.appendChild(poolsloText)
+        poolworkload = doc.createElement("Workload")
+        vpool.appendChild(poolworkload)
+        poolworkloadText = doc.createTextNode("DSS")
+        poolworkload.appendChild(poolworkloadText)
+
+        vpool2 = doc.createElement("Pool")
+        vpools.appendChild(vpool2)
+        pool2Name = doc.createElement("PoolName")
+        vpool2.appendChild(pool2Name)
+        pool2NameText = doc.createTextNode("SRP_1")
+        pool2Name.appendChild(pool2NameText)
+        pool2slo = doc.createElement("SLO")
+        vpool2.appendChild(pool2slo)
+        pool2sloText = doc.createTextNode("Silver")
+        pool2slo.appendChild(pool2sloText)
+        pool2workload = doc.createElement("Workload")
+        vpool.appendChild(pool2workload)
+        pool2workloadText = doc.createTextNode("OLTP")
+        pool2workload.appendChild(pool2workloadText)
+
+        filename = 'cinder_emc_config_MULTI_SLO_V3.xml'
+        self.config_file_path = self.tempdir + '/' + filename
+
+        f = open(self.config_file_path, 'w')
+        doc.writexml(f)
+        f.close()
+
+    def fake_ecom_connection(self):
+        self.conn = FakeEcomConnection()
+        return self.conn
+
+    def fake_sleep(self, seconds):
+        return
+
+    def fake_is_v3(self, conn, serialNumber):
+        return True
+
+    def default_extraspec(self):
+        return {'storagetype:pool': u'SRP_1',
+                'volume_backend_name': 'MULTI_SLO_BE',
+                'storagetype:workload': u'DSS',
+                'storagetype:slo': u'Bronze',
+                'storagetype:array': u'1234567891011',
+                'isV3': True,
+                'portgroupname': u'OS-portgroup-PG'}
+
+    def test_initial_setup(self):
+        self.driver.common._register_config_file_from_config_group = (
+            mock.Mock(return_value=self.config_file_path))
+        extraSpecs = self.driver.common._initial_setup(self.vol_v3)
+        self.assertEqual('SRP_1', extraSpecs['storagetype:pool'])
+        self.assertEqual('DSS', extraSpecs['storagetype:workload'])
+        self.assertEqual('Bronze', extraSpecs['storagetype:slo'])
+        self.assertEqual('1234567891011', extraSpecs['storagetype:array'])
+        self.assertEqual('OS-portgroup-PG', extraSpecs['portgroupname'])
+        self.assertTrue(extraSpecs['isV3'])
+
+    def test_validate_pool(self):
+        v3_valid_pool = self.data.test_volume_v3.copy()
+        # Pool aware scheduler enabled
+        v3_valid_pool['host'] = self.data.fake_host_v3
+        pool = self.driver.common._validate_pool(v3_valid_pool)
+        self.assertEqual('Bronze+SRP_1+1234567891011', pool)
+
+        # Cannot get the pool from the host
+        v3_valid_pool['host'] = 'HostX@Backend'
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.common._validate_pool,
+                          v3_valid_pool)
+        # Legacy test. Provider Location does not have the version
+        v3_valid_pool['host'] = self.data.fake_host_v3
+        v3_valid_pool['provider_location'] = self.data.provider_location
+        pool = self.driver.common._validate_pool(v3_valid_pool)
+        self.assertIsNone(pool)
+
+    def test_array_info_multi_slo(self):
+
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        self.assertTrue(len(arrayInfo) == 2)
+        for arrayInfoRec in arrayInfo:
+            self.assertEqual(
+                '1234567891011', arrayInfoRec['SerialNumber'])
+            self.assertTrue(
+                self.data.port_group in arrayInfoRec['PortGroup'])
+            self.assertTrue('SRP_1' in arrayInfoRec['PoolName'])
+            self.assertTrue(
+                'Bronze' in arrayInfoRec['SLO'] or
+                'Silver' in arrayInfoRec['SLO'])
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_create_volume_multi_slo_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.vol_v3['host'] = self.data.fake_host_v3
+        self.vol_v3['provider_location'] = None
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_volume(self.vol_v3)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_delete_volume_multi_slo_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.delete_volume(self.vol_v3)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_create_volume_in_CG_multi_slo_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.data.test_volume_CG_v3['provider_location'] = None
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_volume(self.data.test_volume_CG_v3)
+
+    @mock.patch.object(
+        emc_vmax_provision_v3.EMCVMAXProvisionV3,
+        '_find_new_storage_group',
+        return_value='Any')
+    @mock.patch.object(
+        emc_vmax_utils.EMCVMAXUtils,
+        'wrap_get_storage_group_from_volume',
+        return_value=None)
+    @mock.patch.object(
+        emc_vmax_utils.EMCVMAXUtils,
+        '_get_fast_settings_from_storage_group',
+        return_value='Gold+DSS_REP')
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_retype_volume_multi_slo_success(
+            self, _mock_volume_type, mock_fast_settings,
+            mock_storage_group, mock_found_SG):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.assertTrue(self.driver.retype(
+            self.data.test_ctxt, self.data.test_volume_v3, self.data.new_type,
+            self.data.diff, self.data.test_host_v3))
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    # There is only one unique array in the conf file
+    def test_create_CG_multi_slo_success(
+            self, _mock_volume_type, _mock_storage_system):
+        self.driver.common._initial_setup = mock.Mock(
+            return_value=self.default_extraspec())
+        self.driver.create_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_members_of_replication_group',
+        return_value=None)
+    @mock.patch.object(
+        FakeDB,
+        'volume_get_all_by_group',
+        return_value=None)
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_delete_CG_no_volumes_multi_slo_success(
+            self, _mock_volume_type, _mock_storage_system,
+            _mock_db_volumes, _mock_members):
+        self.driver.delete_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_SLO_BE'})
+    def test_delete_CG_with_volumes_multi_slo_success(
+            self, _mock_volume_type, _mock_storage_system):
+        self.driver.delete_consistencygroup(
+            self.data.test_ctxt, self.data.test_CG)
+
+    def _cleanup(self):
+        bExists = os.path.exists(self.config_file_path)
+        if bExists:
+            os.remove(self.config_file_path)
+        shutil.rmtree(self.tempdir)
+
+
+class EMCV2MultiPoolDriverMultipleEcomsTestCase(test.TestCase):
+
+    def setUp(self):
+
+        self.data = EMCVMAXCommonData()
+        self.vol_v2 = self.data.test_volume_v2
+        self.vol_v2['provider_location'] = (
+            six.text_type(self.data.provider_location_multi_pool))
+
+        self.tempdir = tempfile.mkdtemp()
+        super(EMCV2MultiPoolDriverMultipleEcomsTestCase, self).setUp()
+        self.config_file_path = None
+        self.create_fake_config_file_multi_ecom()
+        self.addCleanup(self._cleanup)
+
+        configuration = mock.Mock()
+        configuration.cinder_emc_config_file = self.config_file_path
+        configuration.safe_get.return_value = 'MULTI_ECOM'
+        configuration.config_group = 'MULTI_ECOM'
+
+        self.stubs.Set(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
+                       self.fake_ecom_connection)
+        instancename = FakeCIMInstanceName()
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
+                       instancename.fake_getinstancename)
+        self.stubs.Set(time, 'sleep',
+                       self.fake_sleep)
+        self.stubs.Set(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
+                       self.fake_is_v3)
+
+        driver = emc_vmax_fc.EMCVMAXFCDriver(configuration=configuration)
+        driver.db = FakeDB()
+        driver.common.conn = FakeEcomConnection()
+        driver.zonemanager_lookup_service = FakeLookupService()
+        self.driver = driver
+        self.driver.utils = emc_vmax_utils.EMCVMAXUtils(object)
+
+    def create_fake_config_file_multi_ecom(self):
+        doc = minidom.Document()
+        emc = doc.createElement("EMC")
+        doc.appendChild(emc)
+
+        eComServers = doc.createElement("EcomServers")
+        emc.appendChild(eComServers)
+
+        eComServer = doc.createElement("EcomServer")
+        eComServers.appendChild(eComServer)
+
+        ecomserverip = doc.createElement("EcomServerIp")
+        eComServer.appendChild(ecomserverip)
+        ecomserveriptext = doc.createTextNode("1.1.1.1")
+        ecomserverip.appendChild(ecomserveriptext)
+
+        ecomserverport = doc.createElement("EcomServerPort")
+        eComServer.appendChild(ecomserverport)
+        ecomserverporttext = doc.createTextNode("10")
+        ecomserverport.appendChild(ecomserverporttext)
+
+        ecomusername = doc.createElement("EcomUserName")
+        eComServer.appendChild(ecomusername)
+        ecomusernametext = doc.createTextNode("user")
+        ecomusername.appendChild(ecomusernametext)
+
+        ecompassword = doc.createElement("EcomPassword")
+        eComServer.appendChild(ecompassword)
+        ecompasswordtext = doc.createTextNode("pass")
+        ecompassword.appendChild(ecompasswordtext)
+
+        arrays = doc.createElement("Arrays")
+        eComServer.appendChild(arrays)
+
+        array = doc.createElement("Array")
+        arrays.appendChild(array)
+
+        serialNo = doc.createElement("SerialNumber")
+        array.appendChild(serialNo)
+        serialNoText = doc.createTextNode("1110987654321")
+        serialNo.appendChild(serialNoText)
+
+        portgroups = doc.createElement("PortGroups")
+        array.appendChild(portgroups)
+
+        portgroup = doc.createElement("PortGroup")
+        portgroups.appendChild(portgroup)
+        portgrouptext = doc.createTextNode(self.data.port_group)
+        portgroup.appendChild(portgrouptext)
+
+        pools = doc.createElement("Pools")
+        array.appendChild(pools)
+
+        pool = doc.createElement("Pool")
+        pools.appendChild(pool)
+        poolName = doc.createElement("PoolName")
+        pool.appendChild(poolName)
+        poolNameText = doc.createTextNode("gold")
+        poolName.appendChild(poolNameText)
+
+        pool2 = doc.createElement("Pool")
+        pools.appendChild(pool2)
+        pool2Name = doc.createElement("PoolName")
+        pool2.appendChild(pool2Name)
+        pool2NameText = doc.createTextNode("SATA_BRONZE1")
+        pool2Name.appendChild(pool2NameText)
+        pool2FastPolicy = doc.createElement("FastPolicy")
+        pool2.appendChild(pool2FastPolicy)
+        pool2FastPolicyText = doc.createTextNode("BRONZE1")
+        pool2FastPolicy.appendChild(pool2FastPolicyText)
+
+        eComServer = doc.createElement("EcomServer")
+        eComServers.appendChild(eComServer)
+
+        ecomserverip = doc.createElement("EcomServerIp")
+        eComServer.appendChild(ecomserverip)
+        ecomserveriptext = doc.createTextNode("1.1.1.1")
+        ecomserverip.appendChild(ecomserveriptext)
+
+        ecomserverport = doc.createElement("EcomServerPort")
+        eComServer.appendChild(ecomserverport)
+        ecomserverporttext = doc.createTextNode("10")
+        ecomserverport.appendChild(ecomserverporttext)
+
+        ecomusername = doc.createElement("EcomUserName")
+        eComServer.appendChild(ecomusername)
+        ecomusernametext = doc.createTextNode("user")
+        ecomusername.appendChild(ecomusernametext)
+
+        ecompassword = doc.createElement("EcomPassword")
+        eComServer.appendChild(ecompassword)
+        ecompasswordtext = doc.createTextNode("pass")
+        ecompassword.appendChild(ecompasswordtext)
+
+        arrays = doc.createElement("Arrays")
+        eComServer.appendChild(arrays)
+
+        array = doc.createElement("Array")
+        arrays.appendChild(array)
+
+        serialNo = doc.createElement("SerialNumber")
+        array.appendChild(serialNo)
+        serialNoText = doc.createTextNode("1234567891011")
+        serialNo.appendChild(serialNoText)
+
+        portgroups = doc.createElement("PortGroups")
+        array.appendChild(portgroups)
+
+        portgroup = doc.createElement("PortGroup")
+        portgroups.appendChild(portgroup)
+        portgrouptext = doc.createTextNode(self.data.port_group)
+        portgroup.appendChild(portgrouptext)
+
+        pools = doc.createElement("Pools")
+        array.appendChild(pools)
+
+        pool = doc.createElement("Pool")
+        pools.appendChild(pool)
+        poolName = doc.createElement("PoolName")
+        pool.appendChild(poolName)
+        poolNameText = doc.createTextNode("gold")
+        poolName.appendChild(poolNameText)
+
+        pool2 = doc.createElement("Pool")
+        pools.appendChild(pool2)
+        pool2Name = doc.createElement("PoolName")
+        pool2.appendChild(pool2Name)
+        pool2NameText = doc.createTextNode("SATA_BRONZE1")
+        pool2Name.appendChild(pool2NameText)
+        pool2FastPolicy = doc.createElement("FastPolicy")
+        pool2.appendChild(pool2FastPolicy)
+        pool2FastPolicyText = doc.createTextNode("BRONZE1")
+        pool2FastPolicy.appendChild(pool2FastPolicyText)
+
+        filename = 'cinder_emc_config_V2_MULTI_ECOM.xml'
+        self.config_file_path = self.tempdir + '/' + filename
+
+        f = open(self.config_file_path, 'w')
+        doc.writexml(f)
+        f.close()
+
+    def fake_ecom_connection(self):
+        self.conn = FakeEcomConnection()
+        return self.conn
+
+    def fake_sleep(self, seconds):
+        return
+
+    def fake_is_v3(self, conn, serialNumber):
+        return False
+
+    def test_array_info_multi_ecom_no_fast(self):
+        pool = 'gold+1234567891011'
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        self.assertTrue(len(arrayInfo) == 4)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+
+        self.assertEqual('1234567891011', poolRec['SerialNumber'])
+        self.assertEqual(self.data.port_group, poolRec['PortGroup'])
+        self.assertEqual(self.data.poolname, poolRec['PoolName'])
+        self.assertEqual('user', poolRec['EcomUserName'])
+        self.assertEqual('pass', poolRec['EcomPassword'])
+        self.assertEqual(None, poolRec['FastPolicy'])
+        self.assertFalse(poolRec['EcomUseSSL'])
+
+    def test_array_info_multi_ecom_fast(self):
+        pool = 'SATA_BRONZE1+1234567891011'
+
+        arrayInfo = self.driver.utils.parse_file_to_get_array_map(
+            self.config_file_path)
+        self.assertTrue(len(arrayInfo) == 4)
+        poolRec = self.driver.utils.extract_record(arrayInfo, pool)
+
+        self.assertEqual('1234567891011', poolRec['SerialNumber'])
+        self.assertEqual(self.data.port_group, poolRec['PortGroup'])
+        self.assertEqual('SATA_BRONZE1', poolRec['PoolName'])
+        self.assertEqual('user', poolRec['EcomUserName'])
+        self.assertEqual('pass', poolRec['EcomPassword'])
+        self.assertEqual('BRONZE1', poolRec['FastPolicy'])
+        self.assertFalse(poolRec['EcomUseSSL'])
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_ECOM_BE'})
+    def test_create_volume_multi_ecom_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.vol_v2['provider_location'] = None
+        self.driver.create_volume(self.vol_v2)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_ECOM_BE'})
+    # If there are more than one unique arrays in conf file
+    def test_create_CG_multi_array_failure(
+            self, _mock_volume_type, _mock_storage_system):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.create_consistencygroup,
+                          self.data.test_ctxt,
+                          self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_members_of_replication_group',
+        return_value=None)
+    @mock.patch.object(
+        FakeDB,
+        'volume_get_all_by_group',
+        return_value=None)
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_ECOM_BE'})
+    # There is more than one unique arrays in the conf file
+    def test_delete_CG_no_volumes_multi_array_failure(
+            self, _mock_volume_type, _mock_storage_system,
+            _mock_db_volumes, _mock_members):
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.delete_consistencygroup,
+                          self.data.test_ctxt,
+                          self.data.test_CG)
+
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'MULTI_ECOM_BE'})
+    def test_create_volume_in_CG_multi_ecom_success(
+            self, _mock_volume_type, mock_storage_system):
+        self.data.test_volume_CG['provider_location'] = None
+        self.driver.create_volume(self.data.test_volume_CG)
+
     def _cleanup(self):
         bExists = os.path.exists(self.config_file_path)
         if bExists:
index 9bc15bb3c9b7abf26da1eaa1910ff4ac8ed3e414..402d623fa396d73d0404e234510159aa37a4324c 100644 (file)
@@ -29,6 +29,7 @@ from cinder.volume.drivers.emc import emc_vmax_masking
 from cinder.volume.drivers.emc import emc_vmax_provision
 from cinder.volume.drivers.emc import emc_vmax_provision_v3
 from cinder.volume.drivers.emc import emc_vmax_utils
+from cinder.volume import utils as volume_utils
 
 
 LOG = logging.getLogger(__name__)
@@ -44,6 +45,9 @@ except ImportError:
 CINDER_EMC_CONFIG_FILE = '/etc/cinder/cinder_emc_config.xml'
 CINDER_EMC_CONFIG_FILE_PREFIX = '/etc/cinder/cinder_emc_config_'
 CINDER_EMC_CONFIG_FILE_POSTFIX = '.xml'
+BACKENDNAME = 'volume_backend_name'
+PREFIXBACKENDNAME = 'capabilities:volume_backend_name'
+PORTGROUPNAME = 'portgroupname'
 EMC_ROOT = 'root/emc'
 POOL = 'storagetype:pool'
 ARRAY = 'storagetype:array'
@@ -54,7 +58,6 @@ STRIPECOUNT = 'storagetype:stripecount'
 MEMBERCOUNT = 'storagetype:membercount'
 STRIPED = 'striped'
 CONCATENATED = 'concatenated'
-SMI_VERSION_8 = 800
 # V3
 SLO = 'storagetype:slo'
 WORKLOAD = 'storagetype:workload'
@@ -88,14 +91,11 @@ class EMCVMAXCommon(object):
              'vendor_name': 'EMC',
              'volume_backend_name': None}
 
-    pool_info = {'pool_name': None,
-                 'fast_policy': None,
-                 'backend_name': None,
-                 'serial_number': None,
-                 'is_v3': False,
-                 'config_file': None}
+    pool_info = {'backend_name': None,
+                 'config_file': None,
+                 'arrays_info': {}}
 
-    def __init__(self, prtcl, configuration=None):
+    def __init__(self, prtcl, version, configuration=None):
 
         if not pywbemAvailable:
             LOG.info(_LI(
@@ -114,6 +114,7 @@ class EMCVMAXCommon(object):
         self.fast = emc_vmax_fast.EMCVMAXFast(prtcl)
         self.provision = emc_vmax_provision.EMCVMAXProvision(prtcl)
         self.provisionv3 = emc_vmax_provision_v3.EMCVMAXProvisionV3(prtcl)
+        self.version = version
         self._gather_info()
 
     def _gather_info(self):
@@ -133,33 +134,10 @@ class EMCVMAXCommon(object):
             {'emcConfigFileName': self.pool_info['config_file'],
              'backendName': self.pool_info['backend_name']})
 
-        if self.conn is None:
-            self._set_ecom_credentials(self.pool_info['config_file'])
-
-        self.pool_info['serial_number'] = (
-            self.utils.parse_array_name_from_file(
+        self.pool_info['arrays_info'] = (
+            self.utils.parse_file_to_get_array_map(
                 self.pool_info['config_file']))
 
-        if self.pool_info['serial_number'] is None:
-            LOG.error(_LE(
-                "Array Serial Number %(arrayName)s must be in the file "
-                "%(emcConfigFileName)s."),
-                {'arrayName': self.pool_info['serial_number'],
-                 'emcConfigFileName': self.pool_info['config_file']})
-
-        self.pool_info['pool_name'] = (
-            self.utils.parse_pool_name_from_file(
-                self.pool_info['config_file']))
-        if self.pool_info['pool_name'] is None:
-            LOG.error(_LE(
-                "PoolName %(poolName)s must be in the file "
-                "%(emcConfigFileName)s."),
-                {'poolName': self.pool_info['pool_name'],
-                 'emcConfigFileName': self.pool_info['config_file']})
-
-        self.pool_info['is_v3'] = (
-            self.utils.isArrayV3(self.conn, self.pool_info['serial_number']))
-
     def create_volume(self, volume):
         """Creates a EMC(VMAX) volume from a pre-existing storage pool.
 
@@ -215,6 +193,8 @@ class EMCVMAXCommon(object):
                  {'volumeName': volumeName,
                   'rc': rc,
                   'name': volumeDict})
+        # Adding version information
+        volumeDict['version'] = self.version
 
         return volumeDict
 
@@ -229,7 +209,8 @@ class EMCVMAXCommon(object):
         :raises: VolumeBackendAPIException
         """
         LOG.debug("Entering create_volume_from_snapshot.")
-        extraSpecs = self._initial_setup(volume)
+        snapshot['host'] = volume['host']
+        extraSpecs = self._initial_setup(snapshot)
         self.conn = self._get_ecom_connection()
         snapshotInstance = self._find_lun(snapshot)
         storageSystem = snapshotInstance['SystemName']
@@ -249,7 +230,8 @@ class EMCVMAXCommon(object):
             self.provision.delete_clone_relationship(
                 self.conn, repservice, syncName, extraSpecs)
 
-        return self._create_cloned_volume(volume, snapshot, False)
+        snapshot['host'] = volume['host']
+        return self._create_cloned_volume(volume, snapshot, extraSpecs, False)
 
     def create_cloned_volume(self, cloneVolume, sourceVolume):
         """Creates a clone of the specified volume.
@@ -258,7 +240,9 @@ class EMCVMAXCommon(object):
         :param sourceVolume: volume object
         :returns: cloneVolumeDict -- the cloned volume dictionary
         """
-        return self._create_cloned_volume(cloneVolume, sourceVolume, False)
+        extraSpecs = self._initial_setup(sourceVolume)
+        return self._create_cloned_volume(cloneVolume, sourceVolume,
+                                          extraSpecs, False)
 
     def delete_volume(self, volume):
         """Deletes a EMC(VMAX) volume.
@@ -283,7 +267,8 @@ class EMCVMAXCommon(object):
         :param volume: volume Object to create snapshot from
         :returns: dict -- the cloned volume dictionary
         """
-        return self._create_cloned_volume(snapshot, volume, True)
+        extraSpecs = self._initial_setup(volume)
+        return self._create_cloned_volume(snapshot, volume, extraSpecs, True)
 
     def delete_snapshot(self, snapshot, volume):
         """Deletes a snapshot.
@@ -293,6 +278,7 @@ class EMCVMAXCommon(object):
         """
         LOG.info(_LI("Delete Snapshot: %(snapshotName)s."),
                  {'snapshotName': snapshot['name']})
+        snapshot['host'] = volume['host']
         self._delete_snapshot(snapshot)
 
     def _remove_members(self, controllerConfigService,
@@ -564,64 +550,76 @@ class EMCVMAXCommon(object):
 
     def update_volume_stats(self):
         """Retrieve stats info."""
-
-        if self.pool_info['is_v3']:
-            location_info, total_capacity_gb, free_capacity_gb = (
-                self._update_srp_stats(self.pool_info['config_file'],
-                                       self.pool_info['serial_number'],
-                                       self.pool_info['pool_name']))
-        else:
-            # This is V2.
-            location_info, total_capacity_gb, free_capacity_gb = (
-                self._update_pool_stats(self.pool_info['config_file'],
-                                        self.pool_info['backend_name'],
-                                        self.pool_info['serial_number'],
-                                        self.pool_info['pool_name']))
-
-        data = {'total_capacity_gb': total_capacity_gb,
-                'free_capacity_gb': free_capacity_gb,
-                'reserved_percentage': 0,
-                'QoS_support': False,
+        pools = []
+        backendName = self.pool_info['backend_name']
+        for arrayInfo in self.pool_info['arrays_info']:
+            self._set_ecom_credentials(arrayInfo)
+            # Check what type of array it is
+            isV3 = self.utils.isArrayV3(self.conn, arrayInfo['SerialNumber'])
+            if isV3:
+                location_info, total_capacity_gb, free_capacity_gb = (
+                    self._update_srp_stats(arrayInfo))
+                poolName = ("%(slo)s+%(poolName)s+%(array)s"
+                            % {'slo': arrayInfo['SLO'],
+                               'poolName': arrayInfo['PoolName'],
+                               'array': arrayInfo['SerialNumber']})
+            else:
+                # This is V2
+                location_info, total_capacity_gb, free_capacity_gb = (
+                    self._update_pool_stats(backendName, arrayInfo))
+                poolName = ("%(poolName)s+%(array)s"
+                            % {'poolName': arrayInfo['PoolName'],
+                               'array': arrayInfo['SerialNumber']})
+
+            pool = {'pool_name': poolName,
+                    'total_capacity_gb': total_capacity_gb,
+                    'free_capacity_gb': free_capacity_gb,
+                    'reserved_percentage': 0,
+                    'QoS_support': False,
+                    'location_info': location_info,
+                    'consistencygroup_support': True}
+            pools.append(pool)
+
+        data = {'vendor_name': "EMC",
+                'driver_version': self.version,
+                'storage_protocol': 'unknown',
                 'volume_backend_name': self.pool_info['backend_name'] or
                 self.__class__.__name__,
-                'vendor_name': "EMC",
-                'driver_version': self.VERSION,
-                'storage_protocol': 'unknown',
-                'location_info': location_info,
-                'consistencygroup_support': True}
+                # Use zero capacities here so we always use a pool.
+                'total_capacity_gb': 0,
+                'free_capacity_gb': 0,
+                'reserved_percentage': 0,
+                'pools': pools}
 
         return data
 
-    def _update_srp_stats(self, emcConfigFileName, arrayName, poolName):
+    def _update_srp_stats(self, arrayInfo):
         """Update SRP stats.
 
-        :param emcConfigFileName: the EMC configuration file
-        :param arrayName: the array
-        :param poolName: the pool
+        :param arrayInfo: array information
         :returns: location_info
         :returns: totalManagedSpaceGbs
         :returns: remainingManagedSpaceGbs
         """
 
         totalManagedSpaceGbs, remainingManagedSpaceGbs = (
-            self.utils.get_srp_pool_stats(self.conn, arrayName, poolName))
+            self.provisionv3.get_srp_pool_stats(self.conn,
+                                                arrayInfo))
 
         LOG.info(_LI(
             "Capacity stats for SRP pool %(poolName)s on array "
             "%(arrayName)s total_capacity_gb=%(total_capacity_gb)lu, "
-            "free_capacity_gb=%(free_capacity_gb)lu."),
-            {'poolName': poolName,
-             'arrayName': arrayName,
+            "free_capacity_gb=%(free_capacity_gb)lu"),
+            {'poolName': arrayInfo['PoolName'],
+             'arrayName': arrayInfo['SerialNumber'],
              'total_capacity_gb': totalManagedSpaceGbs,
              'free_capacity_gb': remainingManagedSpaceGbs})
-        slo = self.utils.parse_slo_from_file(emcConfigFileName)
-        workload = self.utils.parse_workload_from_file(emcConfigFileName)
 
         location_info = ("%(arrayName)s#%(poolName)s#%(slo)s#%(workload)s"
-                         % {'arrayName': arrayName,
-                            'poolName': poolName,
-                            'slo': slo,
-                            'workload': workload})
+                         % {'arrayName': arrayInfo['SerialNumber'],
+                            'poolName': arrayInfo['PoolName'],
+                            'slo': arrayInfo['SLO'],
+                            'workload': arrayInfo['Workload']})
 
         return location_info, totalManagedSpaceGbs, remainingManagedSpaceGbs
 
@@ -1203,7 +1201,6 @@ class EMCVMAXCommon(object):
         # If there are no extra specs then the default case is assumed.
         if extraSpecs:
             configGroup = self.configuration.config_group
-
         configurationFile = self._register_config_file_from_config_group(
             configGroup)
 
@@ -1317,23 +1314,13 @@ 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.
-            try:
-                foundVolumeinstance = self.conn.GetInstance(instancename)
-            except Exception:
-                foundVolumeinstance = None
+            foundVolumeinstance = self.utils.get_existing_instance(
+                self.conn, instancename)
 
         if foundVolumeinstance is None:
             LOG.debug("Volume %(volumename)s not found on the array.",
@@ -1566,7 +1553,6 @@ class EMCVMAXCommon(object):
         :returns: string -- configurationFile - name of the configuration file
         """
         if configGroupName is None:
-            self._set_ecom_credentials(CINDER_EMC_CONFIG_FILE)
             return CINDER_EMC_CONFIG_FILE
         if hasattr(self.configuration, 'cinder_emc_config_file'):
             configurationFile = self.configuration.cinder_emc_config_file
@@ -1586,15 +1572,6 @@ class EMCVMAXCommon(object):
                     'configGroupName': configGroupName,
                     'postfix': CINDER_EMC_CONFIG_FILE_POSTFIX}))
 
-        self._set_ecom_credentials(configurationFile)
-        return configurationFile
-
-    def _set_ecom_credentials(self, configurationFile):
-        """Given the configuration file set the ecom credentials.
-
-        :param configurationFile: name of the file (String)
-        :raises: VolumeBackendAPIException
-        """
         if os.path.isfile(configurationFile):
             LOG.debug("Configuration file : %(configurationFile)s exists.",
                       {'configurationFile': configurationFile})
@@ -1605,10 +1582,21 @@ class EMCVMAXCommon(object):
             LOG.error(exceptionMessage)
             raise exception.VolumeBackendAPIException(data=exceptionMessage)
 
-        ip, port = self.utils.get_ecom_server(configurationFile)
-        self.user, self.passwd = self.utils.get_ecom_cred(configurationFile)
-        self.ecomUseSSL, self.ecomCACert, self.ecomNoVerification = (
-            self.utils.get_ecom_cred_SSL(configurationFile))
+        return configurationFile
+
+    def _set_ecom_credentials(self, arrayInfo):
+        """Given the array record set the ecom credentials.
+
+        :param arrayInfo: record
+        :raises: VolumeBackendAPIException
+        """
+        ip = arrayInfo['EcomServerIp']
+        port = arrayInfo['EcomServerPort']
+        self.user = arrayInfo['EcomUserName']
+        self.passwd = arrayInfo['EcomPassword']
+        self.ecomUseSSL = arrayInfo['EcomUseSSL']
+        self.ecomCACert = arrayInfo['EcomCACert']
+        self.ecomNoVerification = arrayInfo['EcomNoVerification']
         ip_port = ("%(ip)s:%(port)s"
                    % {'ip': ip,
                       'port': port})
@@ -1641,33 +1629,34 @@ class EMCVMAXCommon(object):
                 self._set_config_file_and_get_extra_specs(
                     volume, volumeTypeId))
 
-            arrayName = self.utils.parse_array_name_from_file(
+            pool = self._validate_pool(volume)
+            LOG.debug("Pool returned is %(pool)s.",
+                      {'pool': pool})
+            arrayInfo = self.utils.parse_file_to_get_array_map(
                 configurationFile)
-            if arrayName is None:
+            poolRecord = self.utils.extract_record(arrayInfo, pool)
+
+            if not poolRecord:
                 exceptionMessage = (_(
-                    "The array cannot be null. The pool must be configured "
-                    "either as a cinder extra spec for multi-backend or in "
-                    "the EMC configuration file for the default case."))
-                LOG.error(exceptionMessage)
+                    "Unable to get corresponding record for pool."))
                 raise exception.VolumeBackendAPIException(
                     data=exceptionMessage)
 
-            isV3 = self.utils.isArrayV3(self.conn, arrayName)
+            self._set_ecom_credentials(poolRecord)
+            isV3 = self.utils.isArrayV3(
+                self.conn, poolRecord['SerialNumber'])
 
             if isV3:
-                extraSpecs = self._set_v3_extra_specs(
-                    configurationFile, arrayName, extraSpecs)
+                extraSpecs = self._set_v3_extra_specs(extraSpecs, poolRecord)
             else:
-                # V2 extra specs.
-                extraSpecs = self._set_v2_extra_specs(
-                    configurationFile, arrayName, extraSpecs)
+                # V2 extra specs
+                extraSpecs = self._set_v2_extra_specs(extraSpecs, poolRecord)
         except Exception:
+            import sys
             exceptionMessage = (_(
-                "Unable to get configuration information necessary to create "
-                "a volume. Please check that there is a configuration file "
-                "for each config group, if multi-backend is enabled. "
-                "The file should be in the following format "
-                "/etc/cinder/cinder_emc_config_<CONFIG_GROUP>.xml."))
+                "Unable to get configuration information necessary to "
+                "create a volume: %(errorMessage)s.")
+                % {'errorMessage': sys.exc_info()[1]})
             raise exception.VolumeBackendAPIException(data=exceptionMessage)
 
         return extraSpecs
@@ -1732,9 +1721,7 @@ class EMCVMAXCommon(object):
                  % {'shortHostName': shortHostName,
                     'poolName': poolName,
                     'protocol': protocol}))
-            maskingViewDict['fastPolicy'] = (
-                self.utils.parse_fast_policy_name_from_file(
-                    self.configuration.cinder_emc_config_file))
+            maskingViewDict['fastPolicy'] = extraSpecs[FASTPOLICY]
 
         maskingViewDict['sgGroupName'] = ("%(prefix)s-SG"
                                           % {'prefix': prefix})
@@ -1749,9 +1736,7 @@ class EMCVMAXCommon(object):
             self.utils.find_controller_configuration_service(
                 self.conn, storageSystemName))
         # The portGroup is gotten from emc xml config file.
-        maskingViewDict['pgGroupName'] = (
-            self.utils.parse_file_to_get_port_group_name(
-                self.configuration.cinder_emc_config_file))
+        maskingViewDict['pgGroupName'] = extraSpecs[PORTGROUPNAME]
 
         maskingViewDict['igGroupName'] = (
             ("OS-%(shortHostName)s-%(protocol)s-IG"
@@ -1843,8 +1828,8 @@ class EMCVMAXCommon(object):
         if 'True' in isVolumeBound:
             appendVolumeInstance = (
                 self._unbind_and_get_volume_from_storage_pool(
-                    conn, storageConfigService, appendVolumeInstance.path,
-                    'appendVolume', extraSpecs))
+                    conn, storageConfigService, assocPoolInstanceName,
+                    appendVolumeInstance.path, 'appendVolume', extraSpecs))
 
         return appendVolumeInstance
 
@@ -1870,33 +1855,27 @@ class EMCVMAXCommon(object):
         return volumeInstance
 
     def _unbind_and_get_volume_from_storage_pool(
-            self, conn, storageConfigService, volumeInstanceName,
-            volumeName, extraSpecs):
+            self, conn, storageConfigService, poolInstanceName,
+            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, volumeInstanceName,
+                conn, storageConfigService, poolInstanceName,
+                volumeInstanceName,
                 volumeName, extraSpecs))
-        # 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)
-
+        volumeDict = self.provision.get_volume_dict_from_job(conn, job['Job'])
+        volumeInstance = self.utils.find_volume_instance(
+            self.conn, volumeDict, volumeName)
         return volumeInstance
 
     def _modify_and_get_composite_volume_instance(
@@ -1964,16 +1943,16 @@ class EMCVMAXCommon(object):
         return defaultStorageGroupInstanceName
 
     def _create_cloned_volume(
-            self, cloneVolume, sourceVolume, isSnapshot=False):
+            self, cloneVolume, sourceVolume, extraSpecs, isSnapshot=False):
         """Create a clone volume from the source volume.
 
         :param cloneVolume: clone volume
         :param sourceVolume: source of the clone volume
+        :param extraSpecs: extra specs
         :param isSnapshot: boolean -- Defaults to False
         :returns: dict -- cloneDict the cloned volume dictionary
+        :raises: VolumeBackendAPIException
         """
-        extraSpecs = self._initial_setup(cloneVolume)
-
         sourceName = sourceVolume['name']
         cloneName = cloneVolume['name']
 
@@ -2035,6 +2014,8 @@ class EMCVMAXCommon(object):
                   {'cloneName': cloneName,
                    'sourceName': sourceName,
                    'rc': rc})
+        # Adding version information
+        cloneDict['version'] = self.version
 
         return cloneDict
 
@@ -2823,28 +2804,6 @@ class EMCVMAXCommon(object):
         storageConfigService = self.utils.find_storage_configuration_service(
             self.conn, storageSystemName)
 
-        # Check the SLO range.
-        maximumVolumeSize, minimumVolumeSize = (
-            self.provisionv3.get_volume_range(
-                self.conn, storageConfigService, poolInstanceName,
-                extraSpecs[SLO], extraSpecs[WORKLOAD],
-                extraSpecs))
-        if not self.utils.is_in_range(
-                volumeSize, maximumVolumeSize, minimumVolumeSize):
-            LOG.warning(_LW(
-                "Volume: %(volume)s with size: %(volumeSize)s bits "
-                "is not in the Performance Capacity range: "
-                "%(minimumVolumeSize)s-%(maximumVolumeSize)s bits. "
-                "for SLO:%(slo)s and workload:%(workload)s. "
-                "Unpredictable results may occur."),
-                {'volume': volumeName,
-                 'volumeSize': volumeSize,
-                 'minimumVolumeSize': minimumVolumeSize,
-                 'maximumVolumeSize': maximumVolumeSize,
-                 'slo': extraSpecs[SLO],
-                 'workload': extraSpecs[WORKLOAD]
-                 })
-
         # A volume created without specifying a storage group during
         # creation time is allocated from the default SRP pool and
         # assigned the optimized SLO.
@@ -2979,7 +2938,6 @@ class EMCVMAXCommon(object):
                 storageGroupName))
 
         storageSystemName = volumeInstance['SystemName']
-
         if not isValid:
             LOG.error(_LE(
                 "Volume %(name)s is not suitable for storage "
@@ -3022,6 +2980,7 @@ class EMCVMAXCommon(object):
         controllerConfigService = (
             self.utils.find_controller_configuration_service(
                 self.conn, storageSystemName))
+
         defaultSgName = self.utils.get_v3_storage_group_name(
             extraSpecs[POOL], extraSpecs[SLO], extraSpecs[WORKLOAD])
 
@@ -3122,83 +3081,72 @@ class EMCVMAXCommon(object):
         return False
 
     def _update_pool_stats(
-            self, emcConfigFileName, backendName, arrayName, poolName):
+            self, backendName, arrayInfo):
         """Update pool statistics (V2).
 
-        :param emcConfigFileName: the EMC configuration file
         :param backendName: the backend name
-        :param arrayName: the array name
-        :param poolName: the pool name
+        :param arrayInfo: the arrayInfo
         :returns: location_info, total_capacity_gb, free_capacity_gb
         """
-        # This value can be None.
-        fastPolicyName = self.utils.parse_fast_policy_name_from_file(
-            emcConfigFileName)
-        if fastPolicyName is not None:
+
+        if arrayInfo['FastPolicy']:
             LOG.debug(
                 "Fast policy %(fastPolicyName)s is enabled on %(arrayName)s.",
-                {'fastPolicyName': fastPolicyName,
-                 'arrayName': arrayName})
+                {'fastPolicyName': arrayInfo['FastPolicy'],
+                 'arrayName': arrayInfo['SerialNumber']})
         else:
             LOG.debug(
                 "No Fast policy for Array:%(arrayName)s "
                 "backend:%(backendName)s.",
-                {'arrayName': arrayName,
+                {'arrayName': arrayInfo['SerialNumber'],
                  'backendName': backendName})
 
         storageSystemInstanceName = self.utils.find_storageSystem(
-            self.conn, arrayName)
+            self.conn, arrayInfo['SerialNumber'])
         isTieringPolicySupported = (
             self.fast.is_tiering_policy_enabled_on_storage_system(
                 self.conn, storageSystemInstanceName))
 
-        if (fastPolicyName is not None and
-                isTieringPolicySupported is True):  # FAST enabled.
+        if (arrayInfo['FastPolicy'] is not None and
+                isTieringPolicySupported is True):  # FAST enabled
             total_capacity_gb, free_capacity_gb = (
                 self.fast.get_capacities_associated_to_policy(
-                    self.conn, arrayName, fastPolicyName))
+                    self.conn, arrayInfo['SerialNumber'],
+                    arrayInfo['FastPolicy']))
             LOG.info(_LI(
-                "FAST: capacity stats for policy %(fastPolicyName)s on "
-                "array: %(arrayName)s total_capacity_gb=%(total_capacity_gb)lu"
-                "free_capacity_gb=%(free_capacity_gb)lu."),
-                {'fastPolicyName': fastPolicyName,
-                 'arrayName': arrayName,
+                "FAST: capacity stats for policy %(fastPolicyName)s on array "
+                "%(arrayName)s. total_capacity_gb=%(total_capacity_gb)lu, "
+                "free_capacity_gb=%(free_capacity_gb)lu."),
+                {'fastPolicyName': arrayInfo['FastPolicy'],
+                 'arrayName': arrayInfo['SerialNumber'],
                  'total_capacity_gb': total_capacity_gb,
                  'free_capacity_gb': free_capacity_gb})
         else:  # NON-FAST
             total_capacity_gb, free_capacity_gb = (
-                self.utils.get_pool_capacities(self.conn, poolName, arrayName))
+                self.utils.get_pool_capacities(self.conn,
+                                               arrayInfo['PoolName'],
+                                               arrayInfo['SerialNumber']))
             LOG.info(_LI(
-                "NON-FAST: capacity stats for pool %(poolName)s on array: "
+                "NON-FAST: capacity stats for pool %(poolName)s on array "
                 "%(arrayName)s total_capacity_gb=%(total_capacity_gb)lu, "
                 "free_capacity_gb=%(free_capacity_gb)lu."),
-                {'poolName': poolName,
-                 'arrayName': arrayName,
+                {'poolName': arrayInfo['PoolName'],
+                 'arrayName': arrayInfo['SerialNumber'],
                  'total_capacity_gb': total_capacity_gb,
                  'free_capacity_gb': free_capacity_gb})
 
-        if poolName is None:
-            LOG.debug("Unable to get the poolName for location_info.")
-        if arrayName is None:
-            LOG.debug("Unable to get the arrayName for location_info.")
-        if fastPolicyName is None:
-            LOG.debug("FAST is not enabled for this configuration: "
-                      "%(emcConfigFileName)s.",
-                      {'emcConfigFileName': emcConfigFileName})
-
         location_info = ("%(arrayName)s#%(poolName)s#%(policyName)s"
-                         % {'arrayName': arrayName,
-                            'poolName': poolName,
-                            'policyName': fastPolicyName})
+                         % {'arrayName': arrayInfo['SerialNumber'],
+                            'poolName': arrayInfo['PoolName'],
+                            'policyName': arrayInfo['FastPolicy']})
 
         return location_info, total_capacity_gb, free_capacity_gb
 
-    def _set_v2_extra_specs(self, configurationFile, arrayName, extraSpecs):
+    def _set_v2_extra_specs(self, extraSpecs, poolRecord):
         """Set the VMAX V2 extra specs.
 
-        :param configurationFile: the EMC configuration file
-        :param arrayName: the array serial number
         :param extraSpecs: extra specifications
+        :param poolRecord: pool record
         :returns: dict -- the extraSpecs
         :raises: VolumeBackendAPIException
         """
@@ -3217,29 +3165,14 @@ class EMCVMAXCommon(object):
             extraSpecs[COMPOSITETYPE] = CONCATENATED
             LOG.debug("StripedMetaCount is not in the extra specs.")
 
-        poolName = self.utils.parse_pool_name_from_file(configurationFile)
-        if poolName is None:
-            exceptionMessage = (_(
-                "The pool cannot be null. The pool must be configured "
-                "either in the extra specs or in the EMC configuration "
-                "file corresponding to the Volume Type."))
-            LOG.error(exceptionMessage)
-            raise exception.VolumeBackendAPIException(
-                data=exceptionMessage)
-
         # Get the FAST policy from the file. This value can be None if the
         # user doesn't want to associate with any FAST policy.
-        fastPolicyName = self.utils.parse_fast_policy_name_from_file(
-            configurationFile)
-        if fastPolicyName is not None:
+        if poolRecord['FastPolicy']:
             LOG.debug("The fast policy name is: %(fastPolicyName)s.",
-                      {'fastPolicyName': fastPolicyName})
-
-        extraSpecs[POOL] = poolName
-        extraSpecs[ARRAY] = arrayName
-        extraSpecs[FASTPOLICY] = fastPolicyName
+                      {'fastPolicyName': poolRecord['FastPolicy']})
+        extraSpecs[FASTPOLICY] = poolRecord['FastPolicy']
         extraSpecs[ISV3] = False
-        extraSpecs = self._get_job_extra_specs(configurationFile, extraSpecs)
+        extraSpecs = self._set_common_extraSpecs(extraSpecs, poolRecord)
 
         LOG.debug("Pool is: %(pool)s "
                   "Array is: %(array)s "
@@ -3253,27 +3186,21 @@ class EMCVMAXCommon(object):
                    'memberCount': extraSpecs[MEMBERCOUNT]})
         return extraSpecs
 
-    def _set_v3_extra_specs(self, configurationFile, arrayName, extraSpecs):
+    def _set_v3_extra_specs(self, extraSpecs, poolRecord):
         """Set the VMAX V3 extra specs.
 
         If SLO or workload are not specified then the default
         values are NONE and the Optimized SLO will be assigned to the
         volume.
 
-        :param configurationFile: the EMC configuration file
-        :param arrayName: the array serial number
-        :returns: dict -- the extraSpecs
+        :param extraSpecs: extra specifications
+        :param poolRecord: pool record
+        :returns: dict -- the extra specifications dictionary
         """
-        extraSpecs[SLO] = self.utils.parse_slo_from_file(
-            configurationFile)
-        extraSpecs[WORKLOAD] = self.utils.parse_workload_from_file(
-            configurationFile)
-        extraSpecs[POOL] = self.utils.parse_pool_name_from_file(
-            configurationFile)
-        extraSpecs[ARRAY] = arrayName
+        extraSpecs[SLO] = poolRecord['SLO']
+        extraSpecs[WORKLOAD] = poolRecord['Workload']
         extraSpecs[ISV3] = True
-        extraSpecs = self._get_job_extra_specs(configurationFile, extraSpecs)
-
+        extraSpecs = self._set_common_extraSpecs(extraSpecs, poolRecord)
         LOG.debug("Pool is: %(pool)s "
                   "Array is: %(array)s "
                   "SLO is: %(slo)s "
@@ -3284,27 +3211,30 @@ class EMCVMAXCommon(object):
                    'workload': extraSpecs[WORKLOAD]})
         return extraSpecs
 
-    def _get_job_extra_specs(self, configurationFile, extraSpecs):
-        """Get user defined extra specs around job intervals and retries.
+    def _set_common_extraSpecs(self, extraSpecs, poolRecord):
+        """Set common extra specs.
+
+        The extraSpecs are common to v2 and v3
 
-        :param configurationFile: the EMC configuration file
-        :param extraSpecs: extraSpecs (in)
-        :returns: extraSpecs (out)
+        :param extraSpecs: extra specifications
+        :param poolRecord: pool record
+        :returns: dict -- the extra specifications dictionary
         """
-        intervalInSecs = self.utils.parse_interval_from_file(
-            configurationFile)
-        if intervalInSecs is not None:
+        extraSpecs[POOL] = poolRecord['PoolName']
+        extraSpecs[ARRAY] = poolRecord['SerialNumber']
+        extraSpecs[PORTGROUPNAME] = poolRecord['PortGroup']
+        if 'Interval' in poolRecord and poolRecord['Interval']:
+            extraSpecs[INTERVAL] = poolRecord['Interval']
             LOG.debug("The user defined interval is : %(intervalInSecs)s.",
-                      {'intervalInSecs': intervalInSecs})
-            extraSpecs[INTERVAL] = intervalInSecs
-
-        retries = self.utils.parse_retries_from_file(
-            configurationFile)
-        if retries is not None:
+                      {'intervalInSecs': poolRecord['Interval']})
+        else:
+            LOG.debug("Interval not overridden, default of 10 assumed.")
+        if 'Retries' in poolRecord and poolRecord['Retries']:
+            extraSpecs[RETRIES] = poolRecord['Retries']
             LOG.debug("The user defined retries is : %(retries)s.",
-                      {'retries': retries})
-            extraSpecs[RETRIES] = retries
-
+                      {'retries': poolRecord['Retries']})
+        else:
+            LOG.debug("Retries not overridden, default of 60 assumed.")
         return extraSpecs
 
     def _delete_from_pool(self, storageConfigService, volumeInstance,
@@ -3348,8 +3278,12 @@ class EMCVMAXCommon(object):
                 controllerConfigurationService,
                 volumeInstance.path, volumeName, extraSpecs)
 
-        LOG.debug("Deleting Volume: %(name)s with deviceId: %(deviceId)s.",
-                  {'name': volumeName,
+        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,
                    'deviceId': deviceId})
         try:
             rc = self.provision.delete_volume_from_pool(
@@ -3382,7 +3316,6 @@ class EMCVMAXCommon(object):
                             {'volumeName': volumeName})
             LOG.exception(errorMessage)
             raise exception.VolumeBackendAPIException(data=errorMessage)
-
         return rc
 
     def _delete_from_pool_v3(self, storageConfigService, volumeInstance,
@@ -3476,9 +3409,9 @@ class EMCVMAXCommon(object):
         else:  # Composite volume with meta device members.
             # Check if the meta members capacity.
             metaMemberInstanceNames = (
-                self.utils.get_composite_elements(
-                    self.conn, sourceInstance))
-            volumeCapacities = self.utils.get_meta_members_capacity_in_byte(
+                self.utils.get_meta_members_of_composite_volume(
+                    self.conn, metaHeadInstanceName))
+            volumeCapacities = self.utils.get_meta_members_capacity_in_bit(
                 self.conn, metaMemberInstanceNames)
             LOG.debug("Volume capacities:  %(metasizes)s.",
                       {'metasizes': volumeCapacities})
@@ -3741,9 +3674,6 @@ class EMCVMAXCommon(object):
         # Default operation 8: Detach for clone.
         operation = self.utils.get_num(8, '16')
 
-        # Create target volume
-        extraSpecs = self._initial_setup(cloneVolume)
-
         numOfBlocks = sourceInstance['NumberOfBlocks']
         blockSize = sourceInstance['BlockSize']
         volumeSizeInbits = numOfBlocks * blockSize
@@ -3904,6 +3834,67 @@ class EMCVMAXCommon(object):
                                     extraSpecs)
         return rc
 
+    def _validate_pool(self, volume):
+        """Get the pool from volume['host'].
+
+        There may be backward compatibiliy concerns, so putting in a
+        check to see if a version has been added to provider_location.
+        If it has, we know we are at the current version, if not, we
+        assume it was created pre 'Pool Aware Scheduler' feature.
+
+        :param volume: the volume Object
+        :returns: string -- pool
+        :raises: VolumeBackendAPIException
+        """
+        pool = None
+        # Volume is None in CG ops.
+        if volume is None:
+            return pool
+
+        # This check is for all operations except a create.
+        # On a create provider_location is None
+        try:
+            if volume['provider_location']:
+                version = self._get_version_from_provider_location(
+                    volume['provider_location'])
+                if not version:
+                    return pool
+        except KeyError:
+            return pool
+        try:
+            pool = volume_utils.extract_host(volume['host'], 'pool')
+            if pool:
+                LOG.debug("Pool from volume['host'] is %(pool)s.",
+                          {'pool': pool})
+            else:
+                exceptionMessage = (_(
+                    "Pool from volume['host'] %(host)s not found.")
+                    % {'host': volume['host']})
+                raise exception.VolumeBackendAPIException(
+                    data=exceptionMessage)
+        except Exception as ex:
+            exceptionMessage = (_(
+                "Pool from volume['host'] failed with: %(ex)s.")
+                % {'ex': ex})
+            raise exception.VolumeBackendAPIException(
+                data=exceptionMessage)
+        return pool
+
+    def _get_version_from_provider_location(self, loc):
+        """Get the version from the provider location.
+
+        :param loc: the provider_location dict
+        :returns: version or None
+        """
+        version = None
+        try:
+            if isinstance(loc, six.string_types):
+                name = eval(loc)
+                version = name['version']
+        except KeyError:
+            pass
+        return version
+
     def manage_existing(self, volume, external_ref):
         """Manages an existing VMAX Volume (import to Cinder).
 
index 1c3a24ea31886df637421a85673891e6cd786437..5fc9b8ff0980618c6172c8dfd56a6f593d78df4d 100644 (file)
@@ -431,8 +431,7 @@ class EMCVMAXFast(object):
         storageMaskingGroupInstances = conn.Associators(
             controllerConfigService, ResultClass='CIM_DeviceMaskingGroup')
 
-        for storageMaskingGroupInstance in \
-                storageMaskingGroupInstances:
+        for storageMaskingGroupInstance in storageMaskingGroupInstances:
 
             if ('_default_' in storageMaskingGroupInstance['ElementName'] and
                     policyName in storageMaskingGroupInstance['ElementName']):
index 93da018b74bd427c894cdb5b94788374cc582f0d..7748abb17ceaed9cad606e3e1b051d42dc0fe1a7 100644 (file)
@@ -40,15 +40,17 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
         2.2.0 - Add manage/unmanage
         2.2.1 - Support for SE 8.0.3
         2.2.2 - Update Consistency Group
+        2.2.3 - Pool aware scheduler(multi-pool) support
     """
 
-    VERSION = "2.2.2"
+    VERSION = "2.2.3"
 
     def __init__(self, *args, **kwargs):
 
         super(EMCVMAXFCDriver, self).__init__(*args, **kwargs)
         self.common = emc_vmax_common.EMCVMAXCommon(
             'FC',
+            self.VERSION,
             configuration=self.configuration)
         self.zonemanager_lookup_service = fczm_utils.create_lookup_service()
 
index ea08ebfc003d140b20950d4ace58488415fb82d3..46b0a583ff8cb80cdabf744561502d41f392af4f 100644 (file)
 #    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 httplib requires
+    Supplies an additional 'makefile' method which http_client 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(httplib.HTTPSConnection):
+class HTTPSConnection(http_client.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(httplib.HTTPSConnection):
         else:
             excp_lst = ()
         try:
-            httplib.HTTPSConnection.__init__(self, host, port,
-                                             key_file=key_file,
-                                             cert_file=cert_file)
+            http_client.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 httplib.  x509 may be a
+    response in XML.  Uses Python's build-in http_client.  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, unicode):
+    if isinstance(data, six.text_type):
         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, unicode):
+            if isinstance(hdr, six.text_type):
                 hdr = hdr.encode('utf-8')
             s = map(lambda x: string.strip(x), string.split(hdr, ":", 1))
-            h.putheader(urllib.quote(s[0]), urllib.quote(s[1]))
+            h.putheader(urllib.parse.quote(s[0]), urllib.parse.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 httplib.BadStatusLine as arg:
+        except http_client.BadStatusLine as arg:
             msg = (_("Bad Status line returned: %(arg)s.")
                    % {'arg': arg})
             raise pywbem.cim_http.Error(msg)
index 5c3d253b34718a24d38b500c77d24ec836680ca9..1477392b8881cd2ef94f267e2445c9d1043db976 100644 (file)
@@ -48,15 +48,17 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
         2.2.0 - Add manage/unmanage
         2.2.1 - Support for SE 8.0.3
         2.2.2 - Update Consistency Group
+        2.2.3 - Pool aware scheduler(multi-pool) support
     """
 
-    VERSION = "2.2.2"
+    VERSION = "2.2.3"
 
     def __init__(self, *args, **kwargs):
 
         super(EMCVMAXISCSIDriver, self).__init__(*args, **kwargs)
         self.common = (
             emc_vmax_common.EMCVMAXCommon('iSCSI',
+                                          self.VERSION,
                                           configuration=self.configuration))
 
     def check_for_setup_error(self):
index 9725cef7e7b6aadda9eb27221220980e0cd02758..18efe241d23a42148718f568a9d92bf6d0d7642f 100644 (file)
@@ -623,6 +623,7 @@ class EMCVMAXMasking(object):
         :param conn: the connection to  ecom
         :param storageGroupInstanceName: the storage group instance name
         :param volumeInstance: the volume instance
+        :param sgName: the storage group name
         :returns: boolean
         """
         foundStorageGroupInstanceName = (
@@ -901,8 +902,8 @@ class EMCVMAXMasking(object):
             conn.AssociatorNames(controllerConfigService,
                                  ResultClass='CIM_InitiatorMaskingGroup'))
 
-        for initiatorMaskingGroupInstanceName in \
-                initiatorMaskingGroupInstanceNames:
+        for initiatorMaskingGroupInstanceName in (
+                initiatorMaskingGroupInstanceNames):
             # Check that it hasn't been deleted. If it has, break out
             # of the for loop.
             instance = self.utils.get_existing_instance(
@@ -919,8 +920,8 @@ class EMCVMAXMasking(object):
                 # we found the existing CIM_InitiatorMaskingGroup.
                 hardwareid = storageHardwareIdInstance['StorageID']
                 for initiator in initiatorNames:
-                    if six.text_type(hardwareid).lower() == \
-                            six.text_type(initiator).lower():
+                    if six.text_type(hardwareid).lower() == (
+                            six.text_type(initiator).lower()):
                         foundInitiatorMaskingGroupInstanceName = (
                             initiatorMaskingGroupInstanceName)
                         break
@@ -2037,10 +2038,10 @@ class EMCVMAXMasking(object):
             maskingViewDict['sgGroupName'] = defaultStorageGroupName
             maskingViewDict['volumeInstance'] = volumeInstance
             maskingViewDict['volumeName'] = volumeName
-            maskingViewDict['controllerConfigService'] = \
-                controllerConfigService
-            maskingViewDict['storageSystemName'] = \
-                storageSystemInstanceName
+            maskingViewDict['controllerConfigService'] = (
+                controllerConfigService)
+            maskingViewDict['storageSystemName'] = (
+                storageSystemInstanceName)
             sgInstanceName = self.utils.find_storage_masking_group(
                 conn, controllerConfigService, defaultStorageGroupName)
             if sgInstanceName is not None:
index 4948a8cb86b96490edab3f605062eba2629e7ba6..6a485e0b88d8116f36aa09ce74c0268f1b46ef1e 100644 (file)
@@ -64,7 +64,7 @@ class EMCVMAXProvision(object):
             theElements = [volumeInstanceName]
 
         rc, job = conn.InvokeMethod(
-            'ReturnElementsToStoragePool', storageConfigservice,
+            'EMCReturnToStoragePool', storageConfigservice,
             TheElements=theElements)
 
         if rc != 0:
@@ -338,13 +338,14 @@ class EMCVMAXProvision(object):
                                                       time.time())})
 
     def unbind_volume_from_storage_pool(
-            self, conn, storageConfigService, volumeInstanceName,
-            volumeName, extraSpecs):
+            self, conn, storageConfigService, poolInstanceName,
+            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
@@ -357,6 +358,7 @@ class EMCVMAXProvision(object):
         rc, job = conn.InvokeMethod(
             'EMCUnBindElement',
             storageConfigService,
+            InPool=poolInstanceName,
             TheElement=volumeInstanceName)
 
         if rc != 0:
@@ -1079,16 +1081,14 @@ class EMCVMAXProvision(object):
              'relationName': relationName,
              'srcGroup': srcGroupInstanceName,
              'tgtGroup': tgtGroupInstanceName})
-        # SyncType 8 - clone.
-        # CopyState 4 - Synchronized.
+        # 8 for clone.
         rc, job = conn.InvokeMethod(
             'CreateGroupReplica',
             replicationService,
             RelationshipName=relationName,
             SourceGroup=srcGroupInstanceName,
             TargetGroup=tgtGroupInstanceName,
-            SyncType=self.utils.get_num(8, '16'),
-            WaitForCopyState=self.utils.get_num(4, '16'))
+            SyncType=self.utils.get_num(8, '16'))
 
         if rc != 0:
             rc, errordesc = self.utils.wait_for_job_complete(conn, job,
index 2aa8cd30cb09c7e2f9630b6517dff000f0b0b6b5..a8a6d366b69dc9c8d5992c627e55330a545cb7a2 100644 (file)
 import time
 
 from oslo_log import log as logging
+import six
 
 from cinder import exception
-from cinder.i18n import _, _LE
+from cinder.i18n import _, _LE, _LW
 from cinder.volume.drivers.emc import emc_vmax_utils
 
 LOG = logging.getLogger(__name__)
@@ -29,6 +30,7 @@ POSTGROUPTYPE = 3
 EMC_ROOT = 'root/emc'
 THINPROVISIONINGCOMPOSITE = 32768
 THINPROVISIONING = 5
+INFO_SRC_V3 = 3
 
 
 class EMCVMAXProvisionV3(object):
@@ -411,12 +413,9 @@ class EMCVMAXProvisionV3(object):
         :param slo: slo string e.g Bronze
         :param workload: workload string e.g DSS
         :param extraSpecs: additional info
-        :returns: maximumVolumeSize - the maximum volume size supported
-        :returns: minimumVolumeSize - the minimum volume size supported
+        :returns: supportedSizeDict
         """
-        maximumVolumeSize = None
-        minimumVolumeSize = None
-
+        supportedSizeDict = {}
         storagePoolCapabilityInstanceName = self._get_storage_pool_capability(
             conn, poolInstanceName)
         if storagePoolCapabilityInstanceName:
@@ -426,11 +425,7 @@ class EMCVMAXProvisionV3(object):
                 supportedSizeDict = self._get_supported_size_range_for_SLO(
                     conn, storageConfigService, poolInstanceName,
                     storagePoolSettingInstanceName, extraSpecs)
-
-                maximumVolumeSize = supportedSizeDict['MaximumVolumeSize']
-                minimumVolumeSize = supportedSizeDict['MinimumVolumeSize']
-
-        return maximumVolumeSize, minimumVolumeSize
+        return supportedSizeDict
 
     def activate_snap_relationship(
             self, conn, repServiceInstanceName, syncInstanceName, extraSpecs):
@@ -578,3 +573,97 @@ class EMCVMAXProvisionV3(object):
                 LOG.error(exceptionMsg)
                 raise exception.VolumeBackendAPIException(data=exceptionMsg)
         return rc, job
+
+    def get_srp_pool_stats(self, conn, arrayInfo):
+        """Get the totalManagedSpace, remainingManagedSpace.
+
+        :param conn: the connection to the ecom server
+        :param arrayInfo: the array dict
+        :returns: totalCapacityGb
+        :returns: remainingCapacityGb
+        """
+        totalCapacityGb = -1
+        remainingCapacityGb = -1
+        storageSystemInstanceName = self.utils.find_storageSystem(
+            conn, arrayInfo['SerialNumber'])
+
+        srpPoolInstanceNames = conn.AssociatorNames(
+            storageSystemInstanceName,
+            ResultClass='Symm_SRPStoragePool')
+
+        for srpPoolInstanceName in srpPoolInstanceNames:
+            poolnameStr = self.utils.get_pool_name(conn, srpPoolInstanceName)
+
+            if six.text_type(arrayInfo['PoolName']) == (
+                    six.text_type(poolnameStr)):
+                try:
+                    # Check that pool hasn't suddently been deleted.
+                    srpPoolInstance = conn.GetInstance(srpPoolInstanceName)
+                    propertiesList = srpPoolInstance.properties.items()
+                    for properties in propertiesList:
+                        if properties[0] == 'TotalManagedSpace':
+                            cimProperties = properties[1]
+                            totalManagedSpace = cimProperties.value
+                            totalCapacityGb = self.utils.convert_bits_to_gbs(
+                                totalManagedSpace)
+                        elif properties[0] == 'RemainingManagedSpace':
+                            cimProperties = properties[1]
+                            remainingManagedSpace = cimProperties.value
+                            remainingCapacityGb = (
+                                self.utils.convert_bits_to_gbs(
+                                    remainingManagedSpace))
+                except Exception:
+                    pass
+                remainingSLOCapacityGb = (
+                    self._get_remaining_slo_capacity_wlp(
+                        conn, srpPoolInstanceName, arrayInfo,
+                        storageSystemInstanceName['Name']))
+                if remainingSLOCapacityGb != -1:
+                    remainingCapacityGb = remainingSLOCapacityGb
+                else:
+                    LOG.warning(_LW(
+                        "Remaining capacity %(remainingCapacityGb)s "
+                        "GBs is determined from SRP pool capacity "
+                        "and not the SLO capacity. Performance may "
+                        "not be what you expect."),
+                        {'remainingCapacityGb': remainingCapacityGb})
+
+        return totalCapacityGb, remainingCapacityGb
+
+    def _get_remaining_slo_capacity_wlp(self, conn, srpPoolInstanceName,
+                                        arrayInfo, systemName):
+        """Get the remaining SLO capacity.
+
+        This is derived from the WLP portion of Unisphere. Please
+        see the SMIProvider doc and the readme doc for details.
+
+        :param conn: the connection to the ecom server
+        :param srpPoolInstanceName: SRP instance name
+        :param arrayInfo: the array dict
+        :param systemName: the system name
+        :returns: remainingCapacityGb
+        """
+        remainingCapacityGb = -1
+        storageConfigService = (
+            self.utils.find_storage_configuration_service(
+                conn, systemName))
+
+        supportedSizeDict = (
+            self.get_volume_range(
+                conn, storageConfigService, srpPoolInstanceName,
+                arrayInfo['SLO'], arrayInfo['Workload'],
+                None))
+        try:
+            # Information source is V3.
+            if supportedSizeDict['EMCInformationSource'] == INFO_SRC_V3:
+                remainingCapacityGb = self.utils.convert_bits_to_gbs(
+                    supportedSizeDict['EMCRemainingSLOCapacity'])
+                LOG.debug("Received remaining SLO Capacity "
+                          "%(remainingCapacityGb)s GBs for SLO "
+                          "%(SLO)s and workload %(workload)s.",
+                          {'remainingCapacityGb': remainingCapacityGb,
+                           'SLO': arrayInfo['SLO'],
+                           'workload': arrayInfo['Workload']})
+        except KeyError:
+            pass
+        return remainingCapacityGb
index 8c092661f832176e38db293503452d526aea9bda..41457ca35958e3088616ccec7e28ba1e81bdda74 100644 (file)
@@ -500,6 +500,7 @@ class EMCVMAXUtils(object):
 
         :param conn: connection to the ecom server
         :param volumeInstanceName: the volume instance name
+        :param sgName: the storage group name
         :returns: foundStorageGroupInstanceName
         """
         foundStorageGroupInstanceName = None
@@ -568,8 +569,7 @@ class EMCVMAXUtils(object):
             conn.Associators(controllerConfigService,
                              ResultClass='CIM_DeviceMaskingGroup'))
 
-        for storageMaskingGroupInstance in \
-                storageMaskingGroupInstances:
+        for storageMaskingGroupInstance in storageMaskingGroupInstances:
 
             if storageGroupName == storageMaskingGroupInstance['ElementName']:
                 # Check that it has not been deleted recently.
@@ -654,242 +654,6 @@ class EMCVMAXUtils(object):
 
         return instanceName
 
-    def get_ecom_server(self, filename):
-        """Given the file name get the ecomPort and ecomIP from it.
-
-        :param filename: the path and file name of the emc configuration file
-        :returns: ecomIp - the ecom IP address
-        :returns: ecomPort - the ecom port
-        """
-        ecomIp = self._parse_from_file(filename, 'EcomServerIp')
-        ecomPort = self._parse_from_file(filename, 'EcomServerPort')
-        if ecomIp is not None and ecomPort is not None:
-            LOG.debug("Ecom IP: %(ecomIp)s Port: %(ecomPort)s.",
-                      {'ecomIp': ecomIp, 'ecomPort': ecomPort})
-            return ecomIp, ecomPort
-        else:
-            LOG.debug("Ecom server not found.")
-            return None
-
-    def get_ecom_cred(self, filename):
-        """Given the filename get the ecomUser and ecomPasswd.
-
-        :param filename: the path and filename of the emc configuration file
-        :returns: ecomUser - the ecom user
-        :returns: ecomPasswd - the ecom password
-        """
-        ecomUser = self._parse_from_file(filename, 'EcomUserName')
-        ecomPasswd = self._parse_from_file(filename, 'EcomPassword')
-        if ecomUser is not None and ecomPasswd is not None:
-            return ecomUser, ecomPasswd
-        else:
-            LOG.debug("Ecom user not found.")
-            return None
-
-    def get_ecom_cred_SSL(self, filename):
-        """Given the filename get the ecomUser and ecomPasswd.
-
-        :param filename: the path and filename of the emc configuration file
-        :returns: string -- ecomUseSSL
-        :returns: string -- ecomCACert
-        :returns: string -- ecomNoVerification
-        """
-        ecomUseSSL = self._parse_from_file(filename, 'EcomUseSSL')
-        ecomCACert = self._parse_from_file(filename, 'EcomCACert')
-        ecomNoVerification = self._parse_from_file(
-            filename, 'EcomNoVerification')
-        if ecomUseSSL is not None and ecomUseSSL == 'True':
-            ecomUseSSL = True
-            if ecomNoVerification is not None and ecomNoVerification == 'True':
-                ecomNoVerification = True
-            return ecomUseSSL, ecomCACert, ecomNoVerification
-        else:
-            ecomUseSSL = False
-            ecomNoVerification = False
-            return ecomUseSSL, ecomCACert, ecomNoVerification
-
-    def parse_file_to_get_port_group_name(self, fileName):
-        """Parses a file and chooses a port group randomly.
-
-        Given a file, parse it to get all the possible
-        portGroupElements and choose one randomly.
-
-        :param fileName: the path and name of the file
-        :returns: string -- portGroupName - the name of the port group chosen
-        :raises: VolumeBackendAPIException
-        """
-        portGroupName = None
-        myFile = open(fileName, 'r')
-        data = myFile.read()
-        myFile.close()
-        dom = minidom.parseString(data)
-        portGroupElements = dom.getElementsByTagName('PortGroup')
-
-        if portGroupElements is not None and len(portGroupElements) > 0:
-            portGroupNames = []
-            for portGroupElement in portGroupElements:
-                if portGroupElement.hasChildNodes():
-                    portGroupName = portGroupElement.childNodes[0].nodeValue
-                    portGroupName = portGroupName.replace('\n', '')
-                    portGroupName = portGroupName.replace('\r', '')
-                    portGroupName = portGroupName.replace('\t', '')
-                    portGroupName = portGroupName.strip()
-                    if portGroupName:
-                        portGroupNames.append(portGroupName)
-
-            LOG.debug("portGroupNames: %(portGroupNames)s.",
-                      {'portGroupNames': portGroupNames})
-            numPortGroups = len(portGroupNames)
-            if numPortGroups > 0:
-                selectedPortGroupName = (
-                    portGroupNames[random.randint(0, numPortGroups - 1)])
-                LOG.debug("Returning Selected Port Group: "
-                          "%(selectedPortGroupName)s.",
-                          {'selectedPortGroupName': selectedPortGroupName})
-                return selectedPortGroupName
-
-        # If reaches here without returning yet, raise exception.
-        exception_message = (_("No Port Group elements found in config file."))
-        LOG.error(exception_message)
-        raise exception.VolumeBackendAPIException(data=exception_message)
-
-    def _parse_from_file(self, fileName, stringToParse):
-        """Parse the string from XML.
-
-        Remove newlines, tabs and trailing spaces.
-
-        :param fileName: the path and name of the file
-        :param stringToParse: the name of the tag to get the value for
-        :returns: string -- the returned string; value of the tag
-        """
-        retString = None
-        myFile = open(fileName, 'r')
-        data = myFile.read()
-        myFile.close()
-        dom = minidom.parseString(data)
-        tag = dom.getElementsByTagName(stringToParse)
-        if tag is not None and len(tag) > 0:
-            strXml = tag[0].toxml()
-            strXml = strXml.replace('<%s>' % stringToParse, '')
-            strXml = strXml.replace('\n', '')
-            strXml = strXml.replace('\r', '')
-            strXml = strXml.replace('\t', '')
-            retString = strXml.replace('</%s>' % stringToParse, '')
-            retString = retString.strip()
-        return retString
-
-    def parse_fast_policy_name_from_file(self, fileName):
-        """Parse the fast policy name from config file.
-
-        If it is not there, then NON FAST is assumed.
-
-        :param fileName: the path and name of the file
-        :returns: fastPolicyName - the fast policy name
-        """
-
-        fastPolicyName = self._parse_from_file(fileName, 'FastPolicy')
-        if fastPolicyName:
-            LOG.debug("File %(fileName)s: Fast Policy is %(fastPolicyName)s.",
-                      {'fileName': fileName,
-                       'fastPolicyName': fastPolicyName})
-            return fastPolicyName
-        else:
-            LOG.info(_LI("Fast Policy not found."))
-            return None
-
-    def parse_array_name_from_file(self, fileName):
-        """Parse the array name from config file.
-
-        If it is not there then there should only be one array configured to
-        the ecom. If there is more than one then erroneous results can occur.
-
-        :param fileName: the path and name of the file
-        :returns: string -- arrayName - the array name
-        """
-        arrayName = self._parse_from_file(fileName, 'Array')
-        if arrayName:
-            return arrayName
-        else:
-            LOG.debug("Array not found from config file.")
-            return None
-
-    def parse_pool_name_from_file(self, fileName):
-        """Parse the pool name from config file.
-
-        If it is not there then we will attempt to get it from extra specs.
-
-        :param fileName: the path and name of the file
-        :returns: string -- poolName - the pool name
-        """
-        poolName = self._parse_from_file(fileName, 'Pool')
-        if poolName:
-            return poolName
-        else:
-            LOG.debug("Pool not found from config file.")
-            return None
-
-    def parse_slo_from_file(self, fileName):
-        """Parse the slo from config file.
-
-        Please note that the string 'NONE' is returned if it is not found.
-
-        :param fileName: the path and name of the file
-        :returns: string -- the slo or 'NONE'
-        """
-        slo = self._parse_from_file(fileName, 'SLO')
-        if slo:
-            return slo
-        else:
-            LOG.debug("SLO not in config file. "
-                      "Defaulting to NONE.")
-            return 'NONE'
-
-    def parse_workload_from_file(self, fileName):
-        """Parse the workload from config file.
-
-        Please note that the string 'NONE' is returned if it is not found.
-
-        :param fileName: the path and name of the file
-        :returns: string -- the workload or 'NONE'
-        """
-        workload = self._parse_from_file(fileName, 'Workload')
-        if workload:
-            return workload
-        else:
-            LOG.debug("Workload not in config file. "
-                      "Defaulting to NONE.")
-            return 'NONE'
-
-    def parse_interval_from_file(self, fileName):
-        """Parse the interval from config file.
-
-        If it is not there then the default will be used.
-
-        :param fileName: the path and name of the file
-        :returns: interval - the interval in seconds
-        """
-        interval = self._parse_from_file(fileName, 'Interval')
-        if interval:
-            return interval
-        else:
-            LOG.debug("Interval not overridden, default of 10 assumed.")
-            return None
-
-    def parse_retries_from_file(self, fileName):
-        """Parse the retries from config file.
-
-        If it is not there then the default will be used.
-
-        :param fileName: the path and name of the file
-        :returns: retries - the max number of retries
-        """
-        retries = self._parse_from_file(fileName, 'Retries')
-        if retries:
-            return retries
-        else:
-            LOG.debug("Retries not overridden, default of 60 assumed.")
-            return None
-
     def parse_pool_instance_id(self, poolInstanceId):
         """Given the instance Id parse the pool name and system name from it.
 
@@ -1223,14 +987,13 @@ class EMCVMAXUtils(object):
         LOG.debug(
             "storagePoolName: %(poolName)s, storageSystemName: %(array)s.",
             {'poolName': storagePoolName, 'array': storageSystemName})
-        storageSystemInstanceName = self.find_storageSystem(conn,
-                                                            storageSystemName)
-        poolInstanceNames = conn.AssociatorNames(
-            storageSystemInstanceName,
-            ResultClass='EMC_VirtualProvisioningPool')
+        poolInstanceNames = conn.EnumerateInstanceNames(
+            'EMC_VirtualProvisioningPool')
         for poolInstanceName in poolInstanceNames:
-            poolName = self._get_pool_name(conn, poolInstanceName)
-            if (poolName == storagePoolName):
+            poolName, systemName = (
+                self.parse_pool_instance_id(poolInstanceName['InstanceID']))
+            if (poolName == storagePoolName and
+                    storageSystemName in systemName):
                 # Check that the pool hasn't been recently deleted.
                 instance = self.get_existing_instance(conn, poolInstanceName)
                 if instance is None:
@@ -1622,13 +1385,27 @@ class EMCVMAXUtils(object):
         :returns: foundPoolInstanceName
         :returns: string -- systemNameStr
         """
+        foundPoolInstanceName = None
         vpoolInstanceNames = conn.AssociatorNames(
             storageSystemInstanceName,
             ResultClass='EMC_VirtualProvisioningPool')
 
-        return self._get_pool_instance_and_system_name(
-            conn, vpoolInstanceNames, storageSystemInstanceName,
-            poolNameInStr)
+        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
 
     def get_pool_and_system_name_v3(
             self, conn, storageSystemInstanceName, poolNameInStr):
@@ -1640,41 +1417,29 @@ class EMCVMAXUtils(object):
         :returns: foundPoolInstanceName
         :returns: string -- systemNameStr
         """
+        foundPoolInstanceName = None
         srpPoolInstanceNames = conn.AssociatorNames(
             storageSystemInstanceName,
             ResultClass='Symm_SRPStoragePool')
 
-        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:
+        for srpPoolInstanceName in srpPoolInstanceNames:
+            poolInstanceID = srpPoolInstanceName['InstanceID']
             # Example: SYMMETRIX-+-000196700535-+-SR-+-SRP_1
-            # 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
+            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
                     break
 
         return foundPoolInstanceName, systemNameStr
 
-    def _get_pool_name(self, conn, poolInstanceName):
-        """The pool name from the instance
+    def get_pool_name(self, conn, poolInstanceName):
+        """Get the pool name from the instance
 
         :param conn: the ecom connection
         :param poolInstanceName: the pool instance
@@ -1689,7 +1454,7 @@ class EMCVMAXUtils(object):
         return poolnameStr
 
     def find_storageSystem(self, conn, arrayStr):
-        """Find an array instance name given the array name.
+        """Find an array instance name by the array name.
 
         :param conn: the ecom connection
         :param arrayStr: the array Serial number (string)
@@ -1844,28 +1609,21 @@ class EMCVMAXUtils(object):
         LOG.debug("metaMembers: %(members)s.", {'members': metaMembers})
         return metaMembers
 
-    def get_meta_members_capacity_in_byte(self, conn, volumeInstanceNames):
-        """Get the capacity in byte of all meta device member volumes.
+    def get_meta_members_capacity_in_bit(self, conn, volumeInstanceNames):
+        """Get the capacity in bits 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
         """
-        capacitiesInByte = []
-        headVolume = conn.GetInstance(volumeInstanceNames[0])
-        totalSizeInByte = (
-            headVolume['ConsumableBlocks'] * headVolume['BlockSize'])
-        volumeInstanceNames.pop(0)
+        capacitiesInBit = []
         for volumeInstanceName in volumeInstanceNames:
             volumeInstance = conn.GetInstance(volumeInstanceName)
             numOfBlocks = volumeInstance['ConsumableBlocks']
             blockSize = volumeInstance['BlockSize']
-            volumeSizeInByte = numOfBlocks * blockSize
-            capacitiesInByte.append(volumeSizeInByte)
-            totalSizeInByte = totalSizeInByte - volumeSizeInByte
-
-        capacitiesInByte.insert(0, totalSizeInByte)
-        return capacitiesInByte
+            volumeSizeInbits = numOfBlocks * blockSize
+            capacitiesInBit.append(volumeSizeInbits)
+        return capacitiesInBit
 
     def get_existing_instance(self, conn, instanceName):
         """Check that the instance name still exists and return the instance.
@@ -2002,6 +1760,373 @@ class EMCVMAXUtils(object):
             LOG.warning(_LW("Cannot determine the hardware type."))
         return hardwareTypeId
 
+    def _process_tag(self, element, tagName):
+        """Process the tag to get the value.
+
+        :param element: the parent element
+        :param tagName: the tag name
+        :returns: nodeValue(can be None)
+        """
+        nodeValue = None
+        try:
+            processedElement = element.getElementsByTagName(tagName)[0]
+            nodeValue = processedElement.childNodes[0].nodeValue
+            if nodeValue:
+                nodeValue = nodeValue.strip()
+        except IndexError:
+            pass
+        return nodeValue
+
+    def _get_connection_info(self, ecomElement):
+        """Given the filename get the ecomUser and ecomPasswd.
+
+        :param ecomElement: the ecom element
+        :returns: dict -- connargs - the connection info dictionary
+        :raises: VolumeBackendAPIException
+        """
+        connargs = {}
+        connargs['EcomServerIp'] = (
+            self._process_tag(ecomElement, 'EcomServerIp'))
+        connargs['EcomServerPort'] = (
+            self._process_tag(ecomElement, 'EcomServerPort'))
+        connargs['EcomUserName'] = (
+            self._process_tag(ecomElement, 'EcomUserName'))
+        connargs['EcomPassword'] = (
+            self._process_tag(ecomElement, 'EcomPassword'))
+
+        for k, __ in connargs.items():
+            if connargs[k] is None:
+                exceptionMessage = (_(
+                    "EcomServerIp, EcomServerPort, EcomUserName, "
+                    "EcomPassword must have valid values."))
+                LOG.error(exceptionMessage)
+                raise exception.VolumeBackendAPIException(
+                    data=exceptionMessage)
+
+        # These can be None
+        connargs['EcomUseSSL'] = self._process_tag(ecomElement, 'EcomUseSSL')
+        connargs['EcomCACert'] = self._process_tag(ecomElement, 'EcomCACert')
+        connargs['EcomNoVerification'] = (
+            self._process_tag(ecomElement, 'EcomNoVerification'))
+
+        if connargs['EcomUseSSL'] and connargs['EcomUseSSL'] == 'True':
+            connargs['EcomUseSSL'] = True
+            if connargs['EcomNoVerification'] and (
+               connargs['EcomNoVerification'] == 'True'):
+                connargs['EcomNoVerification'] = True
+        else:
+            connargs['EcomUseSSL'] = False
+            connargs['EcomNoVerification'] = False
+
+        return connargs
+
+    def _fill_record(self, connargs, serialNumber, poolName,
+                     portGroup, element):
+        """Fill a single record.
+
+        :param connargs: the connection info
+        :param serialNumber: the serial number of array
+        :param poolName: the poolname
+        :param portGroup: the portGroup
+        :param element: the parent element
+        :returns: dict -- kwargs
+        """
+        kwargs = {}
+        kwargs['EcomServerIp'] = connargs['EcomServerIp']
+        kwargs['EcomServerPort'] = connargs['EcomServerPort']
+        kwargs['EcomUserName'] = connargs['EcomUserName']
+        kwargs['EcomPassword'] = connargs['EcomPassword']
+        kwargs['EcomUseSSL'] = connargs['EcomUseSSL']
+        kwargs['EcomCACert'] = connargs['EcomCACert']
+        kwargs['EcomNoVerification'] = connargs['EcomNoVerification']
+
+        slo = self._process_tag(element, 'SLO')
+        if slo is None:
+            slo = 'NONE'
+        kwargs['SLO'] = slo
+        workload = self._process_tag(element, 'Workload')
+        if workload is None:
+            workload = 'NONE'
+        kwargs['Workload'] = workload
+        fastPolicy = self._process_tag(element, 'FastPolicy')
+        kwargs['FastPolicy'] = fastPolicy
+        kwargs['SerialNumber'] = serialNumber
+        kwargs['PoolName'] = poolName
+        kwargs['PortGroup'] = portGroup
+
+        return kwargs
+
+    def _multi_pool_support(self, fileName):
+        """Multi pool support.
+
+        <EMC>
+        <EcomServers>
+            <EcomServer>
+                <EcomServerIp>10.108.246.202</EcomServerIp>
+                ...
+                <Arrays>
+                    <Array>
+                        <SerialNumber>000198700439</SerialNumber>
+                        ...
+                        <Pools>
+                            <Pool>
+                                <PoolName>FC_SLVR1</PoolName>
+                                ...
+                            </Pool>
+                        </Pools>
+                    </Array>
+                </Arrays>
+            </EcomServer>
+        </EcomServers>
+        </EMC>
+
+        :param fileName: the configuration file
+        :returns: list
+        """
+        myList = []
+        connargs = {}
+        myFile = open(fileName, 'r')
+        data = myFile.read()
+        myFile.close()
+        dom = minidom.parseString(data)
+        interval = self._process_tag(dom, 'Interval')
+        retries = self._process_tag(dom, 'Retries')
+        try:
+            ecomElements = dom.getElementsByTagName('EcomServer')
+            if ecomElements and len(ecomElements) > 0:
+                for ecomElement in ecomElements:
+                    connargs = self._get_connection_info(ecomElement)
+                    arrayElements = ecomElement.getElementsByTagName('Array')
+                    if arrayElements and len(arrayElements) > 0:
+                        for arrayElement in arrayElements:
+                            myList = self._get_pool_info(arrayElement,
+                                                         fileName, connargs,
+                                                         interval, retries,
+                                                         myList)
+                    else:
+                        LOG.error(_LE(
+                            "Please check your xml for format or syntax "
+                            "errors. Please see documentation for more "
+                            "details."))
+        except IndexError:
+            pass
+        return myList
+
+    def _single_pool_support(self, fileName):
+        """Single pool support.
+
+        <EMC>
+        <EcomServerIp>10.108.246.202</EcomServerIp>
+        <EcomServerPort>5988</EcomServerPort>
+        <EcomUserName>admin</EcomUserName>
+        <EcomPassword>#1Password</EcomPassword>
+        <PortGroups>
+            <PortGroup>OS-PORTGROUP1-PG</PortGroup>
+        </PortGroups>
+        <Array>000198700439</Array>
+        <Pool>FC_SLVR1</Pool>
+        </EMC>
+
+        :param fileName: the configuration file
+        :returns: list
+        """
+        myList = []
+        kwargs = {}
+        connargs = {}
+        myFile = open(fileName, 'r')
+        data = myFile.read()
+        myFile.close()
+        dom = minidom.parseString(data)
+        try:
+            connargs = self._get_connection_info(dom)
+            interval = self._process_tag(dom, 'Interval')
+            retries = self._process_tag(dom, 'Retries')
+            portGroup = self._get_random_portgroup(dom)
+
+            serialNumber = self._process_tag(dom, 'Array')
+            if serialNumber is None:
+                LOG.error(_LE(
+                    "Array Serial Number must be in the file "
+                    "%(fileName)s."),
+                    {'fileName': fileName})
+            poolName = self._process_tag(dom, 'Pool')
+            if poolName is None:
+                LOG.error(_LE(
+                    "PoolName must be in the file "
+                    "%(fileName)s."),
+                    {'fileName': fileName})
+            kwargs = self._fill_record(
+                connargs, serialNumber, poolName, portGroup, dom)
+            if interval:
+                kwargs['Interval'] = interval
+            if retries:
+                kwargs['Retries'] = retries
+
+            myList.append(kwargs)
+        except IndexError:
+            pass
+        return myList
+
+    def parse_file_to_get_array_map(self, fileName):
+        """Parses a file and gets array map.
+
+        Given a file, parse it to get array and any pool(s) or
+        fast policy(s), SLOs, Workloads that might exist.
+
+        :param fileName: the path and name of the file
+        :returns: list
+        """
+        # Multi-pool support.
+        myList = self._multi_pool_support(fileName)
+        if len(myList) == 0:
+            myList = self._single_pool_support(fileName)
+
+        return myList
+
+    def extract_record(self, arrayInfo, pool):
+        """Given pool string determine the correct record.
+
+        The poolName and the serialNumber will determine the
+        correct record to return in VMAX2.
+        The poolName, SLO and the serialNumber will determine the
+        correct record to return in VMAX3.
+
+        :param arrayInfo: list of records
+        :param pool: e.g 'SATA_BRONZE1+000198700439'
+                         'SRP_1+Bronze+000198700555'
+        :returns: single record
+        """
+        foundArrayInfoRec = {}
+        if pool:
+            for arrayInfoRec in arrayInfo:
+                if pool.count('+') == 2:
+                    compString = ("%(slo)s+%(poolName)s+%(array)s"
+                                  % {'slo': arrayInfoRec['SLO'],
+                                     'poolName': arrayInfoRec['PoolName'],
+                                     'array': arrayInfoRec['SerialNumber']})
+                else:
+                    compString = ("%(poolName)s+%(array)s"
+                                  % {'poolName': arrayInfoRec['PoolName'],
+                                     'array': arrayInfoRec['SerialNumber']})
+                if compString == pool:
+                    LOG.info(_LI(
+                        "The pool_name from extraSpecs is %(pool)s."),
+                        {'pool': pool})
+                    foundArrayInfoRec = arrayInfoRec
+                    break
+        else:
+            foundArrayInfoRec = self._get_serial_number(arrayInfo)
+
+        return foundArrayInfoRec
+
+    def _get_random_portgroup(self, element):
+        """Get a portgroup from list of portgroup.
+
+        Parse all available port groups under a particular
+        array and choose one.
+
+        :param element: the parent element
+        :returns: the randomly chosen port group
+        :raises: VolumeBackendAPIException
+        """
+        portGroupElements = element.getElementsByTagName('PortGroup')
+        if portGroupElements and len(portGroupElements) > 0:
+            portGroupNames = []
+            for __ in portGroupElements:
+                portGroupName = self._process_tag(
+                    element, 'PortGroup')
+                if portGroupName:
+                    portGroupNames.append(portGroupName)
+
+            LOG.debug("portGroupNames: %(portGroupNames)s.",
+                      {'portGroupNames': portGroupNames})
+            numPortGroups = len(portGroupNames)
+            if numPortGroups > 0:
+                selectedPortGroupName = (
+                    portGroupNames[random.randint(0, numPortGroups - 1)])
+                LOG.debug("Returning selected PortGroup: "
+                          "%(selectedPortGroupName)s.",
+                          {'selectedPortGroupName': selectedPortGroupName})
+                return selectedPortGroupName
+
+        exception_message = (_("No PortGroup elements found in config file."))
+        LOG.error(exception_message)
+        raise exception.VolumeBackendAPIException(data=exception_message)
+
+    def _get_serial_number(self, arrayInfo):
+        """If we don't have a pool then we just get the serial number.
+
+        If there is more then one serial number we must return an
+        error and a recommendation to edit the EMC conf file.
+
+        :param arrayInfo: list of records
+        :returns: any record where serial number exists
+        :raises: VolumeBackendAPIException
+        """
+        serialNumberList = []
+        foundRecord = {}
+
+        for arrayInfoRec in arrayInfo:
+            serialNumberList.append(arrayInfoRec['SerialNumber'])
+            foundRecord = arrayInfoRec
+
+        if len(set(serialNumberList)) > 1:
+            # We have more than one serial number in the dict.
+            exception_message = (_("Multiple SerialNumbers found, when only "
+                                   "one was expected for this operation. "
+                                   "Please change your EMC config file."))
+            raise exception.VolumeBackendAPIException(data=exception_message)
+
+        return foundRecord
+
+    def _get_pool_info(self, arrayElement, fileName, connargs, interval,
+                       retries, myList):
+        """Get pool information from element.
+
+        :param arrayElement: arrayElement
+        :param fileName: configuration file
+        :param connargs: connection arguments
+        :param interval: interval, can be None
+        :param retries: retries, can be None
+        :param myList: list (input)
+        :returns: list (output)
+        :raises: VolumeBackendAPIException
+        """
+        kwargs = {}
+        portGroup = self._get_random_portgroup(arrayElement)
+        serialNumber = self._process_tag(
+            arrayElement, 'SerialNumber')
+        if serialNumber is None:
+            exceptionMessage = (_(
+                "SerialNumber must be in the file "
+                "%(fileName)s."),
+                {'fileName': fileName})
+            LOG.error(exceptionMessage)
+            raise exception.VolumeBackendAPIException(
+                data=exceptionMessage)
+
+        poolElements = arrayElement.getElementsByTagName('Pool')
+        if poolElements and len(poolElements) > 0:
+            for poolElement in poolElements:
+                poolName = self._process_tag(poolElement, 'PoolName')
+                if poolName is None:
+                    exceptionMessage = (_(
+                        "PoolName must be in the file "
+                        "%(fileName)s."),
+                        {'fileName': fileName})
+                    LOG.error(exceptionMessage)
+                    raise exception.VolumeBackendAPIException(
+                        data=exceptionMessage)
+                kwargs = self._fill_record(connargs, serialNumber,
+                                           poolName, portGroup,
+                                           poolElement)
+                if interval:
+                    kwargs['Interval'] = interval
+                if retries:
+                    kwargs['Retries'] = retries
+                myList.append(kwargs)
+        return myList
+
     def find_volume_by_device_id_on_array(self, conn, storageSystem, deviceID):
         """Find the volume by device ID on a specific array.
 
@@ -2134,48 +2259,3 @@ 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