Fix silent iSCSI login failures
This patch fixes an issue where every iSCSI login attempt fails and the code doesn't raise an exception. It used to silently fail with nothing but a log warning. The iSCSI connector now checks to make sure that at least 1 of the N potential target portals login attempts is successful. Change-Id: Id248c3f1b12385c9d26150c6aa9dd504c01d0df8 Closes-Bug: #1464988
This commit is contained in:
parent
dc8f8a170f
commit
166820ad11
|
@ -108,3 +108,7 @@ class ProtocolNotSupported(BrickException):
|
|||
|
||||
class TargetPortalNotFound(BrickException):
|
||||
message = _("Unable to find target portal %(target_portal)s.")
|
||||
|
||||
|
||||
class FailedISCSITargetPortalLogin(BrickException):
|
||||
message = _("Unable to login to iSCSI Target Portal")
|
||||
|
|
|
@ -446,6 +446,7 @@ class ISCSIConnector(InitiatorConnector):
|
|||
|
||||
device_info = {'type': 'block'}
|
||||
|
||||
connected_to_portal = False
|
||||
if self.use_multipath:
|
||||
# Multipath installed, discovering other targets if available
|
||||
try:
|
||||
|
@ -474,7 +475,8 @@ class ISCSIConnector(InitiatorConnector):
|
|||
props = copy.deepcopy(connection_properties)
|
||||
props['target_portal'] = ip
|
||||
props['target_iqn'] = iqn
|
||||
self._connect_to_iscsi_portal(props)
|
||||
if self._connect_to_iscsi_portal(props):
|
||||
connected_to_portal = True
|
||||
|
||||
self._rescan_iscsi()
|
||||
host_devices = self._get_device_path(connection_properties)
|
||||
|
@ -483,13 +485,19 @@ class ISCSIConnector(InitiatorConnector):
|
|||
for props in self._iterate_all_targets(connection_properties):
|
||||
if self._connect_to_iscsi_portal(props):
|
||||
target_props = props
|
||||
connected_to_portal = True
|
||||
host_devices = self._get_device_path(target_props)
|
||||
break
|
||||
else:
|
||||
LOG.warning(_LW(
|
||||
'Failed to connect to iSCSI portal %(portal)s.'),
|
||||
{'portal': props['target_portal']})
|
||||
|
||||
host_devices = self._get_device_path(target_props)
|
||||
# make sure we've logged into an iSCSI portal
|
||||
if not connected_to_portal:
|
||||
msg = _("Could not login to any iSCSI portal.")
|
||||
LOG.error(msg)
|
||||
raise exception.FailedISCSITargetPortalLogin(message=msg)
|
||||
|
||||
# The /dev/disk/by-path/... node is not always present immediately
|
||||
# TODO(justinsb): This retry-with-delay is a pattern, move to utils?
|
||||
|
|
|
@ -706,6 +706,54 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
|
|||
self.assertEqual(expected_result, result)
|
||||
self.assertEqual(expected_calls, mock_connect.call_args_list)
|
||||
|
||||
@mock.patch.object(os.path, 'exists', return_value=True)
|
||||
@mock.patch.object(connector.ISCSIConnector,
|
||||
'_get_target_portals_from_iscsiadm_output')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_connect_to_iscsi_portal')
|
||||
@mock.patch.object(host_driver.HostDriver, 'get_all_block_devices')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_get_iscsi_devices')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_rescan_multipath')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_run_multipath')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_get_multipath_device_name')
|
||||
def test_connect_volume_multipath_failed_iscsi_login(
|
||||
self, mock_device_name, mock_run_multipath,
|
||||
mock_rescan_multipath, mock_iscsi_devices, mock_devices,
|
||||
mock_connect, mock_portals, mock_exists):
|
||||
location1 = '10.0.2.15:3260'
|
||||
location2 = '10.0.3.15:3260'
|
||||
name1 = 'volume-00000001-1'
|
||||
name2 = 'volume-00000001-2'
|
||||
iqn1 = 'iqn.2010-10.org.openstack:%s' % name1
|
||||
iqn2 = 'iqn.2010-10.org.openstack:%s' % name2
|
||||
fake_multipath_dev = '/dev/mapper/fake-multipath-dev'
|
||||
vol = {'id': 1, 'name': name1}
|
||||
connection_properties = self.iscsi_connection(vol, location1, iqn1)
|
||||
devs = ['/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location1, iqn1),
|
||||
'/dev/disk/by-path/ip-%s-iscsi-%s-lun-2' % (location2, iqn2)]
|
||||
mock_devices.return_value = devs
|
||||
mock_iscsi_devices.return_value = devs
|
||||
mock_device_name.return_value = fake_multipath_dev
|
||||
mock_portals.return_value = [[location1, iqn1], [location2, iqn1],
|
||||
[location2, iqn2]]
|
||||
|
||||
mock_connect.return_value = False
|
||||
self.assertRaises(exception.FailedISCSITargetPortalLogin,
|
||||
self.connector_with_multipath.connect_volume,
|
||||
connection_properties['data'])
|
||||
|
||||
@mock.patch.object(connector.ISCSIConnector, '_connect_to_iscsi_portal')
|
||||
def test_connect_volume_failed_iscsi_login(self, mock_connect):
|
||||
location1 = '10.0.2.15:3260'
|
||||
name1 = 'volume-00000001-1'
|
||||
iqn1 = 'iqn.2010-10.org.openstack:%s' % name1
|
||||
vol = {'id': 1, 'name': name1}
|
||||
connection_properties = self.iscsi_connection(vol, location1, iqn1)
|
||||
|
||||
mock_connect.return_value = False
|
||||
self.assertRaises(exception.FailedISCSITargetPortalLogin,
|
||||
self.connector.connect_volume,
|
||||
connection_properties['data'])
|
||||
|
||||
@mock.patch.object(time, 'sleep')
|
||||
@mock.patch.object(os.path, 'exists', return_value=False)
|
||||
def test_connect_volume_with_not_found_device(self, exists_mock,
|
||||
|
|
Loading…
Reference in New Issue