]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix HNAS iSCSI 32 targets limitation error
authorErlon R. Cruz <erlon.cruz@fit-tecnologia.org.br>
Tue, 4 Aug 2015 13:18:48 +0000 (10:18 -0300)
committerErlon R. Cruz <erlon.cruz@fit-tecnologia.org.br>
Wed, 12 Aug 2015 13:40:25 +0000 (10:40 -0300)
When attaching more than 32 targets to an HNAS iSCSI backend, the
storage returns an error as there's a limitation on the number of
volumes that can be attached to a target. This patch fixes the
problem and creates new targets as needed.

Closes-Bug: #1479072
Change-Id: Id29259024b003a65cc80dfe63cac1c2d26f36059

cinder/tests/unit/test_hitachi_hnas_backend.py
cinder/tests/unit/test_hitachi_hnas_iscsi.py
cinder/volume/drivers/hitachi/hnas_backend.py
cinder/volume/drivers/hitachi/hnas_iscsi.py

index c4b0f77000b846bece2dba1a8ea7d9664557b69e..4d3f4742538ba50cfd40372a171692e9ad38e753 100644 (file)
@@ -197,6 +197,38 @@ HNAS_RESULT21 = "Target created successfully."
 
 HNAS_RESULT22 = "Failed to establish SSC connection"
 
+HNAS_RESULT23 = "\n\
+Alias               : cinder-Gold\n\
+Globally unique name: iqn.2015-06.10.10.10.10:evstest1.cinder-gold\n\
+Comment             :\n\
+Secret              : None\n\
+Authentication      : Enabled\n\
+Logical units       : No logical units.\n\
+Access configuration :\n\
+\n\
+Alias               : cinder-GoldIsh\n\
+Globally unique name: iqn.2015-06.10.10.10.10:evstest1.cinder-goldish\n\
+Comment             :\n\
+Secret              : None\n\
+Authentication      : Enabled\n\
+Logical units       : No logical units.\n\
+Access configuration :\n\
+\n\
+Alias               : cinder-default\n\
+Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default\n\
+Comment             :\n\
+Secret              : pxr6U37LZZJBoMc\n\
+Authentication      : Disabled\n\
+Logical units       : Logical units       :\n\
+\n\
+  LUN   Logical Unit\n\
+  ----  --------------------------------\n\
+  0     volume-8ddd1a54-9daf-4fa5-842...\n\
+  1     volume-99da7ae7-1e7f-4d57-8bf...\n\
+\n\
+Access configuration :\n\
+"
+
 HNAS_CMDS = {
     ('ssh', '0.0.0.0', 'supervisor', 'supervisor', 'evsfs', 'list'):
         ["%s" % HNAS_RESULT1, ""],
@@ -257,7 +289,14 @@ HNAS_CMDS = {
      '/.cinder/test_clone.iscsi'):
         ["%s" % HNAS_RESULT16, ""],
     ('ssh', '0.0.0.0', 'supervisor', 'supervisor', 'evsipaddr', '-e', '1'):
-        ["%s" % HNAS_RESULT17, ""]
+        ["%s" % HNAS_RESULT17, ""],
+    ('ssh', '0.0.0.0', 'supervisor', 'supervisor',
+     'console-context', '--evs', '1', 'iscsi-target', 'list'):
+        ["%s" % HNAS_RESULT23, ""],
+    ('ssh', '0.0.0.0', 'supervisor', 'supervisor', 'console-context', '--evs',
+     '1', 'iscsi-target', 'addlu', 'cinder-default',
+     'volume-8ddd1a54-0000-0000-0000', '2'):
+        ["%s" % HNAS_RESULT13, ""]
 }
 
 DRV_CONF = {'ssh_enabled': 'True',
@@ -431,9 +470,10 @@ class HDSHNASBendTest(test.TestCase):
                        side_effect=m_run_cmd)
     def test_add_iscsi_conn(self, m_cmd):
         out = self.hnas_bend.add_iscsi_conn("ssh", "0.0.0.0", "supervisor",
-                                            "supervisor", "test_lun",
+                                            "supervisor",
+                                            "volume-8ddd1a54-0000-0000-0000",
                                             "test_hdp", "test_port",
-                                            "test_iqn", "test_init")
+                                            "cinder-default", "test_init")
 
         self.assertIn('successfully paired', out)
 
@@ -445,7 +485,7 @@ class HDSHNASBendTest(test.TestCase):
 
         self.assertIn('already deleted', out)
 
-    @mock.patch.object(hnas_backend.HnasBackend, '_get_evs', return_value=0)
+    @mock.patch.object(hnas_backend.HnasBackend, 'get_evs', return_value=0)
     @mock.patch.object(hnas_backend.HnasBackend, 'run_cmd')
     def test_get_targetiqn(self, m_cmd, m_get_evs):
 
@@ -493,3 +533,60 @@ class HDSHNASBendTest(test.TestCase):
                                               "supervisor", "test_iqn",
                                               "test_hdp")
         self.assertEqual('', out)
