Merge "Improve iSCSI device detection speed"

This commit is contained in:
Zuul 2018-09-11 15:44:23 +00:00 committed by Gerrit Code Review
commit d2af123c66
2 changed files with 86 additions and 11 deletions

View File

@ -618,8 +618,16 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
device = hctl = None
portal = props['target_portal']
session, manual_scan = self._connect_to_iscsi_portal(props)
do_scans = rescans > 0
retry = 1
do_scans = rescans > 0 or manual_scan
# Scan is sent on connect by iscsid, but we must do it manually on
# manual scan mode. This scan cannot count towards total rescans.
if manual_scan:
num_rescans = -1
seconds_next_scan = 0
else:
num_rescans = 0
seconds_next_scan = 4
if session:
data['num_logins'] += 1
LOG.debug('Connected to %s', portal)
@ -628,11 +636,12 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
if not hctl:
hctl = self._linuxscsi.get_hctl(session,
props['target_lun'])
# Scan is sent on connect by iscsid, so skip first rescan
# but on manual scan mode we have to do it ourselves.
if hctl:
if retry > 1 or manual_scan:
if seconds_next_scan <= 0:
num_rescans += 1
self._linuxscsi.scan_iscsi(*hctl)
# 4 seconds on 1st rescan, 9s on 2nd, 16s on 3rd
seconds_next_scan = (num_rescans + 2) ** 2
device = self._linuxscsi.device_name_by_hctl(session,
hctl)
@ -642,11 +651,12 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
except Exception:
LOG.exception('Exception scanning %s', portal)
pass
retry += 1
do_scans = (retry <= rescans and
do_scans = (num_rescans <= rescans and
not (device or data['stop_connecting']))
if do_scans:
time.sleep(retry ** 2)
time.sleep(1)
seconds_next_scan -= 1
if device:
LOG.debug('Connected to %s using %s', device,
strutils.mask_password(props))

View File

@ -1291,12 +1291,13 @@ Setting up iSCSI targets: unused
find_dm_mock.assert_not_called()
self.assertEqual(12, connect_mock.call_count)
@mock.patch('time.sleep', mock.Mock())
@mock.patch('time.sleep')
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
return_value='sda')
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
def test_connect_vol(self, connect_mock, dev_name_mock, scan_mock):
def test_connect_vol(self, connect_mock, dev_name_mock, scan_mock,
sleep_mock):
lscsi = self.connector._linuxscsi
data = self._get_connect_vol_data()
hctl = [mock.sentinel.host, mock.sentinel.channel,
@ -1319,8 +1320,72 @@ Setting up iSCSI targets: unused
mock.call(mock.sentinel.session,
self.CON_PROPS['target_lun'])])
scan_mock.assert_called_once_with(*hctl)
scan_mock.assert_not_called()
dev_name_mock.assert_called_once_with(mock.sentinel.session, hctl)
sleep_mock.assert_called_once_with(1)
@mock.patch('time.sleep')
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
side_effect=(None, None, None, None, 'sda'))
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
def test_connect_vol_rescan(self, connect_mock, dev_name_mock, scan_mock,
sleep_mock):
lscsi = self.connector._linuxscsi
data = self._get_connect_vol_data()
hctl = [mock.sentinel.host, mock.sentinel.channel,
mock.sentinel.target, mock.sentinel.lun]
connect_mock.return_value = (mock.sentinel.session, False)
with mock.patch.object(lscsi, 'get_hctl',
return_value=hctl) as hctl_mock:
self.connector._connect_vol(3, self.CON_PROPS, data)
expected = self._get_connect_vol_data()
expected.update(num_logins=1, stopped_threads=1,
found_devices=['sda'], just_added_devices=['sda'])
self.assertDictEqual(expected, data)
connect_mock.assert_called_once_with(self.CON_PROPS)
hctl_mock.assert_called_once_with(mock.sentinel.session,
self.CON_PROPS['target_lun'])
scan_mock.assert_called_once_with(*hctl)
self.assertEqual(5, dev_name_mock.call_count)
self.assertEqual(4, sleep_mock.call_count)
@mock.patch('time.sleep')
@mock.patch.object(linuxscsi.LinuxSCSI, 'scan_iscsi')
@mock.patch.object(linuxscsi.LinuxSCSI, 'device_name_by_hctl',
side_effect=(None, None, None, None, 'sda'))
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal')
def test_connect_vol_manual(self, connect_mock, dev_name_mock, scan_mock,
sleep_mock):
lscsi = self.connector._linuxscsi
data = self._get_connect_vol_data()
hctl = [mock.sentinel.host, mock.sentinel.channel,
mock.sentinel.target, mock.sentinel.lun]
# Simulate manual scan
connect_mock.return_value = (mock.sentinel.session, True)
with mock.patch.object(lscsi, 'get_hctl',
return_value=hctl) as hctl_mock:
self.connector._connect_vol(3, self.CON_PROPS, data)
expected = self._get_connect_vol_data()
expected.update(num_logins=1, stopped_threads=1,
found_devices=['sda'], just_added_devices=['sda'])
self.assertDictEqual(expected, data)
connect_mock.assert_called_once_with(self.CON_PROPS)
hctl_mock.assert_called_once_with(mock.sentinel.session,
self.CON_PROPS['target_lun'])
self.assertEqual(2, scan_mock.call_count)
self.assertEqual(5, dev_name_mock.call_count)
self.assertEqual(4, sleep_mock.call_count)
@mock.patch.object(iscsi.ISCSIConnector, '_connect_to_iscsi_portal',
return_value=(None, False))