diff --git a/cinder/tests/test_eqlx.py b/cinder/tests/test_eqlx.py index ac815e19197..4ddbab8d539 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 8b29d4515a7..f63e36b5e4c 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'),