]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fixed copy image to volume and clone volume.
authorXing Yang <xing.yang@emc.com>
Sun, 3 Mar 2013 05:06:29 +0000 (00:06 -0500)
committerXing Yang <xing.yang@emc.com>
Tue, 5 Mar 2013 15:46:29 +0000 (10:46 -0500)
This patch fixed the following issues in EMC driver found during G3 testing:
1. VNX array has two storage processors and it is doing load balancing when
attaching a LUN to a host. The storage processor used to attach a LUN to a
host is different from the one discovered by the driver sometimes, causing
Copy Image to Volume to fail.
2. The clone relationship is removed after a volume is successfully
cloned. However, this happens too soon sometimes before the cloned volume
is fully synced with the source volume.  The fix is to wait until it is
fully synced.

Change-Id: I5b8fab263723c47faf30b950a611c5bde7f29092
Fixes: bug #1135221
cinder/tests/test_emc.py
cinder/volume/drivers/emc/emc_smis_common.py
cinder/volume/drivers/emc/emc_smis_iscsi.py

index 639528e484b3e412675fbadc5b8097fb4d195cae..e1098c9dfa74fb66e8993d003116eedb2e8dbb0b 100644 (file)
@@ -249,6 +249,8 @@ class FakeEcomConnection():
             result = self._getinstance_lunmask()
         elif name == 'SE_ConcreteJob':
             result = self._getinstance_job(objectpath)
+        elif name == 'SE_StorageSynchronized_SV_SV':
+            result = self._getinstance_syncsvsv(objectpath)
         else:
             result = self._default_getinstance(objectpath)
         return result
@@ -329,6 +331,16 @@ class FakeEcomConnection():
                 break
         return instance
 
+    def _getinstance_syncsvsv(self, objectpath):
+        foundsync = None
+        syncs = self._enum_syncsvsvs()
+        for sync in syncs:
+            if (sync['SyncedElement'] == objectpath['SyncedElement'] and
+                sync['SystemElement'] == objectpath['SystemElement']):
+                foundsync = sync
+                break
+        return foundsync
+
     def _getinstance_lunmask(self):
         lunmask = {}
         lunmask['CreationClassName'] = lunmask_creationclass
@@ -508,28 +520,13 @@ class FakeEcomConnection():
 
         vols = self._enum_storagevolumes()
 