+
+    @mock.patch.object(hnas_backend.HnasBackend, 'run_cmd')
+    def test_get_targets(self, m_run_cmd):
+        # Test normal behaviour
+        m_run_cmd.return_value = (HNAS_RESULT23, "")
+        tgt_list = self.hnas_bend._get_targets("ssh", "0.0.0.0", "supervisor",
+                                               "supervisor", 1)
+        self.assertEqual(3, len(tgt_list))
+        self.assertEqual(2, len(tgt_list[2]['luns']))
+
+        # Test calling with parameter
+        tgt_list = self.hnas_bend._get_targets("ssh", "0.0.0.0", "supervisor",
+                                               "supervisor", 1,
+                                               'cinder-default')
+        self.assertEqual(1, len(tgt_list))
+        self.assertEqual(2, len(tgt_list[0]['luns']))
+
+        # Test error in BE command
+        m_run_cmd.side_effect = putils.ProcessExecutionError
+        tgt_list = self.hnas_bend._get_targets("ssh", "0.0.0.0", "supervisor",
+                                               "supervisor", 1)
+        self.assertEqual(0, len(tgt_list))
+
+    @mock.patch.object(hnas_backend.HnasBackend,
+                       'run_cmd', side_effect=m_run_cmd)
+    def test_check_targets(self, m_run_cmd):
+        result, tgt = self.hnas_bend.check_target("ssh", "0.0.0.0",
+                                                  "supervisor",
+                                                  "supervisor", "test_hdp",
+                                                  "cinder-default")
+        self.assertTrue(result)
+        self.assertEqual('cinder-default', tgt['alias'])
+
+        result, tgt = self.hnas_bend.check_target("ssh", "0.0.0.0",
+                                                  "supervisor",
+                                                  "supervisor", "test_hdp",
+                                                  "cinder-no-target")
+        self.assertFalse(result)
+        self.assertIsNone(tgt)
+
+    @mock.patch.object(hnas_backend.HnasBackend,
+                       'run_cmd', side_effect=m_run_cmd)
+    def test_check_lu(self, m_run_cmd):
+        ret = self.hnas_bend.check_lu("ssh", "0.0.0.0", "supervisor",
+                                      "supervisor",
+                                      "volume-8ddd1a54-9daf-4fa5-842",
+                                      "test_hdp")
+        result, lunid, tgt = ret
+        self.assertTrue(result)
+        self.assertEqual('0', lunid)
+
+        ret = self.hnas_bend.check_lu("ssh", "0.0.0.0", "supervisor",
+                                      "supervisor",
+                                      "volume-8ddd1a54-0000-0000-000",
+                                      "test_hdp")
+        result, lunid, tgt = ret
+        self.assertFalse(result)
index 46c2af3d76a809669c16ab6c95561138350476c4..f5bb826d6216eeeaaf860570c567e935311e5c67 100644 (file)
@@ -82,7 +82,8 @@ HNAS_WRONG_CONF2 = """<?xml version="1.0" encoding="UTF-8" ?>
 # The following information is passed on to tests, when creating a volume
 _VOLUME = {'name': 'testvol', 'volume_id': '1234567890', 'size': 128,
            'volume_type': 'silver', 'volume_type_id': '1',
-           'provider_location': None, 'id': 'abcdefg',
+           'provider_location': '83-68-96-AA-DA-5D.volume-2dfe280e-470a-4182'
+                                '-afb8-1755025c35b8', 'id': 'abcdefg',
            'host': 'host1@hnas-iscsi-backend#silver'}
 
 
@@ -257,6 +258,16 @@ class SimulatedHnasBackend(object):
         self.out = """wGkJhTpXaaYJ5Rv"""
         return self.out
 
+    def get_evs(self, cmd, ip0, user, pw, fsid):
+        return '1'
+
+    def check_lu(self, cmd, ip0, user, pw, volume_name, hdp):
+        return True, 1, {'alias': 'cinder-default', 'secret': 'mysecret',
+                         'iqn': 'iqn.1993-08.org.debian:01:11f90746eb2'}
+
+    def check_target(self, cmd, ip0, user, pw, hdp, target_alias):
+        return False, None
+
 
 class HNASiSCSIDriverTest(test.TestCase):
     """Test HNAS iSCSI volume driver."""
@@ -426,3 +437,31 @@ class HNASiSCSIDriverTest(test.TestCase):
     def test_get_pool(self, m_ext_spec):
         label = self.driver.get_pool(_VOLUME)
         self.assertEqual('silver', label)
+
+    @mock.patch.object(time, 'sleep')
+    @mock.patch.object(iscsi.HDSISCSIDriver, '_update_vol_location')
+    def test_get_service_target(self, m_update_vol_location, m_sleep):
+
+        vol = _VOLUME.copy()
+        self.backend.check_lu = mock.MagicMock()
+        self.backend.check_target = mock.MagicMock()
+
+        # Test the case where volume is not already mapped - CHAP enabled
+        self.backend.check_lu.return_value = (False, 0, None)
+        self.backend.check_target.return_value = (False, None)
+        ret = self.driver._get_service_target(vol)
+        iscsi_ip, iscsi_port, ctl, svc_port, hdp, alias, secret = ret
+        self.assertEqual('evs1-tgt0', alias)
+
+        # Test the case where volume is not already mapped - CHAP disabled
+        self.driver.config['chap_enabled'] = 'False'
+        ret = self.driver._get_service_target(vol)
+        iscsi_ip, iscsi_port, ctl, svc_port, hdp, alias, secret = ret
+        self.assertEqual('evs1-tgt0', alias)
+
+        # Test the case where all targets are full
+        fake_tgt = {'alias': 'fake', 'luns': range(0, 32)}
+        self.backend.check_lu.return_value = (False, 0, None)
+        self.backend.check_target.return_value = (True, fake_tgt)
+        self.assertRaises(exception.NoMoreTargets,
+                          self.driver._get_service_target, vol)
index f0aa2a4f5e25d180588bee1feef976c626406262..6b2e434af4c702df0735969ec8c04e4dff488b8e 100644 (file)
@@ -25,7 +25,7 @@ from oslo_log import log as logging
 from oslo_utils import units
 import six
 
-from cinder.i18n import _, _LW, _LI
+from cinder.i18n import _, _LW, _LI, _LE
 from cinder import exception
 from cinder import ssh_utils
 from cinder import utils
@@ -44,11 +44,11 @@ class HnasBackend(object):
     def run_cmd(self, cmd, ip0, user, pw, *args, **kwargs):
         """Run a command on SMU or using SSH
 
-        :param cmd: the command that will be run on SMU
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
-        :returns: formated string with version information
+        :return: formated string with version information
         """
         LOG.debug('Enable ssh: %s',
                   six.text_type(self.drv_configs['ssh_enabled']))
@@ -116,11 +116,12 @@ class HnasBackend(object):
     def get_version(self, cmd, ver, ip0, user, pw):
         """Gets version information from the storage unit
 
