Fix disconnecting necessary iSCSI sessions issue
In Icehouse with "iscsi_use_multipath=true", detaching a multipath
iSCSI volume kills all iSCSI volumes visible from the nova compute node.
When we use different targets(IQNs) associated with same portal for
each different multipath device, all of the targets will be deleted
via disconnect_volume().
This patch fixes the behavior of detaching volume:
1. Extract the targets for the detached multipath device.
2. Delete/disconnect the targets for the detached multipath device.
Closes-Bug: #1382440
(cherry picked from commit 36aeedfd5e
)
Conflicts:
nova/tests/unit/virt/libvirt/test_volume.py
Change-Id: I38eafdaee03d136282cfde1fd013e322a4256cc4
This commit is contained in:
parent
ee66c0436b
commit
7307dbaf6b
|
@ -341,6 +341,7 @@ Setting up iSCSI targets: unused
|
|||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
devs = ['/dev/disk/by-path/ip-%s-iscsi-%s-lun-2' % (self.location,
|
||||
self.iqn)]
|
||||
iscsi_devs = ['ip-fake-ip-iscsi-fake-portal-lun-2']
|
||||
with contextlib.nested(
|
||||
mock.patch.object(os.path, 'exists', return_value=True),
|
||||
mock.patch.object(self.fake_conn, '_get_all_block_devices',
|
||||
|
@ -349,14 +350,16 @@ Setting up iSCSI targets: unused
|
|||
mock.patch.object(libvirt_driver, '_run_multipath'),
|
||||
mock.patch.object(libvirt_driver, '_get_multipath_device_name',
|
||||
return_value='/dev/mapper/fake-multipath-devname'),
|
||||
mock.patch.object(libvirt_driver, '_get_iscsi_devices',
|
||||
return_value=iscsi_devs),
|
||||
mock.patch.object(libvirt_driver,
|
||||
'_get_target_portals_from_iscsiadm_output',
|
||||
return_value=[('fake-ip', 'fake-portal')]),
|
||||
mock.patch.object(libvirt_driver, '_get_multipath_iqn',
|
||||
return_value='fake-portal'),
|
||||
) as (mock_exists, mock_devices, mock_rescan_multipath,
|
||||
mock_run_multipath, mock_device_name, mock_get_portals,
|
||||
mock_get_iqn):
|
||||
mock_run_multipath, mock_device_name, mock_iscsi_devices,
|
||||
mock_get_portals, mock_get_iqn):
|
||||
mock_run_multipath.side_effect = processutils.ProcessExecutionError
|
||||
vol = {'id': 1, 'name': self.name}
|
||||
connection_info = self.iscsi_connection(vol, self.location,
|
||||
|
@ -619,6 +622,9 @@ Setting up iSCSI targets: unused
|
|||
mpdev_filepath = '/dev/mapper/foo'
|
||||
connection_info['data']['device_path'] = mpdev_filepath
|
||||
libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath
|
||||
iscsi_devs = ['ip-%s-iscsi-%s-lun-0' % (self.location, self.iqn)]
|
||||
self.stubs.Set(libvirt_driver, '_get_iscsi_devices',
|
||||
lambda: iscsi_devs)
|
||||
self.stubs.Set(libvirt_driver,
|
||||
'_get_target_portals_from_iscsiadm_output',
|
||||
lambda x: [[self.location, self.iqn]])
|
||||
|
@ -679,6 +685,66 @@ Setting up iSCSI targets: unused
|
|||
self.mox.ReplayAll()
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
|
||||
def test_libvirt_kvm_volume_with_multipath_disconnected(self):
|
||||
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
|
||||
volumes = [{'name': self.name,
|
||||
'location': self.location,
|
||||
'iqn': self.iqn,
|
||||
'mpdev_filepath': '/dev/mapper/disconnect'},
|
||||
{'name': 'volume-00000002',
|
||||
'location': '10.0.2.15:3260',
|
||||
'iqn': 'iqn.2010-10.org.openstack:volume-00000002',
|
||||
'mpdev_filepath': '/dev/mapper/donotdisconnect'}]
|
||||
iscsi_devs = ['ip-%s-iscsi-%s-lun-1' % (volumes[0]['location'],
|
||||
volumes[0]['iqn']),
|
||||
'ip-%s-iscsi-%s-lun-1' % (volumes[1]['location'],
|
||||
volumes[1]['iqn'])]
|
||||
|
||||
def _get_multipath_device_name(path):
|
||||
if '%s-lun-1' % volumes[0]['iqn'] in path:
|
||||
return volumes[0]['mpdev_filepath']
|
||||
else:
|
||||
return volumes[1]['mpdev_filepath']
|
||||
|
||||
def _get_multipath_iqn(mpdev):
|
||||
if volumes[0]['mpdev_filepath'] == mpdev:
|
||||
return volumes[0]['iqn']
|
||||
else:
|
||||
return volumes[1]['iqn']
|
||||
|
||||
with contextlib.nested(
|
||||
mock.patch.object(os.path, 'exists', return_value=True),
|
||||
mock.patch.object(self.fake_conn, '_get_all_block_devices',
|
||||
retrun_value=[volumes[1]['mpdev_filepath']]),
|
||||
mock.patch.object(libvirt_driver, '_get_multipath_device_name',
|
||||
_get_multipath_device_name),
|
||||
mock.patch.object(libvirt_driver, '_get_multipath_iqn',
|
||||
_get_multipath_iqn),
|
||||
mock.patch.object(libvirt_driver, '_get_iscsi_devices',
|
||||
return_value=iscsi_devs),
|
||||
mock.patch.object(libvirt_driver,
|
||||
'_get_target_portals_from_iscsiadm_output',
|
||||
return_value=[[volumes[0]['location'],
|
||||
volumes[0]['iqn']],
|
||||
[volumes[1]['location'],
|
||||
volumes[1]['iqn']]]),
|
||||
mock.patch.object(libvirt_driver, '_disconnect_mpath')
|
||||
) as (mock_exists, mock_devices, mock_device_name, mock_get_iqn,
|
||||
mock_iscsi_devices, mock_get_portals, mock_disconnect_mpath):
|
||||
vol = {'id': 1, 'name': volumes[0]['name']}
|
||||
connection_info = self.iscsi_connection(vol,
|
||||
volumes[0]['location'],
|
||||
volumes[0]['iqn'])
|
||||
connection_info['data']['device_path'] =\
|
||||
volumes[0]['mpdev_filepath']
|
||||
libvirt_driver.use_multipath = True
|
||||
libvirt_driver.disconnect_volume(connection_info, 'vde')
|
||||
# Ensure that the mpath device is disconnected.
|
||||
ips_iqns = []
|
||||
ips_iqns.append([volumes[0]['location'], volumes[0]['iqn']])
|
||||
mock_disconnect_mpath.assert_called_once_with(
|
||||
connection_info['data'], ips_iqns)
|
||||
|
||||
def test_libvirt_kvm_volume_with_multipath_getmpdev(self):
|
||||
self.flags(iscsi_use_multipath=True, group='libvirt')
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
|
@ -722,6 +788,9 @@ Setting up iSCSI targets: unused
|
|||
"type": "disk",
|
||||
}
|
||||
libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath
|
||||
iscsi_devs = ['ip-%s-iscsi-%s-lun-0' % (location, iqn)]
|
||||
self.stubs.Set(libvirt_driver, '_get_iscsi_devices',
|
||||
lambda: iscsi_devs)
|
||||
self.stubs.Set(libvirt_driver,
|
||||
'_get_target_portals_from_iscsiadm_output',
|
||||
lambda x: [[location, iqn]])
|
||||
|
|
|
@ -423,7 +423,23 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
|
|||
check_exit_code=[0, 255])[0] \
|
||||
or ""
|
||||
|
||||
ips_iqns = self._get_target_portals_from_iscsiadm_output(out)
|
||||
# Extract targets for the current multipath device.
|
||||
ips_iqns = []
|
||||
entries = self._get_iscsi_devices()
|
||||
for ip, iqn in self._get_target_portals_from_iscsiadm_output(out):
|
||||
ip_iqn = "%s-iscsi-%s" % (ip.split(",")[0], iqn)
|
||||
for entry in entries:
|
||||
entry_ip_iqn = entry.split("-lun-")[0]
|
||||
if entry_ip_iqn[:3] == "ip-":
|
||||
entry_ip_iqn = entry_ip_iqn[3:]
|
||||
if (ip_iqn != entry_ip_iqn):
|
||||
continue
|
||||
entry_real_path = os.path.realpath("/dev/disk/by-path/%s" %
|
||||
entry)
|
||||
entry_mpdev = self._get_multipath_device_name(entry_real_path)
|
||||
if entry_mpdev == multipath_device:
|
||||
ips_iqns.append([ip, iqn])
|
||||
break
|
||||
|
||||
if not devices:
|
||||
# disconnect if no other multipath devices
|
||||
|
|
Loading…
Reference in New Issue