Failed to discovery when iscsi multipath and CHAP both enabled

Storage server may be configured to protect target discovering phase with CHAP
authentication, in this case existing discovery command will be failed.
The authentication properties are:
    "discovery.sendtargets.auth.authmethod",
    "discovery.sendtargets.auth.username",
    "discovery.sendtargets.auth.password"
Cinder Storage driver need to send discovery auth properties in this case,
and the properties are:
    iscsi_properties['discovery_auth_method']
    iscsi_properties['discovery_auth_username']
    iscsi_properties['discovery_auth_password']

Change-Id: Ic70426d7d0fd8126879840f05341731ed92d6392
Closes-Bug: #1367189
This commit is contained in:
TaoBai 2015-01-15 22:49:49 -08:00
parent 4f59f773e4
commit 45227bbbfd
2 changed files with 126 additions and 19 deletions

View File

@ -280,6 +280,27 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
ret['data']['auth_password'] = 'bar'
return ret
def iscsi_connection_discovery_chap_enable(self, volume, location, iqn):
dev_name = 'ip-%s-iscsi-%s-lun-1' % (location, iqn)
dev_path = '/dev/disk/by-path/%s' % (dev_name)
return {
'driver_volume_type': 'iscsi',
'data': {
'volume_id': volume['id'],
'target_portal': location,
'target_iqn': iqn,
'target_lun': 1,
'device_path': dev_path,
'discovery_auth_method': 'CHAP',
'discovery_auth_username': "testuser",
'discovery_auth_password': '123456',
'qos_specs': {
'total_bytes_sec': '102400',
'read_iops_sec': '200',
}
}
}
def generate_device(self, transport=None, lun=1, short=False):
dev_format = "ip-%s-iscsi-%s-lun-%s" % (self.location, self.iqn, lun)
if transport:
@ -682,6 +703,51 @@ Setting up iSCSI targets: unused
self.assertEqual(tree.find('./auth/secret').get('uuid'), SECRET_UUID)
libvirt_driver.disconnect_volume(connection_info, 'vde')
def test_libvirt_iscsi_driver_discovery_chap_enable(self):
# NOTE(vish) exists is to make driver assume connecting worked
self.stubs.Set(os.path, 'exists', lambda x: True)
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
libvirt_driver.use_multipath = True
connection_info = self.iscsi_connection_discovery_chap_enable(
self.vol, self.location,
self.iqn)
mpdev_filepath = '/dev/mapper/foo'
libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath
libvirt_driver.connect_volume(connection_info, self.disk_info)
libvirt_driver.disconnect_volume(connection_info, "vde")
expected_commands = [('iscsiadm', '-m', 'discoverydb',
'-t', 'sendtargets',
'-p', self.location, '--op', 'update',
'-n', 'discovery.sendtargets.auth.authmethod',
'-v', 'CHAP',
'-n', 'discovery.sendtargets.auth.username',
'-v', 'testuser',
'-n', 'discovery.sendtargets.auth.password',
'-v', '123456'),
('iscsiadm', '-m', 'discoverydb',
'-t', 'sendtargets',
'-p', self.location, '--discover'),
('iscsiadm', '-m', 'node', '--rescan'),
('iscsiadm', '-m', 'session', '--rescan'),
('multipath', '-r'),
('iscsiadm', '-m', 'node', '--rescan'),
('iscsiadm', '-m', 'session', '--rescan'),
('multipath', '-r'),
('iscsiadm', '-m', 'discoverydb',
'-t', 'sendtargets',
'-p', self.location, '--op', 'update',
'-n', 'discovery.sendtargets.auth.authmethod',
'-v', 'CHAP',
'-n', 'discovery.sendtargets.auth.username',
'-v', 'testuser',
'-n', 'discovery.sendtargets.auth.password',
'-v', '123456'),
('iscsiadm', '-m', 'discoverydb',
'-t', 'sendtargets',
'-p', self.location, '--discover'),
('multipath', '-r')]
self.assertEqual(self.executes, expected_commands)
def test_libvirt_kvm_volume(self):
self.stubs.Set(os.path, 'exists', lambda x: True)
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)

View File

@ -345,18 +345,12 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
"""Attach the volume to instance_name."""
iscsi_properties = connection_info['data']
# multipath installed, discovering other targets if available
# multipath should be configured on the nova-compute node,
# in order to fit storage vendor
out = None
if self.use_multipath:
# multipath installed, discovering other targets if available
# multipath should be configured on the nova-compute node,
# in order to fit storage vendor
out = self._run_iscsiadm_bare(['-m',
'discovery',
'-t',
'sendtargets',
'-p',
iscsi_properties['target_portal']],
check_exit_code=[0, 255])[0] \
or ""
out = self._run_iscsiadm_discover(iscsi_properties)
# There are two types of iSCSI multipath devices. One which shares
# the same iqn between multiple portals, and the other which use
@ -441,6 +435,60 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
connection_info['data']['device_path'] = host_device
def _run_iscsiadm_discover(self, iscsi_properties):
def run_iscsiadm_update_discoverydb():
return utils.execute(
'iscsiadm',
'-m', 'discoverydb',
'-t', 'sendtargets',
'-p', iscsi_properties['target_portal'],
'--op', 'update',
'-n', "discovery.sendtargets.auth.authmethod",
'-v', iscsi_properties['discovery_auth_method'],
'-n', "discovery.sendtargets.auth.username",
'-v', iscsi_properties['discovery_auth_username'],
'-n', "discovery.sendtargets.auth.password",
'-v', iscsi_properties['discovery_auth_password'],
run_as_root=True)
out = None
if iscsi_properties.get('discovery_auth_method'):
try:
run_iscsiadm_update_discoverydb()
except processutils.ProcessExecutionError as exc:
# iscsiadm returns 6 for "db record not found"
if exc.exit_code == 6:
(out, err) = utils.execute(
'iscsiadm',
'-m', 'discoverydb',
'-t', 'sendtargets',
'-p', iscsi_properties['target_portal'],
'--op', 'new',
run_as_root=True)
run_iscsiadm_update_discoverydb()
else:
raise
out = self._run_iscsiadm_bare(
['-m',
'discoverydb',
'-t',
'sendtargets',
'-p',
iscsi_properties['target_portal'],
'--discover'],
check_exit_code=[0, 255])[0] or ""
else:
out = self._run_iscsiadm_bare(
['-m',
'discovery',
'-t',
'sendtargets',
'-p',
iscsi_properties['target_portal']],
check_exit_code=[0, 255])[0] or ""
return out
@utils.synchronized('connect_volume')
def disconnect_volume(self, connection_info, disk_dev):
"""Detach the volume from instance_name."""
@ -518,14 +566,7 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
# Do a discovery to find all targets.
# Targets for multiple paths for the same multipath device
# may not be the same.
out = self._run_iscsiadm_bare(['-m',
'discovery',
'-t',
'sendtargets',
'-p',
iscsi_properties['target_portal']],
check_exit_code=[0, 255])[0] \
or ""
out = self._run_iscsiadm_discover(iscsi_properties)
# Extract targets for the current multipath device.
ips_iqns = []