+       :param cmd: ssc command name
        :param ver: string driver version
        :param ip0: string IP address of controller
        :param user: string user authentication for array
        :param pw: string password authentication for array
-       :returns: formated string with version information
+       :return: formated string with version information
        """
         if (self.drv_configs['ssh_enabled'] == 'True' and
                 self.drv_configs['cluster_admin_ip0'] is not None):
@@ -154,10 +155,11 @@ class HnasBackend(object):
     def get_iscsi_info(self, cmd, ip0, user, pw):
         """Gets IP addresses for EVSs, use EVSID as controller.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
-        :returns: formated string with iSCSI information
+        :return: formated string with iSCSI information
         """
 
         out, err = self.run_cmd(cmd, ip0, user, pw,
@@ -180,11 +182,12 @@ class HnasBackend(object):
     def get_hdp_info(self, cmd, ip0, user, pw, fslabel=None):
         """Gets the list of filesystems and fsids.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
         :param fslabel: filesystem label we want to get info
-        :returns: formated string with filesystems and fsids
+        :return: formated string with filesystems and fsids
         """
 
         if fslabel is None:
@@ -240,12 +243,19 @@ class HnasBackend(object):
                   {'out': newout, 'err': err})
         return newout
 
-    def _get_evs(self, cmd, ip0, user, pw, fsid):
-        """Gets the EVSID for the named filesystem."""
+    def get_evs(self, cmd, ip0, user, pw, fsid):
+        """Gets the EVSID for the named filesystem.
+
+        :param cmd: ssc command name
+        :param ip0: string IP address of controller
+        :param user: string user authentication for array
+        :param pw: string password authentication for array
+        :return: EVS id of the file system
+        """
 
         out, err = self.run_cmd(cmd, ip0, user, pw, "evsfs", "list",
                                 check_exit_code=True)
-        LOG.debug('get_evs: out %s', out)
+        LOG.debug('get_evs: out %s.', out)
 
         lines = out.split('\n')
         for line in lines:
@@ -292,9 +302,89 @@ class HnasBackend(object):
                     {'out': out, 'fslabel': fslabel})
         return 0
 
+    def _get_targets(self, cmd, ip0, user, pw, evsid, tgtalias=None):
+        """Get the target list of an EVS.
+
+        Get the target list of an EVS. Optionally can return the target
+        list of a specific target.
+        """
+
+        LOG.debug("Getting target list for evs %s, tgtalias: %s.",
+                  evsid, tgtalias)
+
+        try:
+            out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
+                                    "--evs", evsid, 'iscsi-target', 'list',
+                                    check_exit_code=True)
+        except putils.ProcessExecutionError as e:
+            LOG.error(_LE('Error getting iSCSI target info '
+                          'from EVS %(evs)s.'), {'evs': evsid})
+            LOG.debug("_get_targets out: %(out)s, err: %(err)s.",
+                      {'out': e.stdout, 'err': e.stderr})
+            return []
+
+        tgt_list = []
+        if 'No targets' in out:
+            LOG.debug("No targets found in EVS %(evsid)s.", {'evsid': evsid})
+            return tgt_list
+
+        tgt_raw_list = out.split('Alias')[1:]
+        for tgt_raw_info in tgt_raw_list:
+            tgt = {}
+            tgt['alias'] = tgt_raw_info.split('\n')[0].split(' ').pop()
+            tgt['iqn'] = tgt_raw_info.split('\n')[1].split(' ').pop()
+            tgt['secret'] = tgt_raw_info.split('\n')[3].split(' ').pop()
+            tgt['auth'] = tgt_raw_info.split('\n')[4].split(' ').pop()
+            luns = []
+            tgt_raw_info = tgt_raw_info.split('\n\n')[1]
+            tgt_raw_list = tgt_raw_info.split('\n')[2:]
+
+            for lun_raw_line in tgt_raw_list:
+                lun_raw_line = lun_raw_line.strip()
+                lun_raw_line = lun_raw_line.split(' ')
+                lun = {}
+                lun['id'] = lun_raw_line[0]
+                lun['name'] = lun_raw_line.pop()
+                luns.append(lun)
+
+            tgt['luns'] = luns
+
+            if tgtalias == tgt['alias']:
+                return [tgt]
+
+            tgt_list.append(tgt)
+
+        if tgtalias is not None:
+            # We tried to find  'tgtalias' but didn't find. Return a empty
+            # list.
+            LOG.debug("There's no target %(alias)s in EVS %(evsid)s.",
+                      {'alias': tgtalias, 'evsid': evsid})
+            return []
+
+        LOG.debug("Targets in EVS %(evs)s: %(tgtl)s.",
+                  {'evs': evsid, 'tgtl': tgt_list})
+        return tgt_list
+
+    def _get_unused_lunid(self, cmd, ip0, user, pw, tgt_info):
+
+        if len(tgt_info['luns']) == 0:
+            return 0
+
+        free_lun = 0
+        for lun in tgt_info['luns']:
+            if int(lun['id']) == free_lun:
+                free_lun += 1
+
+            if int(lun['id']) > free_lun:
+                # Found a free LUN number
+                break
+
+        return free_lun
+
     def get_nfs_info(self, cmd, ip0, user, pw):
         """Gets information on each NFS export.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -322,7 +412,7 @@ class HnasBackend(object):
                 fs = inf[3]
             if 'Transfer setting' in line and fs != "":
                 fsid = self._get_fsid(cmd, ip0, user, pw, fs)
-                evsid = self._get_evs(cmd, ip0, user, pw, fsid)
+                evsid = self.get_evs(cmd, ip0, user, pw, fsid)
                 ips = self._get_evsips(cmd, ip0, user, pw, evsid)
                 newout += "Export: %s Path: %s HDP: %s FSID: %s \
                            EVS: %s IPS: %s\n" \
