From 31538cafe12164549fe1d409a7574ae7679f19cb Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Mon, 20 Oct 2014 14:32:55 -0400 Subject: [PATCH] TgtAdm: Don't change CHAP username/password on live migration As tgtd doesn't update CHAP username/password while the initiator is connected, CHAP username/password must not be changed while a Nova instance are performing live-migration; otherwise the compute node which the instance migrates to cannot login to the volume and the migration process is aborted. This fixes TgtAdm implementation not to regenerate random username/password every time initialize_connection is called. Also, it enables CHAP auth in unit tests of TargetAdmin helpers. Change-Id: I48729a33fada62a7c8e4fe500b1e39533d898701 Closes-Bug: #1383509 (cherry picked from commit c22038b9005070e51224f5057aac9f73cf4d0340) --- cinder/brick/iscsi/iscsi.py | 29 +++++++++++++++++++++++++---- cinder/tests/test_iscsi.py | 30 +++++++++++++++++++++++++++--- cinder/volume/iscsi.py | 8 ++++++-- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/cinder/brick/iscsi/iscsi.py b/cinder/brick/iscsi/iscsi.py index e94a3438e..9ff4e42c1 100644 --- a/cinder/brick/iscsi/iscsi.py +++ b/cinder/brick/iscsi/iscsi.py @@ -23,6 +23,8 @@ import re import stat import time +import six + from cinder.brick import exception from cinder.brick import executor from cinder.i18n import _ @@ -47,6 +49,10 @@ class TargetAdmin(executor.Executor): def _run(self, *args, **kwargs): self._execute(self._cmd, *args, run_as_root=True, **kwargs) + def _get_target_chap_auth(self, volume_id): + """Get the current chap auth username and password.""" + return None + def create_iscsi_target(self, name, tid, lun, path, chap_auth=None, **kwargs): """Create an iSCSI target and logical unit.""" @@ -159,6 +165,25 @@ class TgtAdm(TargetAdmin): "id:%(vol_id)s: %(e)s") % {'vol_id': name, 'e': e}) + def _get_target_chap_auth(self, name): + volumes_dir = self.volumes_dir + vol_id = name.split(':')[1] + volume_path = os.path.join(volumes_dir, vol_id) + + try: + with open(volume_path, 'r') as f: + volume_conf = f.read() + except Exception as e: + LOG.debug('Failed to open config for %(vol_id)s: %(e)s' + % {'vol_id': vol_id, 'e': six.text_type(e)}) + return None + + m = re.search('incominguser (\w+) (\w+)', volume_conf) + if m: + return (m.group(1), m.group(2)) + LOG.debug('Failed to find CHAP auth from config for %s' % vol_id) + return None + def create_iscsi_target(self, name, tid, lun, path, chap_auth=None, **kwargs): # Note(jdg) tid and lun aren't used by TgtAdm but remain for @@ -496,10 +521,6 @@ class LioAdm(TargetAdmin): LOG.info(_('Creating iscsi_target for volume: %s') % vol_id) - # rtstool requires chap_auth, but unit tests don't provide it - chap_auth_userid = 'test_id' - chap_auth_password = 'test_pass' - if chap_auth is not None: (chap_auth_userid, chap_auth_password) = chap_auth.split(' ')[1:] diff --git a/cinder/tests/test_iscsi.py b/cinder/tests/test_iscsi.py index f8dcf8989..b093f17f2 100644 --- a/cinder/tests/test_iscsi.py +++ b/cinder/tests/test_iscsi.py @@ -34,6 +34,8 @@ class TargetAdminTestCase(object): self.path = '/foo' self.vol_id = 'blaa' self.vol_name = 'volume-blaa' + self.chap_username = 'test_id' + self.chap_password = 'test_pass' self.write_cache = 'off' self.db = {} @@ -66,7 +68,9 @@ class TargetAdminTestCase(object): return {'tid': self.tid, 'target_name': self.target_name, 'lun': self.lun, - 'path': self.path} + 'path': self.path, + 'username': self.chap_username, + 'password': self.chap_password} def get_script(self): return self.script_template % self.get_script_params() @@ -78,10 +82,14 @@ class TargetAdminTestCase(object): def clear_cmds(self): self.cmds = [] + def verify_config(self): + pass + def verify_cmds(self, cmds): self.assertEqual(len(cmds), len(self.cmds)) for cmd in self.cmds: self.assertTrue(cmd in cmds) + self.verify_config() def verify(self): script = self.get_script() @@ -95,8 +103,11 @@ class TargetAdminTestCase(object): def run_commands(self): target_helper = self.driver.get_target_helper(self.db) target_helper.set_execute(self.fake_execute) + chap_auth = target_helper._iscsi_authentication('IncomingUser', + self.chap_username, + self.chap_password) target_helper.create_iscsi_target(self.target_name, self.tid, - self.lun, self.path, + self.lun, self.path, chap_auth, write_cache=self.write_cache) target_helper.show_target(self.tid, iqn=self.target_name) target_helper.remove_iscsi_target(self.tid, self.lun, self.vol_id, @@ -128,6 +139,11 @@ class TgtAdmTestCase(test.TestCase, TargetAdminTestCase): '--delete %(target_name)s', 'tgtadm --lld iscsi --op show --mode target']) + def verify_config(self): + target_helper = self.driver.get_target_helper(self.db) + self.assertEqual(target_helper._get_target_chap_auth(self.target_name), + (self.chap_username, self.chap_password)) + class IetAdmTestCase(test.TestCase, TargetAdminTestCase): @@ -139,6 +155,8 @@ class IetAdmTestCase(test.TestCase, TargetAdminTestCase): 'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s', 'ietadm --op new --tid=%(tid)s --lun=%(lun)s ' '--params Path=%(path)s,Type=fileio', + 'ietadm --op new --tid=%(tid)s --user ' + '--params=IncomingUser=%(username)s,Password=%(password)s', 'ietadm --op show --tid=%(tid)s', 'ietadm --op delete --tid=%(tid)s --lun=%(lun)s', 'ietadm --op delete --tid=%(tid)s']) @@ -155,6 +173,8 @@ class IetAdmBlockIOTestCase(test.TestCase, TargetAdminTestCase): 'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s', 'ietadm --op new --tid=%(tid)s --lun=%(lun)s ' '--params Path=%(path)s,Type=blockio', + 'ietadm --op new --tid=%(tid)s --user ' + '--params=IncomingUser=%(username)s,Password=%(password)s', 'ietadm --op show --tid=%(tid)s', 'ietadm --op delete --tid=%(tid)s --lun=%(lun)s', 'ietadm --op delete --tid=%(tid)s']) @@ -171,6 +191,8 @@ class IetAdmFileIOTestCase(test.TestCase, TargetAdminTestCase): 'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s', 'ietadm --op new --tid=%(tid)s --lun=%(lun)s ' '--params Path=%(path)s,Type=fileio', + 'ietadm --op new --tid=%(tid)s --user ' + '--params=IncomingUser=%(username)s,Password=%(password)s', 'ietadm --op show --tid=%(tid)s', 'ietadm --op delete --tid=%(tid)s --lun=%(lun)s', 'ietadm --op delete --tid=%(tid)s']) @@ -188,6 +210,8 @@ class IetAdmAutoIOTestCase(test.TestCase, TargetAdminTestCase): 'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s', 'ietadm --op new --tid=%(tid)s --lun=%(lun)s ' '--params Path=%(path)s,Type=blockio', + 'ietadm --op new --tid=%(tid)s --user ' + '--params=IncomingUser=%(username)s,Password=%(password)s', 'ietadm --op show --tid=%(tid)s', 'ietadm --op delete --tid=%(tid)s --lun=%(lun)s', 'ietadm --op delete --tid=%(tid)s']) @@ -201,7 +225,7 @@ class LioAdmTestCase(test.TestCase, TargetAdminTestCase): self.flags(iscsi_helper='lioadm') self.script_template = "\n".join([ 'cinder-rtstool create ' - '%(path)s %(target_name)s test_id test_pass', + '%(path)s %(target_name)s %(username)s %(password)s', 'cinder-rtstool delete %(target_name)s']) diff --git a/cinder/volume/iscsi.py b/cinder/volume/iscsi.py index 3835ff578..af85b5449 100644 --- a/cinder/volume/iscsi.py +++ b/cinder/volume/iscsi.py @@ -41,8 +41,12 @@ class _ExportMixin(object): volume, max_targets) - chap_username = utils.generate_username() - chap_password = utils.generate_password() + current_chap_auth = self._get_target_chap_auth(iscsi_name) + if current_chap_auth: + (chap_username, chap_password) = current_chap_auth + else: + chap_username = utils.generate_username() + chap_password = utils.generate_password() chap_auth = self._iscsi_authentication('IncomingUser', chap_username, chap_password) -- 2.45.2