-        objpath1 = vols[0]
-        objpath2 = vols[1]
-        sync = {}
-        sync['SyncedElement'] = objpath2
-        sync['SystemElement'] = objpath1
-        sync['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync = self._create_sync(vols[0], vols[1], 100)
         syncs.append(sync)
 
-        objpath1 = vols[1]
-        objpath2 = vols[2]
-        sync2 = {}
-        sync2['SyncedElement'] = objpath2
-        sync2['SystemElement'] = objpath1
-        sync2['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync2 = self._create_sync(vols[1], vols[2], 100)
         syncs.append(sync2)
 
-        objpath1 = vols[0]
-        objpath2 = vols[3]
-        sync3 = {}
-        sync3['SyncedElement'] = objpath2
-        sync3['SystemElement'] = objpath1
-        sync3['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync3 = self._create_sync(vols[0], vols[3], 100)
         syncs.append(sync3)
 
         objpath1 = vols[1]
@@ -537,10 +534,7 @@ class FakeEcomConnection():
             if vol['ElementName'] == 'failed_snapshot_sync':
                 objpath2 = vol
                 break
-        sync4 = {}
-        sync4['SyncedElement'] = objpath2
-        sync4['SystemElement'] = objpath1
-        sync4['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync4 = self._create_sync(objpath1, objpath2, 100)
         syncs.append(sync4)
 
         objpath1 = vols[0]
@@ -548,14 +542,19 @@ class FakeEcomConnection():
             if vol['ElementName'] == 'failed_clone_sync':
                 objpath2 = vol
                 break
-        sync5 = {}
-        sync5['SyncedElement'] = objpath2
-        sync5['SystemElement'] = objpath1
-        sync5['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync5 = self._create_sync(objpath1, objpath2, 100)
         syncs.append(sync5)
 
         return syncs
 
+    def _create_sync(self, objpath1, objpath2, percentsynced):
+        sync = {}
+        sync['SyncedElement'] = objpath2
+        sync['SystemElement'] = objpath1
+        sync['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
+        sync['PercentSynced'] = percentsynced
+        return sync
+
     def _enum_unitnames(self):
         return self._ref_unitnames()
 
@@ -675,6 +674,8 @@ class EMCSMISISCSIDriverTestCase(test.TestCase):
         self.driver.create_volume(test_volume)
         export = self.driver.create_export(None, test_volume)
         test_volume['provider_location'] = export['provider_location']
+        test_volume['EMCCurrentOwningStorageProcessor'] = \
+            'iqn.1993-08.org.debian:01:a1b2c3d4e5f6'
         connector = {'initiator': initiator1}
         connection_info = self.driver.initialize_connection(test_volume,
                                                             connector)
index 113200203b26c31f7117149f4abe4e5c41305b53..60c4c3452a95cebaea7c4630edae54aecf759dd7 100644 (file)
@@ -552,7 +552,7 @@ class EMCSMISCommon():
                      'volume': volumename})
 
         sync_name, storage_system = self._find_storage_sync_sv_sv(
-                                    snapshotname, volumename)
+                                    snapshotname, volumename, False)
         if sync_name is None:
             LOG.error(_('Snapshot: %(snapshot)s: volume: %(volume)s '
                       'not found on the array. No snapshot to delete.')
@@ -1116,9 +1116,11 @@ class EMCSMISCommon():
 
         return foundinstance
 
-    def _find_storage_sync_sv_sv(self, snapshotname, volumename):
+    def _find_storage_sync_sv_sv(self, snapshotname, volumename,
+                                 waitforsync=True):
         foundsyncname = None
         storage_system = None
+        percent_synced = 0
 
         LOG.debug(_("Source: %(volumename)s  Target: %(snapshotname)s.")
                   % {'volumename': volumename, 'snapshotname': snapshotname})
@@ -1137,6 +1139,9 @@ class EMCSMISCommon():
             if vol_instance['ElementName'] == volumename:
                 foundsyncname = n
                 storage_system = vol_instance['SystemName']
+                if waitforsync:
+                    sync_instance = self.conn.GetInstance(n, LocalOnly=False)
+                    percent_synced = sync_instance['PercentSynced']
                 break
 
         if foundsyncname is None:
@@ -1149,6 +1154,13 @@ class EMCSMISCommon():
                       "Storage Synchronized instance: %(sync)s.")
                       % {'storage_system': storage_system,
                          'sync': str(foundsyncname)})
+            # Wait for SE_StorageSynchronized_SV_SV to be fully synced
+            while waitforsync and percent_synced < 100:
+                time.sleep(10)
+                sync_instance = self.conn.GetInstance(foundsyncname,
+                                                      LocalOnly=False)
+                percent_synced = sync_instance['PercentSynced']
+
         return foundsyncname, storage_system
 
     def _find_initiator_names(self, connector):
@@ -1350,6 +1362,12 @@ class EMCSMISCommon():
         volumename = volume['name']
         vol_instance = self._find_lun(volume)
         storage_system = vol_instance['SystemName']
+        sp = None
+        try:
+            sp = vol_instance['EMCCurrentOwningStorageProcessor']
+        except KeyError:
+            # VMAX LUN doesn't have this property
+            pass
 
         unitnames = self.conn.ReferenceNames(
                         vol_instance.path,
@@ -1388,7 +1406,8 @@ class EMCSMISCommon():
                        'vol_instance': str(vol_instance.path)})
 
         data = {'hostlunid': out_num_device_number,
-                'storagesystem': storage_system}
+                'storagesystem': storage_system,
+                'owningsp': sp}
 
         LOG.debug(_("Device info: %(data)s.") % {'data': data})
 
index 4f093b61556ab03ed8c427f3a07cdb45b630078d..3046e041d44ed714bade7b4d509ef89ee49cd304 100644 (file)
@@ -122,11 +122,11 @@ class EMCSMISISCSIDriver(driver.ISCSIDriver):
                                     '-t', 'sendtargets', '-p',
                                     self.configuration.iscsi_ip_address,
                                     run_as_root=True)
+        targets = []
         for target in out.splitlines():
-            index = target.find(self.configuration.iscsi_ip_address)
-            if index != -1:
-                return target
-        return None
+            targets.append(target)
+
+        return targets
 
     def _get_iscsi_properties(self, volume):
         """Gets iscsi configuration.
@@ -162,10 +162,6 @@ class EMCSMISISCSIDriver(driver.ISCSIDriver):
         LOG.debug(_("ISCSI Discovery: Found %s") % (location))
         properties['target_discovered'] = True
 
-        results = location.split(" ")
-        properties['target_portal'] = results[0].split(",")[0]
-        properties['target_iqn'] = results[1]
-
         device_info = self.common.find_device_number(volume)
         if device_info is None or device_info['hostlunid'] is None:
             exception_message = (_("Cannot find device number for volume %s")
@@ -174,6 +170,16 @@ class EMCSMISISCSIDriver(driver.ISCSIDriver):
 
         device_number = device_info['hostlunid']
 
+        sp = device_info['owningsp']
+        for loc in location:
+            results = loc.split(" ")
+            properties['target_portal'] = results[0].split(",")[0]
+            properties['target_iqn'] = results[1]
+            # owning sp is None for VMAX
+            # for VNX, find the owning sp in target_iqn
+            if not sp or -1 != properties['target_iqn'].find(sp):
+                break
+
         properties['target_lun'] = device_number
 
         properties['volume_id'] = volume['id']