@@ -339,6 +429,7 @@ class HnasBackend(object):
         If the operation can not be performed for some reason, utils.execute()
         throws an error and aborts the operation. Used for iSCSI only
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -349,7 +440,7 @@ class HnasBackend(object):
                   successfully created'
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-lu', 'add', "-e",
@@ -361,12 +452,13 @@ class HnasBackend(object):
         out = "LUN %s HDP: %s size: %s MB, is successfully created" \
               % (name, hdp, size)
 
-        LOG.debug('create_lu: %s', out)
+        LOG.debug('create_lu: %s.', out)
         return out
 
     def delete_lu(self, cmd, ip0, user, pw, hdp, lun):
         """Delete an logical unit. Used for iSCSI only
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -375,14 +467,14 @@ class HnasBackend(object):
         :returns: formated string 'Logical unit deleted successfully.'
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-lu', 'del', '-d',
                                 '-f', lun,
                                 check_exit_code=True)
 
-        LOG.debug('delete_lu: %(out)s -- %(err)s', {'out': out, 'err': err})
+        LOG.debug('delete_lu: %(out)s -- %(err)s.', {'out': out, 'err': err})
         return out
 
     def create_dup(self, cmd, ip0, user, pw, src_lun, hdp, size, name):
@@ -391,6 +483,7 @@ class HnasBackend(object):
         Clone primitive used to support all iSCSI snapshot/cloning functions.
         Used for iSCSI only.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -400,7 +493,7 @@ class HnasBackend(object):
         :returns: formated string
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-lu', 'clone', '-e',
@@ -411,7 +504,7 @@ class HnasBackend(object):
         out = "LUN %s HDP: %s size: %s MB, is successfully created" \
               % (name, hdp, size)
 
-        LOG.debug('create_dup: %(out)s -- %(err)s', {'out': out, 'err': err})
+        LOG.debug('create_dup: %(out)s -- %(err)s.', {'out': out, 'err': err})
         return out
 
     def file_clone(self, cmd, ip0, user, pw, fslabel, src, name):
@@ -419,6 +512,7 @@ class HnasBackend(object):
 
         Clone primitive used to support all NFS snapshot/cloning functions.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -429,7 +523,7 @@ class HnasBackend(object):
         """
 
         _fsid = self._get_fsid(cmd, ip0, user, pw, fslabel)
-        _evsid = self._get_evs(cmd, ip0, user, pw, _fsid)
+        _evsid = self.get_evs(cmd, ip0, user, pw, _fsid)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'file-clone-create', '-f', fslabel,
@@ -438,12 +532,13 @@ class HnasBackend(object):
 
         out = "LUN %s HDP: %s Clone: %s -> %s" % (name, _fsid, src, name)
 
-        LOG.debug('file_clone: %(out)s -- %(err)s', {'out': out, 'err': err})
+        LOG.debug('file_clone: %(out)s -- %(err)s.', {'out': out, 'err': err})
         return out
 
     def extend_vol(self, cmd, ip0, user, pw, hdp, lun, new_size, name):
         """Extend a iSCSI volume.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -453,7 +548,7 @@ class HnasBackend(object):
         :param name: formated string
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-lu', 'expand',
@@ -462,81 +557,59 @@ class HnasBackend(object):
 
         out = ("LUN: %s successfully extended to %s MB" % (name, new_size))
 
-        LOG.debug('extend_vol: %s', out)
+        LOG.debug('extend_vol: %s.', out)
         return out
 
     @utils.retry(putils.ProcessExecutionError, retries=HNAS_SSC_RETRIES)
-    def add_iscsi_conn(self, cmd, ip0, user, pw, lun, hdp,
-                       port, iqn, initiator):
+    def add_iscsi_conn(self, cmd, ip0, user, pw, lun_name, hdp,
+                       port, tgtalias, initiator):
         """Setup the lun on on the specified target port
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
-        :param lun: id of the logical unit being extended
+        :param lun_name: id of the logical unit being extended
         :param hdp: data pool of the logical unit
         :param port: iSCSI port
-        :param iqn: iSCSI qualified name
+        :param tgtalias: iSCSI qualified name
         :param initiator: initiator address
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
-        out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
-                                "--evs", _evsid,
-                                'iscsi-target', 'list', iqn,
-                                check_exit_code=True)
-
-        # even though ssc uses the target alias, need to return the full iqn
-        fulliqn = ""
-        lines = out.split('\n')
-        for line in lines:
-            if 'Globally unique name' in line:
-                fulliqn = line.split()[3]
-
-        # find first free hlun
-        hlun = 0
-        for line in lines:
-            if line.startswith('  '):
-                lunline = line.split()[0]
-                vol = line.split()[1]
-                if lunline[0].isdigit():
-                    # see if already mounted
-                    if vol[:29] == lun[:29]:
-                        LOG.info(_LI('lun: %(lun)s already mounted %(lline)s'),
-                                 {'lun': lun, 'lline': lunline})
-                        conn = (int(lunline), lun, initiator, hlun, fulliqn,
-                                hlun, hdp, port)
-                        out = "H-LUN: %d alreadymapped LUN: %s, iSCSI \
-                               Initiator: %s @ index: %d, and Target: %s \
-                               @ index %d is successfully paired  @ CTL: \
-                               %s, Port: %s" % conn
-                        LOG.debug('add_iscsi_conn: returns %s', out)
-                        return out
-
-                    if int(lunline) == hlun:
-                        hlun += 1
-                    if int(lunline) > hlun:
-                        # found a hole
-                        break
+        LOG.debug('Adding %(lun)s to %(tgt)s returns %(tgt)s.',
+                  {'lun': lun_name, 'tgt': tgtalias})
+        found, lunid, tgt = self.check_lu(cmd, ip0, user, pw, lun_name, hdp)
+        evsid = self.get_evs(cmd, ip0, user, pw, hdp)
+
+        if found:
+            conn = (int(lunid), lun_name, initiator, int(lunid), tgt['iqn'],
+                    int(lunid), hdp, port)
+            out = ("H-LUN: %d mapped LUN: %s, iSCSI Initiator: %s "
+                   "@ index: %d, and Target: %s @ index %d is "
+                   "successfully paired  @ CTL: %s, Port: %s.") % conn
+        else:
+            tgt = self._get_targets(cmd, ip0, user, pw, evsid, tgtalias)
+            lunid = self._get_unused_lunid(cmd, ip0, user, pw, tgt[0])
 
