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
3dcdce39e5
commit
52103be3e1
|
@ -13,10 +13,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import fixtures
|
||||
import contextlib
|
||||
import os
|
||||
import time
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import exception
|
||||
|
@ -480,6 +482,9 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
|
|||
connection_info['data']['device_path'] = mpdev_filepath
|
||||
target_portals = ['fake_portal1', 'fake_portal2']
|
||||
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]])
|
||||
|
@ -540,6 +545,66 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
|
|||
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)
|
||||
|
@ -585,6 +650,9 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
|
|||
}
|
||||
target_portals = ['fake_portal1', 'fake_portal2']
|
||||
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]])
|
||||
|
|
|
@ -415,7 +415,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