Disconnect multipath iscsi may logout session

When disconnecting a volume multipath iscsi, we get multipath device
name through a dict(/dev/sdX:/dev/mapper/XXX) by key
"/dev/disk/by-path/entry". But we can not get multipath device because
of the unmatched key, then disconnect from iscsi portal. But in most
cases, we have others devices and the disconnecting may lead to others
devices cannot be used. This patch fixes it by translating the key
from"/dev/disk/by-path/entry" to "/dev/sdX".

Change-Id: Ia0cd914b4d9e5a050fa80eaebfecf1b384d9ee09
Closes-Bug: #1587256
This commit is contained in:
yuyafei 2016-05-31 15:47:24 +08:00
parent a2d38af095
commit 54d4525ff5
2 changed files with 24 additions and 10 deletions

View File

@ -1137,8 +1137,9 @@ class ISCSIConnector(BaseLinuxConnector):
if "/mapper/" in dev:
devices.append(dev)
else:
mpdev = mpath_map.get(dev)
if mpdev:
dev_name = self._linuxscsi.get_name_from_path(dev)
mpdev = mpath_map.get(dev_name)
if mpdev and mpdev not in devices:
devices.append(mpdev)
# Do a discovery to find all targets.

View File

@ -972,6 +972,7 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
'/dev/sdb': '/dev/mapper/mpathb'}
self.assertEqual(expected, self.connector._get_multipath_device_map())
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_name_from_path')
@mock.patch.object(connector.ISCSIConnector, '_get_multipath_device_map')
@mock.patch.object(connector.ISCSIConnector,
'_get_target_portals_from_iscsiadm_output')
@ -987,17 +988,20 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
self, exists_mock, multipath_iqn_mock, disconnect_mock,
get_all_devices_mock, get_iscsi_devices_mock,
rescan_multipath_mock, rescan_iscsi_mock, get_portals_mock,
get_multipath_device_map_mock):
get_multipath_device_map_mock, get_name_from_path_mock):
iqn1 = 'iqn.2013-01.ro.com.netapp:node.netapp01'
iqn2 = 'iqn.2013-01.ro.com.netapp:node.netapp02'
iqns = [iqn1, iqn2]
portal = '10.0.0.1:3260'
dev = ('ip-%s-iscsi-%s-lun-0' % (portal, iqn1))
dev_name = '/dev/sdx'
get_portals_mock.return_value = [[portal, iqn1]]
multipath_iqn_mock.return_value = iqns
get_name_from_path_mock.return_value = dev_name
get_all_devices_mock.return_value = [dev, '/dev/mapper/md-1']
get_multipath_device_map_mock.return_value = {dev: '/dev/mapper/md-3'}
get_multipath_device_map_mock.return_value = {
dev_name: '/dev/mapper/md-3'}
get_iscsi_devices_mock.return_value = []
fake_property = {'target_portal': portal,
'target_iqn': iqn1}
@ -1006,6 +1010,7 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
# Target in use by other mp devices, don't disconnect
self.assertFalse(disconnect_mock.called)
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_name_from_path')
@mock.patch.object(connector.ISCSIConnector,
'_get_target_portals_from_iscsiadm_output')
@mock.patch.object(connector.ISCSIConnector, '_rescan_iscsi')
@ -1020,18 +1025,21 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
def test_disconnect_volume_multipath_iscsi_other_targets(
self, exists_mock, multipath_iqn_mock, get_multipath_map_mock,
disconnect_mock, get_all_devices_mock, get_iscsi_devices_mock,
rescan_multipath_mock, rescan_iscsi_mock, get_portals_mock):
rescan_multipath_mock, rescan_iscsi_mock, get_portals_mock,
get_name_from_path_mock):
iqn1 = 'iqn.2010-10.org.openstack:target-1'
iqn2 = 'iqn.2010-10.org.openstack:target-2'
portal = '10.0.0.1:3260'
dev2 = ('ip-%s-iscsi-%s-lun-0' % (portal, iqn2))
dev_name = '/dev/sdx'
# Multiple targets are discovered, but only block devices for target-1
# is deleted and target-2 is in use.
get_portals_mock.return_value = [[portal, iqn1], [portal, iqn2]]
multipath_iqn_mock.return_value = [iqn2, iqn2]
get_name_from_path_mock.return_value = dev_name
get_all_devices_mock.return_value = [dev2, '/dev/mapper/md-1']
get_multipath_map_mock.return_value = {dev2: '/dev/mapper/md-3'}
get_multipath_map_mock.return_value = {dev_name: '/dev/mapper/md-3'}
get_iscsi_devices_mock.return_value = [dev2]
fake_property = {'target_portal': portal,
'target_iqn': iqn1}
@ -1040,6 +1048,7 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
# Only target-1 should be disconneced.
disconnect_mock.assert_called_once_with(fake_property)
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_name_from_path')
@mock.patch.object(connector.ISCSIConnector, '_get_multipath_device_map',
return_value={})
@mock.patch.object(connector.ISCSIConnector,
@ -1056,7 +1065,8 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
def test_disconnect_volume_multipath_iscsi_without_other_mp_devices(
self, exists_mock, disconnect_mock, get_all_devices_mock,
get_iscsi_devices_mock, rescan_multipath_mock, rescan_iscsi_mock,
get_portals_mock, get_multipath_device_map_mock):
get_portals_mock, get_multipath_device_map_mock,
get_name_from_path_mock):
portal = '10.0.2.15:3260'
name = 'volume-00000001'
iqn = 'iqn.2010-10.org.openstack:%s' % name
@ -1069,6 +1079,7 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
# Target not in use by other mp devices, disconnect
disconnect_mock.assert_called_once_with(fake_property)
@mock.patch.object(linuxscsi.LinuxSCSI, 'get_name_from_path')
@mock.patch.object(connector.ISCSIConnector, '_get_multipath_device_map',
return_value={})
@mock.patch.object(connector.ISCSIConnector,
@ -1083,15 +1094,17 @@ class ISCSIConnectorTestCase(ConnectorTestCase):
def test_disconnect_volume_multipath_iscsi_with_invalid_symlink(
self, exists_mock, disconnect_mock, get_all_devices_mock,
get_iscsi_devices_mock, rescan_multipath_mock, rescan_iscsi_mock,
get_portals_mock, get_multipath_device_map_mock):
get_portals_mock, get_multipath_device_map_mock,
get_name_from_path_mock):
# Simulate a broken symlink by returning False for os.path.exists(dev)
portal = '10.0.0.1:3260'
name = 'volume-00000001'
iqn = 'iqn.2010-10.org.openstack:%s' % name
dev = ('ip-%s-iscsi-%s-lun-0' % (portal, iqn))
dev_name = '/dev/sdx'
get_portals_mock.return_value = [[portal, iqn]]
get_all_devices_mock.return_value = [dev, '/dev/mapper/md-1']
get_name_from_path_mock.return_value = dev_name
get_all_devices_mock.return_value = [dev_name, '/dev/mapper/md-1']
get_iscsi_devices_mock.return_value = []
fake_property = {'target_portal': portal,