-        out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
-                                "--evs", _evsid,
-                                'iscsi-target', 'addlu',
-                                iqn, lun, six.text_type(hlun),
-                                check_exit_code=True)
+            out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
+                                    "--evs", evsid,
+                                    'iscsi-target', 'addlu',
+                                    tgtalias, lun_name, six.text_type(lunid),
+                                    check_exit_code=True)
 
-        conn = (int(hlun), lun, initiator, int(hlun), fulliqn, int(hlun),
-                hdp, port)
-        out = "H-LUN: %d mapped LUN: %s, iSCSI Initiator: %s \
-               @ index: %d, and Target: %s @ index %d is \
-               successfully paired  @ CTL: %s, Port: %s" % conn
+            conn = (int(lunid), lun_name, initiator, int(lunid), tgt[0]['iqn'],
+                    int(lunid), hdp, port)
+            out = ("H-LUN: %d mapped LUN: %s, iSCSI Initiator: %s "
+                   "@ index: %d, and Target: %s @ index %d is "
+                   "successfully paired  @ CTL: %s, Port: %s.") % conn
 
-        LOG.debug('add_iscsi_conn: returns %s', out)
+        LOG.debug('add_iscsi_conn: returns %s.', out)
         return out
 
     def del_iscsi_conn(self, cmd, ip0, user, pw, evsid, iqn, hlun):
         """Remove the lun on on the specified target port
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -563,7 +636,7 @@ class HnasBackend(object):
 
         if out != "":
             # hlun wasn't found
-            LOG.info(_LI('del_iscsi_conn: hlun not found %s'), out)
+            LOG.info(_LI('del_iscsi_conn: hlun not found %s.'), out)
             return out
 
         # remove the LU from the target
@@ -576,14 +649,14 @@ class HnasBackend(object):
         out = "H-LUN: %d successfully deleted from target %s" \
               % (int(hlun), iqn)
 
-        LOG.debug('del_iscsi_conn: %s', out)
+        LOG.debug('del_iscsi_conn: %s.', out)
         return out
 
     def get_targetiqn(self, cmd, ip0, user, pw, targetalias, hdp, secret):
         """Obtain the targets full iqn
 
-        Return the target's full iqn rather than its alias.
-
+        Returns the target's full iqn rather than its alias.
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -593,7 +666,7 @@ class HnasBackend(object):
         :return: string with full IQN
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-target', 'list', targetalias,
@@ -626,6 +699,7 @@ class HnasBackend(object):
     def set_targetsecret(self, cmd, ip0, user, pw, targetalias, hdp, secret):
         """Sets the chap secret for the specified target.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -634,7 +708,7 @@ class HnasBackend(object):
         :param secret: CHAP secret of the target
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-target', 'list',
@@ -659,6 +733,7 @@ class HnasBackend(object):
     def get_targetsecret(self, cmd, ip0, user, pw, targetalias, hdp):
         """Returns the chap secret for the specified target.
 
+        :param cmd: ssc command name
         :param ip0: string IP address of controller
         :param user: string user authentication for array
         :param pw: string password authentication for array
@@ -667,7 +742,7 @@ class HnasBackend(object):
         :return secret: CHAP secret of the target
         """
 
-        _evsid = self._get_evs(cmd, ip0, user, pw, hdp)
+        _evsid = self.get_evs(cmd, ip0, user, pw, hdp)
         out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
                                 "--evs", _evsid,
                                 'iscsi-target', 'list', targetalias,
@@ -687,3 +762,65 @@ class HnasBackend(object):
             return secret
         else:
             return ""
+
+    def check_target(self, cmd, ip0, user, pw, hdp, target_alias):
+        """Checks if a given target exists and gets its info
+
+        :param cmd: ssc command name
+        :param ip0: string IP address of controller
+        :param user: string user authentication for array
+        :param pw: string password authentication for array
+        :param hdp: pool name used
+        :param target_alias: alias of the target
+        :return True if target exists
+        :return list with the target info
+        """
+
+        LOG.debug("Checking if target %(tgt)s exists.", {'tgt': target_alias})
+        evsid = self.get_evs(cmd, ip0, user, pw, hdp)
+        tgt_list = self._get_targets(cmd, ip0, user, pw, evsid)
+
+        for tgt in tgt_list:
+            if tgt['alias'] == target_alias:
+                attached_luns = len(tgt['luns'])
+                LOG.debug("Target %(tgt)s has %(lun)s volumes.",
+                          {'tgt': target_alias, 'lun': attached_luns})
+                return True, tgt
+
+        LOG.debug("Target %(tgt)s does not exist.", {'tgt': target_alias})
+        return False, None
+
+    def check_lu(self, cmd, ip0, user, pw, volume_name, hdp):
+        """Checks if a given LUN is already mapped
+
+        :param cmd: ssc command name
+        :param ip0: string IP address of controller
+        :param user: string user authentication for array
+        :param pw: string password authentication for array
+        :param volume_name: number of the LUN
+        :param hdp: storage pool of the LUN
+        :return True if the lun is attached
+        :return the LUN id
+        :return Info related to the target
+        """
+
+        LOG.debug("Checking if vol %s (hdp: %s) is attached.",
+                  volume_name, hdp)
+        evsid = self.get_evs(cmd, ip0, user, pw, hdp)
+        tgt_list = self._get_targets(cmd, ip0, user, pw, evsid)
+
+        for tgt in tgt_list:
+            if len(tgt['luns']) == 0:
+                continue
+
+            for lun in tgt['luns']:
+                lunid = lun['id']
+                lunname = lun['name']
+                if lunname[:29] == volume_name[:29]:
+                    LOG.debug("LUN %(lun)s attached on %(lunid)s, "
+                              "target: %(tgt)s.",
+                              {'lun': volume_name, 'lunid': lunid, 'tgt': tgt})
+                    return True, lunid, tgt
+
+        LOG.debug("LUN %(lun)s not attached.", {'lun': volume_name})
+        return False, 0, None
index 925d72583fd2fb9347e896fe4276f5aa4cb5482e..d48d7900a79641c547ae510112f66f171db0bc2b 100644 (file)
@@ -18,6 +18,7 @@
 iSCSI Cinder Volume driver for Hitachi Unified Storage (HUS-HNAS) platform.
 """
 import os
