]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fixes EqualLogic volume live migration.
authorrajinir <rajini_ram@dell.com>
Fri, 27 Jun 2014 19:53:07 +0000 (14:53 -0500)
committerrajinir <rajini_ram@dell.com>
Thu, 10 Jul 2014 14:28:22 +0000 (09:28 -0500)
Fixes the issue by enabling the multihost flag for the volume and also
discovering the correct access record to delete when terminating
the connection from the source vm and then deleting the record.

Change-Id: If3580c84a4efd3a58c19e9e74d0a13eb68e67031
Closes-Bug: 1296677

cinder/tests/test_eqlx.py
cinder/volume/drivers/eqlx.py

index ac815e19197373dd5020ee69bdefbf9cb4ae1390..4ddbab8d539122670cf4a7b9e2520087a2444ebc 100644 (file)
@@ -55,9 +55,16 @@ class DellEQLSanISCSIDriverTestCase(test.TestCase):
             configuration=self.configuration)
         self.volume_name = "fakevolume"
         self.volid = "fakeid"
-        self.connector = {'ip': '10.0.0.2',
-                          'initiator': 'iqn.1993-08.org.debian:01:222',
-                          'host': 'fakehost'}
+        self.connector = {
+            'ip': '10.0.0.2',
+            'initiator': 'iqn.1993-08.org.debian:01:2227dab76162',
+            'host': 'fakehost'}
+        self.access_record_output = [
+            "ID  Initiator       Ipaddress     AuthMethod UserName   Apply-To",
+            "--- --------------- ------------- ---------- ---------- --------",
+            "1   iqn.1993-08.org.debian:01:222 *.*.*.*       none        both",
+            "       7dab76162"]
+
         self.fake_iqn = 'iqn.2003-10.com.equallogic:group01:25366:fakev'
         self.driver._group_ip = '10.0.1.6'
         self.properties = {
@@ -85,6 +92,8 @@ class DellEQLSanISCSIDriverTestCase(test.TestCase):
                                  self.configuration.eqlx_pool,
                                  'thin-provision').\
             AndReturn(['iSCSI target name is %s.' % self.fake_iqn])
+        self.driver._eql_execute('volume', 'select', volume['name'],
+                                 'multihost-access', 'enable')
         self.mox.ReplayAll()
         model_update = self.driver.create_volume(volume)
         self.assertEqual(model_update, self._model_update)
@@ -140,6 +149,8 @@ class DellEQLSanISCSIDriverTestCase(test.TestCase):
                                  'snapshot', 'select', snapshot['name'],
                                  'clone', volume['name']).\
             AndReturn(['iSCSI target name is %s.' % self.fake_iqn])
+        self.driver._eql_execute('volume', 'select', volume['name'],
+                                 'multihost-access', 'enable')
         self.mox.ReplayAll()
         model_update = self.driver.create_volume_from_snapshot(volume,
                                                                snapshot)
@@ -155,6 +166,8 @@ class DellEQLSanISCSIDriverTestCase(test.TestCase):
         self.driver._eql_execute('volume', 'select', src_volume_name, 'clone',
                                  volume['name']).\
             AndReturn(['iSCSI target name is %s.' % self.fake_iqn])
+        self.driver._eql_execute('volume', 'select', volume['name'],
+                                 'multihost-access', 'enable')
         self.mox.ReplayAll()
         model_update = self.driver.create_cloned_volume(volume, src_vref)
         self.assertEqual(model_update, self._model_update)
@@ -200,6 +213,8 @@ class DellEQLSanISCSIDriverTestCase(test.TestCase):
         self.driver._eql_execute = self.mox.\
             CreateMock(self.driver._eql_execute)
         volume = {'name': self.volume_name}
+        self.driver._eql_execute('volume', 'select', volume['name'], 'access',
+                                 'show').AndReturn(self.access_record_output)
         self.driver._eql_execute('volume', 'select', volume['name'], 'access',
                                  'delete', '1')
         self.mox.ReplayAll()
index 8b29d4515a7757dcf93722a9b3dc24930ad252fc..f63e36b5e4c46c542ce3c8d5d8a4fed514382138 100644 (file)
@@ -284,6 +284,28 @@ class DellEQLSanISCSIDriver(SanISCSIDriver):
                               volume['name'])
                     raise exception.VolumeNotFound(volume_id=volume['id'])
 
+    def _parse_connection(self, connector, out):
+        """Returns the correct connection id for the initiator.
+
+        This parses the cli output from the command
+        'volume select <volumename> access show'
+        and returns the correct connection id.
+        """
+        lines = [line for line in out if line != '']
+        #Every record has 2 lines
+        for i in xrange(0, len(lines), 2):
+            try:
+                int(lines[i][0])
+                #sanity check
+                if len(lines[i + 1].split()) == 1:
+                    check = lines[i].split()[1] + lines[i + 1].strip()
+                    if connector['initiator'] == check:
+                        return lines[i].split()[0]
+            except (IndexError, ValueError):
+                pass  # skip the line that is not a valid access record
+
+        return None
+
     def do_setup(self, context):
         """Disable cli confirmation and tune output format."""
         try:
@@ -314,11 +336,23 @@ class DellEQLSanISCSIDriver(SanISCSIDriver):
             if self.configuration.san_thin_provision:
                 cmd.append('thin-provision')
             out = self._eql_execute(*cmd)
+            self.add_multihost_access(volume)
             return self._get_volume_data(out)
         except Exception:
             with excutils.save_and_reraise_exception():
                 LOG.error(_('Failed to create volume %s'), volume['name'])
 
+    def add_multihost_access(self, volume):
+        """Add multihost-access to a volume. Needed for live migration."""
+        try:
+            cmd = ['volume', 'select',
+                   volume['name'], 'multihost-access', 'enable']
+            self._eql_execute(*cmd)
+        except Exception:
+            with excutils.save_and_reraise_exception():
+                LOG.error(_('Failed to add multi-host access for volume %s'),
+                          volume['name'])
+
     def delete_volume(self, volume):
         """Delete a volume."""
         try:
@@ -355,6 +389,7 @@ class DellEQLSanISCSIDriver(SanISCSIDriver):
                                     snapshot['volume_name'], 'snapshot',
                                     'select', snapshot['name'],
                                     'clone', volume['name'])
+            self.add_multihost_access(volume)
             return self._get_volume_data(out)
         except Exception:
             with excutils.save_and_reraise_exception():
@@ -368,6 +403,7 @@ class DellEQLSanISCSIDriver(SanISCSIDriver):
                 volume_name_template % src_vref['id']
             out = self._eql_execute('volume', 'select', src_volume_name,
                                     'clone', volume['name'])
+            self.add_multihost_access(volume)
             return self._get_volume_data(out)
         except Exception:
             with excutils.save_and_reraise_exception():
@@ -408,8 +444,12 @@ class DellEQLSanISCSIDriver(SanISCSIDriver):
     def terminate_connection(self, volume, connector, force=False, **kwargs):
         """Remove access restrictions from a volume."""
         try:
-            self._eql_execute('volume', 'select', volume['name'],
-                              'access', 'delete', '1')
+            out = self._eql_execute('volume', 'select', volume['name'],
+                                    'access', 'show')
+            connection_id = self._parse_connection(connector, out)
+            if connection_id != None:
+                self._eql_execute('volume', 'select', volume['name'],
+                                  'access', 'delete', connection_id)
         except Exception:
             with excutils.save_and_reraise_exception():
                 LOG.error(_('Failed to terminate connection to volume %s'),