Merge "[Pure Storage] Ensure multiattach volumes are not disconnected early"

This commit is contained in:
Zuul 2021-06-19 15:16:07 +00:00 committed by Gerrit Code Review
commit 0caaa1fee5
3 changed files with 52 additions and 10 deletions

View File

@ -657,6 +657,7 @@ class PureBaseSharedDriverTestCase(PureDriverTestCase):
vol.volume_type = voltype
vol.volume_type_id = voltype.id
vol.volume_attachment = None
return vol, vol_name
@ -4060,9 +4061,9 @@ class PureFCDriverTestCase(PureBaseSharedDriverTestCase):
self.driver.terminate_connection(vol, FC_CONNECTOR)
mock_disconnect.assert_has_calls([
mock.call(mock_secondary, vol, FC_CONNECTOR,
remove_remote_hosts=False),
is_multiattach=False, remove_remote_hosts=False),
mock.call(self.array, vol, FC_CONNECTOR,
remove_remote_hosts=False)
is_multiattach=False, remove_remote_hosts=False)
])

View File

@ -690,8 +690,23 @@ class PureBaseVolumeDriver(san.SanDriver):
"""
raise NotImplementedError
def _is_multiattach_to_host(self, volume_attachment, host_name):
# When multiattach is enabled a volume could be attached to multiple
# instances which are hosted on the same Nova compute.
# Because Purity cannot recognize the volume is attached more than
# one instance we should keep the volume attached to the Nova compute
# until the volume is detached from the last instance
if not volume_attachment:
return False
attachment = [a for a in volume_attachment
if a.attach_status == "attached" and
a.attached_host == host_name]
return len(attachment) > 1
@pure_driver_debug_trace
def _disconnect(self, array, volume, connector, remove_remote_hosts=False):
def _disconnect(self, array, volume, connector, remove_remote_hosts=False,
is_multiattach=False):
"""Disconnect the volume from the host described by the connector.
If no connector is specified it will remove *all* attachments for
@ -722,11 +737,16 @@ class PureBaseVolumeDriver(san.SanDriver):
remote=remove_remote_hosts)
if hosts:
any_in_use = False
host_in_use = False
for host in hosts:
host_name = host["name"]
if not is_multiattach:
host_in_use = self._disconnect_host(array,
host_name,
vol_name)
else:
LOG.warning("Unable to disconnect host from volume. "
"Volume is multi-attached.")
any_in_use = any_in_use or host_in_use
return any_in_use
else:
@ -739,20 +759,27 @@ class PureBaseVolumeDriver(san.SanDriver):
def terminate_connection(self, volume, connector, **kwargs):
"""Terminate connection."""
vol_name = self._get_vol_name(volume)
# None `connector` indicates force detach, then delete all even
# if the volume is multi-attached.
multiattach = (connector is not None and
self._is_multiattach_to_host(volume.volume_attachment,
connector["host"]))
if self._is_vol_in_pod(vol_name):
# Try to disconnect from each host, they may not be online though
# so if they fail don't cause a problem.
for array in self._uniform_active_cluster_target_arrays:
try:
self._disconnect(array, volume, connector,
remove_remote_hosts=False)
remove_remote_hosts=False,
is_multiattach=multiattach)
except purestorage.PureError as err:
# Swallow any exception, just warn and continue
LOG.warning("Disconnect on secondary array failed with"
" message: %(msg)s", {"msg": err.text})
# Now disconnect from the current array
self._disconnect(self._get_current_array(), volume,
connector, remove_remote_hosts=False)
connector, remove_remote_hosts=False,
is_multiattach=multiattach)
@pure_driver_debug_trace
def _disconnect_host(self, array, host_name, vol_name):
@ -2901,6 +2928,11 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
def terminate_connection(self, volume, connector, **kwargs):
"""Terminate connection."""
vol_name = self._get_vol_name(volume)
# None `connector` indicates force detach, then delete all even
# if the volume is multi-attached.
multiattach = (connector is not None and
self._is_multiattach_to_host(volume.volume_attachment,
connector["host"]))
unused_wwns = []
if self._is_vol_in_pod(vol_name):
@ -2909,7 +2941,8 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
for array in self._uniform_active_cluster_target_arrays:
try:
no_more_connections = self._disconnect(
array, volume, connector, remove_remote_hosts=False)
array, volume, connector, remove_remote_hosts=False,
is_multiattach=multiattach)
if no_more_connections:
unused_wwns += self._get_array_wwns(array)
except purestorage.PureError as err:
@ -2922,7 +2955,8 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
current_array = self._get_current_array()
no_more_connections = self._disconnect(current_array,
volume, connector,
remove_remote_hosts=False)
remove_remote_hosts=False,
is_multiattach=multiattach)
if no_more_connections:
unused_wwns += self._get_array_wwns(current_array)

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Pure Storage `bug #1930748
<https://bugs.launchpad.net/cinder/+bug/1930748>`_: Fixed issues
with multiattched volumes being diconnected from a backend when
still listed as an attachment to an instance.