+import six
 from xml.etree import ElementTree as ETree
 
 from oslo_concurrency import processutils
@@ -26,6 +27,7 @@ from oslo_log import log as logging
 from oslo_utils import excutils
 from oslo_utils import units
 
+
 from cinder import exception
 from cinder.i18n import _, _LE, _LI, _LW
 from cinder import utils as cinder_utils
@@ -35,7 +37,7 @@ from cinder.volume import utils
 from cinder.volume import volume_types
 
 
-HDS_HNAS_ISCSI_VERSION = '3.1.0'
+HDS_HNAS_ISCSI_VERSION = '3.3.0'
 
 LOG = logging.getLogger(__name__)
 
@@ -50,6 +52,7 @@ CONF.register_opts(iSCSI_OPTS)
 HNAS_DEFAULT_CONFIG = {'hnas_cmd': 'ssc',
                        'chap_enabled': 'True',
                        'ssh_port': '22'}
+MAX_HNAS_ISCSI_TARGETS = 32
 
 
 def factory_bend(drv_configs):
@@ -157,7 +160,10 @@ class HDSISCSIDriver(driver.ISCSIDriver):
     """HDS HNAS volume driver.
 
     Version 1.0.0: Initial driver version
-    Version 2.2.0:  Added support to SSH authentication
+    Version 2.2.0: Added support to SSH authentication
+    Version 3.2.0: Added pool aware scheduling
+                   Fixed concurrency errors
+    Version 3.3.0: Fixed iSCSI target limitation error
     """
 
     def __init__(self, *args, **kwargs):
@@ -213,10 +219,12 @@ class HDSISCSIDriver(driver.ISCSIDriver):
         return conf
 
     def _get_service(self, volume):
-        """Get available service parameters.
+        """Get the available service parameters
 
