]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
TgtAdm: Don't change CHAP username/password on live migration
authorTomoki Sekiyama <tomoki.sekiyama@hds.com>
Mon, 20 Oct 2014 18:32:55 +0000 (14:32 -0400)
committerTomoki Sekiyama <tomoki.sekiyama@hds.com>
Wed, 22 Oct 2014 23:39:33 +0000 (23:39 +0000)
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

cinder/brick/iscsi/iscsi.py
cinder/tests/test_iscsi.py
cinder/volume/iscsi.py

index e94a3438e594879042d52043a9d2726459e081af..9ff4e42c1b285f604eee09eca28c2d2e2f182bd9 100644 (file)
@@ -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:]
 
index f8dcf8989bc182814bac9ca3fccd0c644d078223..b093f17f20d0f255727a03a08204c3bb6c1bb7a9 100644 (file)
@@ -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'])
 
 
index 3835ff578c3f0117d4feafc4d919b1cf7e58b298..af85b5449bd46ffb5667cc583060c48045b0a9f4 100644 (file)
@@ -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)