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
This commit is contained in:
rajinir 2014-06-27 14:53:07 -05:00
parent 08543ee8f8
commit 2339351c04
2 changed files with 60 additions and 5 deletions

View 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()

View 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'),