-        Get the available service parameters for a given volume using its type.
-        :param volume: dictionary volume reference
+           Get the available service parametersfor a given volume using its
+           type.
+           :param volume: dictionary volume reference
+           :return HDP related to the service
         """
 
         label = utils.extract_host(volume['host'], level='pool')
@@ -224,68 +232,145 @@ class HDSISCSIDriver(driver.ISCSIDriver):
 
         if label in self.config['services'].keys():
             svc = self.config['services'][label]
-            # HNAS - one time lookup
-            # see if the client supports CHAP authentication and if
-            # iscsi_secret has already been set, retrieve the secret if
-            # available, otherwise generate and store
-            if self.config['chap_enabled'] == 'True':
-                # it may not exist, create and set secret
-                if 'iscsi_secret' not in svc:
-                    LOG.info(_LI("Retrieving secret for service: %s"), label)
-
-                    out = self.bend.get_targetsecret(self.config['hnas_cmd'],
-                                                     self.config['mgmt_ip0'],
-                                                     self.config['username'],
-                                                     self.config['password'],
-                                                     'cinder-' + label,
-                                                     svc['hdp'])
-                    svc['iscsi_secret'] = out
-                    if svc['iscsi_secret'] == "":
-                        svc['iscsi_secret'] = utils.generate_password()[0:15]
-                        self.bend.set_targetsecret(self.config['hnas_cmd'],
-                                                   self.config['mgmt_ip0'],
-                                                   self.config['username'],
-                                                   self.config['password'],
-                                                   'cinder-' + label,
-                                                   svc['hdp'],
-                                                   svc['iscsi_secret'])
-
-                        LOG.info(_LI("Set tgt CHAP secret for service: %s"),
-                                 label)
-            else:
-                # We set blank password when the client does not
-                # support CHAP. Later on, if the client tries to create a new
-                # target that does not exists in the backend, we check for this
-                # value and use a temporary dummy password.
-                if 'iscsi_secret' not in svc:
-                    # Warns in the first time
-                    LOG.info(_LI("CHAP authentication disabled"))
-
-                svc['iscsi_secret'] = ""
-
-            if 'iscsi_target' not in svc:
-                LOG.info(_LI("Retrieving target for service: %s"), label)
-
-                out = self.bend.get_targetiqn(self.config['hnas_cmd'],
-                                              self.config['mgmt_ip0'],
-                                              self.config['username'],
-                                              self.config['password'],
-                                              'cinder-' + label,
-                                              svc['hdp'],
-                                              svc['iscsi_secret'])
-                svc['iscsi_target'] = out
-
-            self.config['services'][label] = svc
-
-            service = (svc['iscsi_ip'], svc['iscsi_port'], svc['ctl'],
-                       svc['port'], svc['hdp'], svc['iscsi_target'],
-                       svc['iscsi_secret'])
+            return svc['hdp']
         else:
-            LOG.info(_LI("Available services: %s"),
+            LOG.info(_LI("Available services: %s."),
                      self.config['services'].keys())
-            LOG.error(_LE("No configuration found for service: %s"), label)
+            LOG.error(_LE("No configuration found for service: %s."), label)
             raise exception.ParameterNotFound(param=label)
 
+    def _get_service_target(self, volume):
+        """Get the available service parameters
+
+           Get the available service parameters for a given volume using
+           its type.
+           :param volume: dictionary volume reference
+        """
+
+        hdp = self._get_service(volume)
+        info = _loc_info(volume['provider_location'])
+        (arid, lun_name) = info['id_lu']
+
+        evsid = self.bend.get_evs(self.config['hnas_cmd'],
+                                  self.config['mgmt_ip0'],
+                                  self.config['username'],
+                                  self.config['password'],
+                                  hdp)
+        svc_label = utils.extract_host(volume['host'], level='pool')
+        svc = self.config['services'][svc_label]
+
+        LOG.info(_LI("_get_service_target hdp: %s."), hdp)
+        LOG.info(_LI("config[services]: %s."), self.config['services'])
+
+        mapped, lunid, tgt = self.bend.check_lu(self.config['hnas_cmd'],
+                                                self.config['mgmt_ip0'],
+                                                self.config['username'],
+                                                self.config['password'],
+                                                lun_name, hdp)
+
+        LOG.info(_LI("Target is %(map)s! Targetlist = %(tgtl)s."),
+                 {'map': "mapped" if mapped else "not mapped", 'tgtl': tgt})
+
+        # The volume is already mapped to a LUN, so no need to create any
+        # targets
+        if mapped:
+            service = (svc['iscsi_ip'], svc['iscsi_port'], svc['ctl'],
+                       svc['port'], hdp, tgt['alias'], tgt['secret'])
+            return service
+
+        # Each EVS can have up to 32 targets. Each target can have up to 32
+        # LUNs attached and have the name format 'evs<id>-tgt<0-N>'. We run
+        # from the first 'evs1-tgt0' until we find a target that is not already
+        # created in the BE or is created but have slots to place new targets.
+        found_tgt = False
+        for i in range(0, MAX_HNAS_ISCSI_TARGETS):
+            tgt_alias = 'evs' + evsid + '-tgt' + six.text_type(i)
+            # TODO(erlon): we need to go to the BE 32 times here
+            tgt_exist, tgt = self.bend.check_target(self.config['hnas_cmd'],
+                                                    self.config['mgmt_ip0'],
+                                                    self.config['username'],
+                                                    self.config['password'],
+                                                    hdp, tgt_alias)
+            if tgt_exist and len(tgt['luns']) < 32 or not tgt_exist:
+                # Target exists and has free space or, target does not exist
+                # yet. Proceed and use the target or create a target using this
+                # name.
+                found_tgt = True
+                break
+
+        # If we've got here and found_tgt is not True, we run out of targets,
+        # raise and go away.
+        if not found_tgt:
+            LOG.error(_LE("No more targets avaliable."))
+            raise exception.NoMoreTargets(param=tgt_alias)
+
+        LOG.info(_LI("Using target label: %s."), tgt_alias)
+
+        # Check if we have a secret stored for this target so we don't have to
+        # go to BE on every query
+        if 'targets' not in self.config.keys():
+            self.config['targets'] = {}
+
+        if tgt_alias not in self.config['targets'].keys():
+            self.config['targets'][tgt_alias] = {}
+
+        tgt_info = self.config['targets'][tgt_alias]
+
+        # HNAS - one time lookup
+        # see if the client supports CHAP authentication and if
+        # iscsi_secret has already been set, retrieve the secret if
+        # available, otherwise generate and store
+        if self.config['chap_enabled'] == 'True':
+            # It may not exist, create and set secret.
+            if 'iscsi_secret' not in tgt_info.keys():
+                LOG.info(_LI("Retrieving secret for service: %s."),
+                         tgt_alias)
+
+                out = self.bend.get_targetsecret(self.config['hnas_cmd'],
+                                                 self.config['mgmt_ip0'],
+                                                 self.config['username'],
+                                                 self.config['password'],
+                                                 tgt_alias, hdp)
+                tgt_info['iscsi_secret'] = out
+                if tgt_info['iscsi_secret'] == "":
+                    randon_secret = utils.generate_password()[0:15]
+                    tgt_info['iscsi_secret'] = randon_secret
+                    self.bend.set_targetsecret(self.config['hnas_cmd'],
+                                               self.config['mgmt_ip0'],
+                                               self.config['username'],
+                                               self.config['password'],
+                                               tgt_alias, hdp,
+                                               tgt_info['iscsi_secret'])
+
+                    LOG.info(_LI("Set tgt CHAP secret for service: %s."),
+                             tgt_alias)
+        else:
+            # We set blank password when the client does not
+            # support CHAP. Later on, if the client tries to create a new
+            # target that does not exists in the backend, we check for this
+            # value and use a temporary dummy password.
+            if 'iscsi_secret' not in tgt_info.keys():
+                # Warns in the first time
+                LOG.info(_LI("CHAP authentication disabled."))
+
+            tgt_info['iscsi_secret'] = ""
+
+        if 'tgt_iqn' not in tgt_info:
+            LOG.info(_LI("Retrieving target for service: %s."), tgt_alias)
+
+            out = self.bend.get_targetiqn(self.config['hnas_cmd'],
+                                          self.config['mgmt_ip0'],
+                                          self.config['username'],
+                                          self.config['password'],
+                                          tgt_alias, hdp,
+                                          tgt_info['iscsi_secret'])
+            tgt_info['tgt_iqn'] = out
+
+        self.config['targets'][tgt_alias] = tgt_info
+
+        service = (svc['iscsi_ip'], svc['iscsi_port'], svc['ctl'],
+                   svc['port'], hdp, tgt_alias, tgt_info['iscsi_secret'])
+
         return service
 
     def _get_stats(self):
@@ -306,7 +391,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
                                          self.config['password'],
                                          pool['hdp'])
 
-            LOG.debug('Query for pool %(pool)s: %(out)s',
+            LOG.debug('Query for pool %(pool)s: %(out)s.',
                       {'pool': pool['pool_name'], 'out': out})
 
             (hdp, size, _ign, used) = out.split()[1:5]  # in MB
@@ -318,7 +403,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
 
         hnas_stat['pools'] = self.pools
 
-        LOG.info(_LI("stats: stats: %s"), hnas_stat)
+        LOG.info(_LI("stats: stats: %s."), hnas_stat)
         return hnas_stat
 
     def _get_hdp_list(self):
@@ -456,8 +541,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
         :param volume: dictionary volume reference
         """
 
