diff --git a/os_brick/exception.py b/os_brick/exception.py index 2bff6f202..c928773d5 100644 --- a/os_brick/exception.py +++ b/os_brick/exception.py @@ -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") diff --git a/os_brick/initiator/connector.py b/os_brick/initiator/connector.py index 08c8ea0bc..cbab35036 100644 --- a/os_brick/initiator/connector.py +++ b/os_brick/initiator/connector.py @@ -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? diff --git a/os_brick/tests/initiator/test_connector.py b/os_brick/tests/initiator/test_connector.py index 48b2cf85a..82d78533a 100644 --- a/os_brick/tests/initiator/test_connector.py +++ b/os_brick/tests/initiator/test_connector.py @@ -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,