Merge "[Pure Storage] Ensure multiattach volumes are not disconnected early"
This commit is contained in:
commit
0caaa1fee5
@ -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)
|
||||
])
|
||||
|
||||
|
||||
|
@ -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"]
|
||||
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:
|
||||
@ -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)
|
||||
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user