Merge "NetApp ONTAP: Fix iSCSI multiattach volume terminates connection" into stable/train
This commit is contained in:
commit
2479cd3e69
|
@ -538,6 +538,15 @@ test_snapshot.volume_id = 'fake_volume_id'
|
||||||
test_snapshot.provider_location = PROVIDER_LOCATION
|
test_snapshot.provider_location = PROVIDER_LOCATION
|
||||||
|
|
||||||
|
|
||||||
|
class test_iscsi_attachment(object):
|
||||||
|
def __getattr__(self, key):
|
||||||
|
return getattr(self, key)
|
||||||
|
|
||||||
|
|
||||||
|
test_iscsi_attachment = test_iscsi_attachment()
|
||||||
|
test_iscsi_attachment.connector = ISCSI_CONNECTOR
|
||||||
|
|
||||||
|
|
||||||
def get_fake_net_interface_get_iter_response():
|
def get_fake_net_interface_get_iter_response():
|
||||||
return etree.XML("""<results status="passed">
|
return etree.XML("""<results status="passed">
|
||||||
<num-records>1</num-records>
|
<num-records>1</num-records>
|
||||||
|
|
|
@ -260,6 +260,33 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||||
'fake_volume', fake.FC_FORMATTED_INITIATORS,
|
'fake_volume', fake.FC_FORMATTED_INITIATORS,
|
||||||
protocol, None)
|
protocol, None)
|
||||||
|
|
||||||
|
def test__is_multiattached_true(self):
|
||||||
|
volume = copy.deepcopy(fake.test_volume)
|
||||||
|
volume.multiattach = True
|
||||||
|
volume.volume_attachment = [
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertTrue(self.library._is_multiattached(
|
||||||
|
volume,
|
||||||
|
fake.ISCSI_CONNECTOR))
|
||||||
|
|
||||||
|
def test__is_multiattached_false(self):
|
||||||
|
volume1 = copy.deepcopy(fake.test_volume)
|
||||||
|
volume1.multiattach = True
|
||||||
|
volume1.volume_attachment = []
|
||||||
|
volume2 = copy.deepcopy(fake.test_volume)
|
||||||
|
volume2.multiattach = False
|
||||||
|
volume2.volume_attachment = []
|
||||||
|
|
||||||
|
self.assertFalse(self.library._is_multiattached(
|
||||||
|
volume1,
|
||||||
|
fake.ISCSI_CONNECTOR))
|
||||||
|
self.assertFalse(self.library._is_multiattached(
|
||||||
|
volume2,
|
||||||
|
fake.ISCSI_CONNECTOR))
|
||||||
|
|
||||||
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
|
||||||
'_find_mapped_lun_igroup')
|
'_find_mapped_lun_igroup')
|
||||||
def test_unmap_lun_empty(self, mock_find_mapped_lun_igroup):
|
def test_unmap_lun_empty(self, mock_find_mapped_lun_igroup):
|
||||||
|
@ -302,6 +329,50 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||||
fake.ISCSI_MULTI_MAP_LIST[1]['initiator-group'])]
|
fake.ISCSI_MULTI_MAP_LIST[1]['initiator-group'])]
|
||||||
self.zapi_client.unmap_lun.assert_has_calls(calls)
|
self.zapi_client.unmap_lun.assert_has_calls(calls)
|
||||||
|
|
||||||
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary, '_unmap_lun')
|
||||||
|
def test_terminate_connection_iscsi_multiattach(self, mock_unmap_lun):
|
||||||
|
volume = copy.deepcopy(fake.test_volume)
|
||||||
|
volume.multiattach = True
|
||||||
|
volume.volume_attachment = [
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
]
|
||||||
|
|
||||||
|
self.library.terminate_connection_iscsi(volume, fake.ISCSI_CONNECTOR)
|
||||||
|
|
||||||
|
mock_unmap_lun.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary, '_unmap_lun')
|
||||||
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary, '_get_lun_attr')
|
||||||
|
def test_terminate_connection_iscsi_last_attachment(self,
|
||||||
|
mock_get_lun_attr,
|
||||||
|
mock_unmap_lun):
|
||||||
|
mock_get_lun_attr.return_value = {'Path': fake.PATH}
|
||||||
|
volume = copy.deepcopy(fake.test_volume)
|
||||||
|
volume.multiattach = True
|
||||||
|
volume.volume_attachment = [fake.test_iscsi_attachment]
|
||||||
|
|
||||||
|
self.library.terminate_connection_iscsi(volume, fake.ISCSI_CONNECTOR)
|
||||||
|
|
||||||
|
mock_unmap_lun.assert_called_once_with(
|
||||||
|
fake.PATH, [fake.ISCSI_CONNECTOR['initiator']])
|
||||||
|
|
||||||
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary, '_unmap_lun')
|
||||||
|
@mock.patch.object(block_base.NetAppBlockStorageLibrary, '_get_lun_attr')
|
||||||
|
def test_terminate_connection_iscsi_all_initiators(self, mock_get_lun_attr,
|
||||||
|
mock_unmap_lun):
|
||||||
|
mock_get_lun_attr.return_value = {'Path': fake.PATH}
|
||||||
|
volume = copy.deepcopy(fake.test_volume)
|
||||||
|
volume.multiattach = True
|
||||||
|
volume.volume_attachment = [
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
fake.test_iscsi_attachment,
|
||||||
|
]
|
||||||
|
|
||||||
|
self.library.terminate_connection_iscsi(volume, None)
|
||||||
|
|
||||||
|
mock_unmap_lun.assert_called_once_with(fake.PATH, [])
|
||||||
|
|
||||||
def test_find_mapped_lun_igroup(self):
|
def test_find_mapped_lun_igroup(self):
|
||||||
self.assertRaises(NotImplementedError,
|
self.assertRaises(NotImplementedError,
|
||||||
self.library._find_mapped_lun_igroup,
|
self.library._find_mapped_lun_igroup,
|
||||||
|
|
|
@ -888,12 +888,30 @@ class NetAppBlockStorageLibrary(object):
|
||||||
targets = target_details_list
|
targets = target_details_list
|
||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
def _is_multiattached(self, volume, connector):
|
||||||
|
"""Returns whether the volume is multiattached.
|
||||||
|
|
||||||
|
Returns True if the volume is attached to multiple instances using the
|
||||||
|
same initiator as the given one.
|
||||||
|
Returns False otherwise.
|
||||||
|
"""
|
||||||
|
if not volume.multiattach or not volume.volume_attachment:
|
||||||
|
return False
|
||||||
|
|
||||||
|
same_connector = (True for at in volume.volume_attachment
|
||||||
|
if at.connector and
|
||||||
|
at.connector['initiator'] == connector['initiator'])
|
||||||
|
next(same_connector, False)
|
||||||
|
return next(same_connector, False)
|
||||||
|
|
||||||
def terminate_connection_iscsi(self, volume, connector, **kwargs):
|
def terminate_connection_iscsi(self, volume, connector, **kwargs):
|
||||||
"""Driver entry point to unattach a volume from an instance.
|
"""Driver entry point to unattach a volume from an instance.
|
||||||
|
|
||||||
Unmask the LUN on the storage system so the given initiator can no
|
Unmask the LUN on the storage system so the given initiator can no
|
||||||
longer access it.
|
longer access it.
|
||||||
"""
|
"""
|
||||||
|
if connector and self._is_multiattached(volume, connector):
|
||||||
|
return
|
||||||
|
|
||||||
name = volume['name']
|
name = volume['name']
|
||||||
if connector is None:
|
if connector is None:
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
NetApp ONTAP: Fixes `bug 1839384
|
||||||
|
<https://bugs.launchpad.net/cinder/+bug/1839384>`__ Detaching any instance
|
||||||
|
from multiattached volume terminates connection. Now the connection is
|
||||||
|
terminated only if there're no other instances using the same initiator.
|
Loading…
Reference in New Issue