INFINIDAT: support force detach

terminate_connection should support the case where "connector" is
None (force detach), in which case all volume connections should
be detached.

Change-Id: I67bc72891d5aec0161e20b2eefeedbe3a401e7c1
This commit is contained in:
Arnon Yaari 2018-01-18 16:57:28 +02:00
parent 71b869cf1d
commit 1d24144959
2 changed files with 50 additions and 14 deletions

View File

@ -74,8 +74,10 @@ class InfiniboxDriverTestCaseBase(test.TestCase):
# mock external library dependencies
infinisdk = self.patch("cinder.volume.drivers.infinidat.infinisdk")
capacity = self.patch("cinder.volume.drivers.infinidat.capacity")
self.patch("cinder.volume.drivers.infinidat.iqn")
self.patch("cinder.volume.drivers.infinidat.wwn")
self._iqn = self.patch("cinder.volume.drivers.infinidat.iqn")
self._wwn = self.patch("cinder.volume.drivers.infinidat.wwn")
self._wwn.WWN = mock.Mock
self._iqn.IQN = mock.Mock
capacity.byte = 1
capacity.GiB = units.Gi
infinisdk.core.exceptions.InfiniSDKException = FakeInfinisdkException
@ -507,6 +509,19 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
self.driver.delete_group_snapshot,
None, test_snapgroup, [test_snapshot])
def test_terminate_connection_force_detach(self):
mock_infinidat_host = mock.Mock()
mock_infinidat_host.get_ports.return_value = [
self._wwn.WWN(TEST_WWN_1)]
mock_mapping = mock.Mock()
mock_mapping.get_host.return_value = mock_infinidat_host
self._mock_volume.get_logical_units.return_value = [mock_mapping]
# connector is None - force detach - detach all mappings
self.driver.terminate_connection(test_volume, None)
# make sure we actually detached the host mapping
self._mock_host.unmap_volume.assert_called_once()
self._mock_host.safe_delete.assert_called_once()
class InfiniboxDriverTestCaseFC(InfiniboxDriverTestCaseBase):
def test_initialize_connection_multiple_wwpns(self):

View File

@ -381,6 +381,26 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
return dict(driver_volume_type='iscsi',
data=result_data)
def _get_ports_from_connector(self, infinidat_volume, connector):
if connector is None:
# If no connector was provided it is a force-detach - remove all
# host connections for the volume
if self._protocol == 'FC':
port_cls = wwn.WWN
else:
port_cls = iqn.IQN
ports = []
for lun_mapping in infinidat_volume.get_logical_units():
host_ports = lun_mapping.get_host().get_ports()
host_ports = [port for port in host_ports
if isinstance(port, port_cls)]
ports.extend(host_ports)
elif self._protocol == 'FC':
ports = [wwn.WWN(wwpn) for wwpn in connector['wwpns']]
else:
ports = [iqn.IQN(connector['initiator'])]
return ports
@fczm_utils.add_fc_zone
@infinisdk_to_cinder_exceptions
@coordination.synchronized('infinidat-{self.management_address}-lock')
@ -399,11 +419,10 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
infinidat_volume = self._get_infinidat_volume(volume)
if self._protocol == 'FC':
volume_type = 'fibre_channel'
ports = [wwn.WWN(wwpn) for wwpn in connector['wwpns']]
else:
volume_type = 'iscsi'
ports = [iqn.IQN(connector['initiator'])]
result_data = dict()
ports = self._get_ports_from_connector(infinidat_volume, connector)
for port in ports:
host_name = self._make_host_name(port)
host = self._system.hosts.safe_get(name=host_name)
@ -415,16 +434,18 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
host.unmap_volume(infinidat_volume)
except KeyError:
continue # volume mapping not found
# check if the host now doesn't have mappings
if host is not None and len(host.get_luns()) == 0:
host.safe_delete()
if self._protocol == 'FC':
# Create initiator-target mapping to delete host entry
target_wwpns = list(self._get_online_fc_ports())
target_wwpns, target_map = self._build_initiator_target_map(
connector, target_wwpns)
result_data = dict(target_wwn=target_wwpns,
initiator_target_map=target_map)
# check if the host now doesn't have mappings
if host is not None and len(host.get_luns()) == 0:
host.safe_delete()
if self._protocol == 'FC' and connector is not None:
# Create initiator-target mapping to delete host entry
# this is only relevant for regular (specific host) detach
target_wwpns = list(self._get_online_fc_ports())
target_wwpns, target_map = (
self._build_initiator_target_map(connector,
target_wwpns))
result_data = dict(target_wwn=target_wwpns,
initiator_target_map=target_map)
return dict(driver_volume_type=volume_type,
data=result_data)