diff --git a/drivers/iscsilib.py b/drivers/iscsilib.py index 62d00f80..79c0ff0e 100644 --- a/drivers/iscsilib.py +++ b/drivers/iscsilib.py @@ -480,7 +480,7 @@ def match_targetIQN(tgtIQN, s): return True # Extract IQN from iscsiadm -m session # Ex: tcp: [17] 10.220.98.9:3260,1 iqn.2009-01.xenrt.test:iscsi4181a93e - siqn = s.split(",")[1].split()[1] + siqn = s.split(",")[1].split()[1].strip() return (siqn == tgtIQN) @@ -489,6 +489,17 @@ def match_session(s): return regex.search(s, 0) +def _compare_sessions_to_tgt(session_output, tgtIQN, tgt=''): + for line in session_output.split('\n'): + if match_targetIQN(tgtIQN, line) and match_session(line): + if len(tgt): + if match_target(tgt, line): + return True + else: + return True + return False + + def _checkTGT(tgtIQN, tgt=''): if not is_iscsi_daemon_running(): return False @@ -501,14 +512,7 @@ def _checkTGT(tgtIQN, tgt=''): except Exception as e: util.SMlog("%s failed with %s" % (cmd, e.args)) stdout = "" - for line in stdout.split('\n'): - if match_targetIQN(tgtIQN, line) and match_session(line): - if len(tgt): - if match_target(tgt, line): - return True - else: - return True - return False + return _compare_sessions_to_tgt(stdout, tgtIQN, tgt) def get_rootdisk_IQNs(): diff --git a/tests/test_LVHDoISCSISR.py b/tests/test_LVHDoISCSISR.py index ab2735dc..47cd1dfd 100644 --- a/tests/test_LVHDoISCSISR.py +++ b/tests/test_LVHDoISCSISR.py @@ -1,10 +1,14 @@ +import os import unittest import unittest.mock as mock +import traceback + from uuid import uuid4 import SR import LVHDoISCSISR +import iscsilib from BaseISCSI import BaseISCSISR import SRCommand import util @@ -126,13 +130,29 @@ def test_1st_try_block_raise_RandomError( class TestLVHDoISCSISR(unittest.TestCase): def setUp(self): - util_patcher = mock.patch('LVHDoISCSISR.util') + util_patcher = mock.patch('LVHDoISCSISR.util', autospec=True) self.mock_util = util_patcher.start() + # self.mock_util.SMlog.side_effect = print + self.mock_util.isVDICommand = util.isVDICommand self.mock_util.sessions_less_than_targets = util.sessions_less_than_targets - baseiscsi_patcher = mock.patch('LVHDoISCSISR.BaseISCSI.BaseISCSISR') + + self.base_srs = set() + baseiscsi_patcher = mock.patch('LVHDoISCSISR.BaseISCSI.BaseISCSISR', + autospec=True) patched_baseiscsi = baseiscsi_patcher.start() - self.mock_baseiscsi = mock.create_autospec(BaseISCSISR) - patched_baseiscsi.return_value = self.mock_baseiscsi + patched_baseiscsi.side_effect = self.baseiscsi + lvhdsr_patcher = mock.patch ('LVHDoISCSISR.LVHDSR') + + iscsilib_patcher = mock.patch('LVHDoISCSISR.iscsilib', + autospec=True) + self.mock_iscsilib = iscsilib_patcher.start() + self.mock_iscsilib.discovery.side_effect = self.discovery + self.mock_iscsilib._checkTGT.side_effect = self._checkTGT + self.mock_iscsilib.login.side_effect = self.iscsi_login + self.discovery_data = {} + self.sessions = [] + + self.mock_lvhdsr = lvhdsr_patcher.start() self.mock_session = mock.MagicMock() xenapi_patcher = mock.patch('SR.XenAPI') mock_xenapi = xenapi_patcher.start() @@ -153,28 +173,81 @@ def deepcopy(to_copy): self.addCleanup(mock.patch.stopall) - dummy_cmd = mock.create_autospec(SRCommand) - dummy_cmd.dconf = { + def _checkTGT(self, tgtIQN, tgt=''): + all_sessions = '\n'.join(self.sessions) + matched = iscsilib._compare_sessions_to_tgt(all_sessions, tgtIQN, tgt) + return matched + + def discovery(self, target, port, chapuser, chappassword, + targetIQN="any", interfaceArray=["default"]): + return self.discovery_data.get(target, []) + + def iscsi_login(self, target, target_iqn, chauser, chappassword, + incoming_user, incoming_password, mpath): + print(f"Logging in {target} - {target_iqn}") + session_count = len(self.sessions) + self.sessions.append(f'tcp: [{session_count}] {target}:3260,1 {target_iqn}') + + @property + def mock_baseiscsi(self): + assert len(self.base_srs) == 1 + single_sr = None + for sr in self.base_srs: + single_sr = sr + + return single_sr + + def baseiscsi(self, srcmd, sr_uuid): + new_baseiscsi = mock.create_autospec(BaseISCSISR) + local_iqn = srcmd.dconf['localIQN'] + target_iqn = srcmd.dconf['targetIQN'] + target = srcmd.dconf['target'] + new_baseiscsi.localIQN = local_iqn + new_baseiscsi.targetIQN = target_iqn + new_baseiscsi.target = target + new_baseiscsi.path = os.path.join('/dev/iscsi', target_iqn, target) + new_baseiscsi.port = 3260 + new_baseiscsi.chapuser = srcmd.dconf.get('chapuser') + new_baseiscsi.chappassword = srcmd.dconf.get('chappassword') + new_baseiscsi.incoming_chapuser = srcmd.dconf.get('incoming_chapuser') + new_baseiscsi.incoming_chappassword = srcmd.dconf.get('incoming_chappassword') + self.base_srs.add(new_baseiscsi) + + return new_baseiscsi + + def create_test_sr(self, sr_cmd): + self.sr_uuid = str(uuid4()) + self.subject = LVHDoISCSISR.LVHDoISCSISR( + sr_cmd, self.sr_uuid) + + def create_sr_command( + self, additional_dconf=None, cmd=None, + target_iqn='iqn.2009-01.example.test:iscsi085e938a'): + + sr_cmd = mock.create_autospec(SRCommand) + sr_cmd.dconf = { 'SCSIid': '3600a098038313577792450384a4a6275', 'multihomelist': 'tgt1:3260,tgt2:3260', 'target': "10.70.89.34", - 'targetIQN': 'iqn.2009-01.example.test:iscsi085e938a' + 'targetIQN': target_iqn, + 'localIQN': 'iqn.2018-05.com.example:0d312804' } - dummy_cmd.params = { + if additional_dconf: + sr_cmd.dconf.update(additional_dconf) + + sr_cmd.params = { 'command': 'nop', 'session_ref': 'test_session', 'host_ref': 'test_host', 'sr_ref': 'sr_ref' } - dummy_cmd.cmd = None - - self.sr_uuid = str(uuid4()) - self.subject = LVHDoISCSISR.LVHDoISCSISR( - dummy_cmd, self.sr_uuid) + sr_cmd.cmd = cmd + return sr_cmd def test_check_sr_pbd_not_found(self): # Arrange self.mock_util.find_my_pbd.return_value = None + self.create_test_sr(self.create_sr_command()) # Act self.subject.check_sr(TEST_SR_UUID) @@ -189,6 +262,7 @@ def test_check_sr_correct_sessions_count(self): self.mock_session.xenapi.PBD.get_other_config.return_value = { 'iscsi_sessions': 2 } + self.create_test_sr(self.create_sr_command()) # Act self.subject.check_sr(TEST_SR_UUID) @@ -202,7 +276,7 @@ def test_check_sr_not_enough_sessions(self): self.mock_session.xenapi.PBD.get_other_config.return_value = { 'iscsi_sessions': 1 } - + self.create_test_sr(self.create_sr_command()) # Act self.subject.check_sr(TEST_SR_UUID) @@ -211,3 +285,76 @@ def test_check_sr_not_enough_sessions(self): self.mock_baseiscsi.attach.assert_called_with( TEST_SR_UUID ) + + def test_sr_attach_multi_session(self): + # Arrange + self.mock_util.find_my_pbd.return_value = 'my_pbd' + additional_dconf = { + 'multiSession': '10.207.6.60,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.3.65,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + '10.207.3.61,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.6.61,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.3.63,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + '10.207.6.62,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.3.62,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.3.60,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3393|' + '10.207.6.64,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + '10.207.6.65,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + '10.207.3.64,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + '10.207.6.63,3260,iqn.2009-11.com.infinidat:storage:infinibox-sn-3394|' + } + + tpg_data = [ + [ + ('10.207.3.60:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393'), + ('10.207.3.61:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393'), + ('10.207.3.62:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393')], + [ + ('10.207.3.63:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394'), + ('10.207.3.64:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394'), + ('10.207.3.65:3260', 1, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394')], + [ + ('10.207.6.60:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393'), + ('10.207.6.61:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393'), + ('10.207.6.62:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3393') + ], + [ + ('10.207.6.63:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394'), + ('10.207.6.64:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394'), + ('10.207.6.65:3260', 2, 'iqn.2009-11.com.infinidat:storage:infinibox-sn-3394') + ] + ] + + self.discovery_data = { + '10.207.3.60': tpg_data[0], + '10.207.3.61': tpg_data[0], + '10.207.3.62': tpg_data[0], + '10.207.3.63': tpg_data[1], + '10.207.3.64': tpg_data[1], + '10.207.3.65': tpg_data[1], + '10.207.6.60': tpg_data[2], + '10.207.6.61': tpg_data[2], + '10.207.6.62': tpg_data[2], + '10.207.6.63': tpg_data[3], + '10.207.6.64': tpg_data[3], + '10.207.6.65': tpg_data[3] + } + + # Create SR + self.create_test_sr(self.create_sr_command( + additional_dconf=additional_dconf, + cmd='sr_attach', + target_iqn='*')) + + # Act + self.subject.attach(TEST_SR_UUID) + + # Assert + # print(f"iscsilib calls {self.mock_iscsilib.mock_calls}") + attach_count = 0 + for sr in self.base_srs: + attach_count += sr.attach.call_count + + self.assertEqual(12, attach_count) + self.assertEqual(12, self.mock_iscsilib.discovery.call_count) + self.assertEqual(12, self.mock_iscsilib.login.call_count)