-        service = self._get_service(volume)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(volume)
         out = self.bend.create_lu(self.config['hnas_cmd'],
                                   self.config['mgmt_ip0'],
                                   self.config['username'],
@@ -486,8 +570,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
         if src['size'] != dst['size']:
             msg = 'clone volume size mismatch'
             raise exception.VolumeBackendAPIException(data=msg)
-        service = self._get_service(dst)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(dst)
         size = int(src['size']) * units.Ki
         source_vol = self._id_to_vol(src['id'])
         (arid, slun) = _loc_info(source_vol['provider_location'])['id_lu']
@@ -512,8 +595,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
        :param new_size: int size in GB to extend
        """
 
-        service = self._get_service(volume)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(volume)
         (arid, lun) = _loc_info(volume['provider_location'])['id_lu']
         self.bend.extend_vol(self.config['hnas_cmd'],
                              self.config['mgmt_ip0'],
@@ -552,8 +634,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
 
         LOG.debug("delete lun %(lun)s on %(name)s", {'lun': lun, 'name': name})
 
-        service = self._get_service(volume)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(volume)
         self.bend.delete_lu(self.config['hnas_cmd'],
                             self.config['mgmt_ip0'],
                             self.config['username'],
@@ -572,24 +653,23 @@ class HDSISCSIDriver(driver.ISCSIDriver):
                  {'vol': volume, 'conn': connector})
 
         # connector[ip, host, wwnns, unititator, wwp/
-        service = self._get_service(volume)
-        (ip, ipp, ctl, port, _hdp, target, secret) = service
+
+        service_info = self._get_service_target(volume)
+        (ip, ipp, ctl, port, _hdp, tgtalias, secret) = service_info
         info = _loc_info(volume['provider_location'])
 
         if 'tgt' in info.keys():  # spurious repeat connection
             # print info.keys()
             LOG.debug("initiate_conn: tgt already set %s", info['tgt'])
-        (arid, lun) = info['id_lu']
-        loc = arid + '.' + lun
+        (arid, lun_name) = info['id_lu']
+        loc = arid + '.' + lun_name
         # sps, use target if provided
-        iqn = target
-
         try:
             out = self.bend.add_iscsi_conn(self.config['hnas_cmd'],
                                            self.config['mgmt_ip0'],
                                            self.config['username'],
                                            self.config['password'],
-                                           lun, _hdp, port, iqn,
+                                           lun_name, _hdp, port, tgtalias,
                                            connector['initiator'])
         except processutils.ProcessExecutionError:
             msg = _("Error attaching volume %s. "
@@ -600,7 +680,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
         # sps need hlun, fulliqn
         hlun = out.split()[1]
         fulliqn = out.split()[13]
-        tgt = hnas_portal + ',' + iqn + ',' + loc + ',' + ctl + ','
+        tgt = hnas_portal + ',' + tgtalias + ',' + loc + ',' + ctl + ','
         tgt += port + ',' + hlun
 
         LOG.info(_LI("initiate: connection %s"), tgt)
@@ -619,7 +699,9 @@ class HDSISCSIDriver(driver.ISCSIDriver):
             properties['auth_method'] = 'CHAP'
             properties['auth_password'] = secret
 
-        return {'driver_volume_type': 'iscsi', 'data': properties}
+        conn_info = {'driver_volume_type': 'iscsi', 'data': properties}
+        LOG.debug("initialize_connection: conn_info: %s.", conn_info)
+        return conn_info
 
     @cinder_utils.synchronized('volume_mapping')
     def terminate_connection(self, volume, connector, **kwargs):
@@ -634,13 +716,13 @@ class HDSISCSIDriver(driver.ISCSIDriver):
             LOG.warning(_LW("terminate_conn: provider location empty."))
             return
         (arid, lun) = info['id_lu']
-        (_portal, iqn, loc, ctl, port, hlun) = info['tgt']
+        (_portal, tgtalias, loc, ctl, port, hlun) = info['tgt']
         LOG.info(_LI("terminate: connection %s"), volume['provider_location'])
         self.bend.del_iscsi_conn(self.config['hnas_cmd'],
                                  self.config['mgmt_ip0'],
                                  self.config['username'],
                                  self.config['password'],
-                                 ctl, iqn, hlun)
+                                 ctl, tgtalias, hlun)
         self._update_vol_location(volume['id'], loc)
 
         return {'provider_location': loc}
@@ -654,8 +736,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
 
         size = int(snapshot['volume_size']) * units.Ki
         (arid, slun) = _loc_info(snapshot['provider_location'])['id_lu']
-        service = self._get_service(volume)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(volume)
         out = self.bend.create_dup(self.config['hnas_cmd'],
                                    self.config['mgmt_ip0'],
                                    self.config['username'],
@@ -676,8 +757,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
         """
 
         source_vol = self._id_to_vol(snapshot['volume_id'])
-        service = self._get_service(source_vol)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(source_vol)
         size = int(snapshot['volume_size']) * units.Ki
         (arid, slun) = _loc_info(source_vol['provider_location'])['id_lu']
         out = self.bend.create_dup(self.config['hnas_cmd'],
@@ -709,8 +789,7 @@ class HDSISCSIDriver(driver.ISCSIDriver):
 
         (arid, lun) = loc.split('.')
         source_vol = self._id_to_vol(snapshot['volume_id'])
-        service = self._get_service(source_vol)
-        (_ip, _ipp, _ctl, _port, hdp, target, secret) = service
+        hdp = self._get_service(source_vol)
         myid = self.arid
 
         if arid != myid: