[Pure Storage] Ensure multiattach volumes are not disconnected early

Change-Id: I5135a48326f5f7adb0a380b55993660b8b38ce27
Closes-Bug: #1930748
(cherry picked from commit 0c5511f843)
(cherry picked from commit ba49980eca)
Depends-On: I53ab2c8dae43d5aef7a65d35ad99e55f0acb7431
This commit is contained in:
Simon Dodsley 2021-06-03 10:48:40 -04:00
parent c9457f860a
commit 1eaf389692
3 changed files with 52 additions and 10 deletions

View File

@ -604,6 +604,7 @@ class PureBaseSharedDriverTestCase(PureDriverTestCase):
vol.volume_type = voltype
vol.volume_type_id = voltype.id
vol.volume_attachment = None
return vol, vol_name
@ -3716,9 +3717,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

@ -611,8 +611,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
@ -643,11 +658,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"]
host_in_use = self._disconnect_host(array,
host_name,
vol_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:
@ -660,20 +680,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):
@ -2739,6 +2766,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):
@ -2747,7 +2779,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:
@ -2760,7 +2793,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.