Adding CHAP discovery logic to os-brick
The changes that were made to libvirt volume drivers to use os-brick, left out the code that provided credentials to discover iSCSI devices Essentially, the code responsible for updating iscsiadm's CHAP authentication parameters was left out Closes-Bug: #1481914 Change-Id: I3fa0132247374d89b9fdcfdba3e9b1eac502a2ad
This commit is contained in:
parent
d99fb09ee3
commit
2ff5d8edca
|
@ -104,3 +104,7 @@ class VolumePathNotRemoved(BrickException):
|
|||
|
||||
class ProtocolNotSupported(BrickException):
|
||||
message = _("Connect to volume via protocol %(protocol)s not supported.")
|
||||
|
||||
|
||||
class TargetPortalNotFound(BrickException):
|
||||
message = _("Unable to find target portal %(target_portal)s.")
|
||||
|
|
|
@ -339,18 +339,60 @@ class ISCSIConnector(InitiatorConnector):
|
|||
return zip(connection_properties['target_portals'],
|
||||
connection_properties['target_iqns'])
|
||||
|
||||
# Discover and return every available target
|
||||
out = self._run_iscsiadm_bare(['-m',
|
||||
'discovery',
|
||||
'-t',
|
||||
'sendtargets',
|
||||
'-p',
|
||||
connection_properties['target_portal']],
|
||||
check_exit_code=[0, 255])[0] \
|
||||
or ""
|
||||
out = None
|
||||
if connection_properties.get('discovery_auth_method'):
|
||||
try:
|
||||
self._run_iscsiadm_update_discoverydb(connection_properties)
|
||||
except putils.ProcessExecutionError as exception:
|
||||
# iscsiadm returns 6 for "db record not found"
|
||||
if exception.exit_code == 6:
|
||||
# Create a new record for this target and update the db
|
||||
self._run_iscsiadm_bare(
|
||||
['-m', 'discoverydb',
|
||||
'-t', 'sendtargets',
|
||||
'-p', connection_properties['target_portal'],
|
||||
'--op', 'new'],
|
||||
check_exit_code=[0, 255])
|
||||
self._run_iscsiadm_update_discoverydb(
|
||||
connection_properties
|
||||
)
|
||||
else:
|
||||
LOG.error(_LE("Unable to find target portal: "
|
||||
"%(target_portal)s."),
|
||||
{'target_portal': connection_properties[
|
||||
'target_portal']})
|
||||
raise
|
||||
out = self._run_iscsiadm_bare(
|
||||
['-m', 'discoverydb',
|
||||
'-t', 'sendtargets',
|
||||
'-p', connection_properties['target_portal'],
|
||||
'--discover'],
|
||||
check_exit_code=[0, 255])[0] or ""
|
||||
else:
|
||||
out = self._run_iscsiadm_bare(
|
||||
['-m', 'discovery',
|
||||
'-t', 'sendtargets',
|
||||
'-p', connection_properties['target_portal']],
|
||||
check_exit_code=[0, 255])[0] or ""
|
||||
|
||||
return self._get_target_portals_from_iscsiadm_output(out)
|
||||
|
||||
def _run_iscsiadm_update_discoverydb(self, connection_properties):
|
||||
return self._execute(
|
||||
'iscsiadm',
|
||||
'-m', 'discoverydb',
|
||||
'-t', 'sendtargets',
|
||||
'-p', connection_properties['target_portal'],
|
||||
'--op', 'update',
|
||||
'-n', "discovery.sendtargets.auth.authmethod",
|
||||
'-v', connection_properties['discovery_auth_method'],
|
||||
'-n', "discovery.sendtargets.auth.username",
|
||||
'-v', connection_properties['discovery_auth_username'],
|
||||
'-n', "discovery.sendtargets.auth.password",
|
||||
'-v', connection_properties['discovery_auth_password'],
|
||||
run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
|
||||
@synchronized('connect_volume')
|
||||
def connect_volume(self, connection_properties):
|
||||
"""Attach the volume to instance_name.
|
||||
|
@ -366,7 +408,11 @@ class ISCSIConnector(InitiatorConnector):
|
|||
|
||||
if self.use_multipath:
|
||||
# Multipath installed, discovering other targets if available
|
||||
ips_iqns = self._discover_iscsi_portals(connection_properties)
|
||||
try:
|
||||
ips_iqns = self._discover_iscsi_portals(connection_properties)
|
||||
except Exception:
|
||||
raise exception.TargetPortalNotFound(
|
||||
target_portal=connection_properties['target_portal'])
|
||||
|
||||
if not connection_properties.get('target_iqns'):
|
||||
# There are two types of iSCSI multipath devices. One which
|
||||
|
|
|
@ -228,6 +228,26 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
|
|||
}
|
||||
}
|
||||
|
||||
def iscsi_connection_chap(self, volume, location, iqn, auth_method,
|
||||
auth_username, auth_password,
|
||||
discovery_auth_method, discovery_auth_username,
|
||||
discovery_auth_password):
|
||||
return {
|
||||
'driver_volume_type': 'iscsi',
|
||||
'data': {
|
||||
'auth_method': auth_method,
|
||||
'auth_username': auth_username,
|
||||
'auth_password': auth_password,
|
||||
'discovery_auth_method': discovery_auth_method,
|
||||
'discovery_auth_username': discovery_auth_username,
|
||||
'discovery_auth_password': discovery_auth_password,
|
||||
'target_lun': 1,
|
||||
'volume_id': volume['id'],
|
||||
'target_iqn': iqn,
|
||||
'target_portal': location,
|
||||
}
|
||||
}
|
||||
|
||||
def test_get_initiator(self):
|
||||
def initiator_no_file(*args, **kwargs):
|
||||
raise putils.ProcessExecutionError('No file')
|
||||
|
@ -427,6 +447,52 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
|
|||
'type': 'block'}
|
||||
self.assertEqual(result, expected_result)
|
||||
|
||||
@mock.patch.object(connector.ISCSIConnector,
|
||||
'_run_iscsiadm_update_discoverydb')
|
||||
@mock.patch.object(os.path, 'exists', return_value=True)
|
||||
def test_iscsi_portals_with_chap_discovery(
|
||||
self, exists, update_discoverydb):
|
||||
location = '10.0.2.15:3260'
|
||||
name = 'volume-00000001'
|
||||
iqn = 'iqn.2010-10.org.openstack:%s' % name
|
||||
vol = {'id': 1, 'name': name}
|
||||
auth_method = 'CHAP'
|
||||
auth_username = 'fake_chap_username'
|
||||
auth_password = 'fake_chap_password'
|
||||
discovery_auth_method = 'CHAP'
|
||||
discovery_auth_username = 'fake_chap_username'
|
||||
discovery_auth_password = 'fake_chap_password'
|
||||
connection_properties = self.iscsi_connection_chap(
|
||||
vol, location, iqn, auth_method, auth_username, auth_password,
|
||||
discovery_auth_method, discovery_auth_username,
|
||||
discovery_auth_password)
|
||||
self.connector_with_multipath = connector.ISCSIConnector(
|
||||
None, execute=self.fake_execute, use_multipath=True)
|
||||
self.cmds = []
|
||||
# The first call returns an error code = 6, mocking an empty
|
||||
# discovery db. The second one mocks a successful return and the
|
||||
# third one a dummy exit code, which will trigger the
|
||||
# TargetPortalNotFound exception in connect_volume
|
||||
update_discoverydb.side_effect = [
|
||||
putils.ProcessExecutionError(None, None, 6),
|
||||
("", ""),
|
||||
putils.ProcessExecutionError(None, None, 9)]
|
||||
|
||||
self.connector_with_multipath._discover_iscsi_portals(
|
||||
connection_properties['data'])
|
||||
update_discoverydb.assert_called_with(connection_properties['data'])
|
||||
|
||||
expected_cmds = [
|
||||
'iscsiadm -m discoverydb -t sendtargets -p %s --op new' %
|
||||
location,
|
||||
'iscsiadm -m discoverydb -t sendtargets -p %s --discover' %
|
||||
location]
|
||||
self.assertEqual(expected_cmds, self.cmds)
|
||||
|
||||
self.assertRaises(exception.TargetPortalNotFound,
|
||||
self.connector_with_multipath.connect_volume,
|
||||
connection_properties['data'])
|
||||
|
||||
@mock.patch.object(os.path, 'exists', return_value=True)
|
||||
@mock.patch.object(host_driver.HostDriver, 'get_all_block_devices')
|
||||
@mock.patch.object(connector.ISCSIConnector, '_get_multipath_device_map',
|
||||
|
@ -1055,7 +1121,7 @@ class AoEConnectorTestCase(ConnectorTestCase):
|
|||
|
||||
@mock.patch.object(os.path, 'exists', side_effect=[True, True])
|
||||
def test_connect_volume(self, exists_mock):
|
||||
"""Ensure that if path exist aoe-revaliadte was called."""
|
||||
"""Ensure that if path exist aoe-revalidate was called."""
|
||||
aoe_device, aoe_path = self.connector._get_aoe_info(
|
||||
self.connection_properties)
|
||||
with mock.patch.object(self.connector, '_execute',
|
||||
|
|
Loading…
Reference in New Issue