From 2339351c04e0f99897ca0365343066b0f4065378 Mon Sep 17 00:00:00 2001 From: rajinir Date: Fri, 27 Jun 2014 14:53:07 -0500 Subject: [PATCH] Fixes EqualLogic volume live migration. 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 | 21 ++++++++++++++--- cinder/volume/drivers/eqlx.py | 44 +++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/cinder/tests/test_eqlx.py b/cinder/tests/test_eqlx.py index ac815e191..4ddbab8d5 100644 --- a/cinder/tests/test_eqlx.py +++ b/cinder/tests/test_eqlx.py @@ -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() diff --git a/cinder/volume/drivers/eqlx.py b/cinder/volume/drivers/eqlx.py index 8b29d4515..f63e36b5e 100644 --- a/cinder/volume/drivers/eqlx.py +++ b/cinder/volume/drivers/eqlx.py @@ -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 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'), -- 2.45.2