3PAR: Add force detach
support
Add support to force detach a volume from all hosts on 3PAR. Change-Id: I2ddd0be0d59018db43dca297585d5cb2ee459ede Closes-bug: #1686745
This commit is contained in:
parent
b53574cfb7
commit
abca1abc7b
@ -7015,6 +7015,45 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver):
|
||||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
def test_force_detach_volume(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
mock_client = self.setup_driver()
|
||||
|
||||
mock_client.getVLUNs.return_value = {
|
||||
'members': [{
|
||||
'active': False,
|
||||
'volumeName': self.VOLUME_3PAR_NAME,
|
||||
'hostname': self.FAKE_HOST,
|
||||
'lun': None, 'type': 0}]}
|
||||
|
||||
mock_client.queryHost.return_value = {
|
||||
'members': [{
|
||||
'name': self.FAKE_HOST
|
||||
}]
|
||||
}
|
||||
|
||||
mock_client.getHostVLUNs.side_effect = hpeexceptions.HTTPNotFound
|
||||
|
||||
expected = [
|
||||
mock.call.getVLUNs(),
|
||||
mock.call.deleteVLUN(
|
||||
self.VOLUME_3PAR_NAME,
|
||||
None,
|
||||
hostname=self.FAKE_HOST),
|
||||
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||
mock.call.deleteHost(self.FAKE_HOST)]
|
||||
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
self.driver.terminate_connection(self.volume, None)
|
||||
|
||||
mock_client.assert_has_calls(
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout)
|
||||
|
||||
@mock.patch('cinder.zonemanager.utils.create_lookup_service')
|
||||
def test_terminate_connection_with_lookup(self, mock_lookup):
|
||||
# setup_mock_client drive with default configuration
|
||||
|
@ -265,11 +265,12 @@ class HPE3PARCommon(object):
|
||||
differs from volume present in the source group in terms of
|
||||
extra-specs. bug #1744025
|
||||
4.0.6 - Monitor task of promoting a virtual copy. bug #1749642
|
||||
4.0.7 - Handle force detach case. bug #1686745
|
||||
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "4.0.6"
|
||||
VERSION = "4.0.7"
|
||||
|
||||
stats = {}
|
||||
|
||||
@ -1659,7 +1660,11 @@ class HPE3PARCommon(object):
|
||||
|
||||
def delete_vlun(self, volume, hostname, wwn=None, iqn=None):
|
||||
volume_name = self._get_3par_vol_name(volume['id'])
|
||||
vluns = self.client.getHostVLUNs(hostname)
|
||||
if hostname:
|
||||
vluns = self.client.getHostVLUNs(hostname)
|
||||
else:
|
||||
# In case of 'force detach', hostname is None
|
||||
vluns = self.client.getVLUNs()['members']
|
||||
|
||||
# When deleteing VLUNs, you simply need to remove the template VLUN
|
||||
# and any active VLUNs will be automatically removed. The template
|
||||
@ -1681,6 +1686,8 @@ class HPE3PARCommon(object):
|
||||
|
||||
# VLUN Type of MATCHED_SET 4 requires the port to be provided
|
||||
for vlun in volume_vluns:
|
||||
if hostname is None:
|
||||
hostname = vlun.get('hostname')
|
||||
if 'portPos' in vlun:
|
||||
self.client.deleteVLUN(volume_name, vlun['lun'],
|
||||
hostname=hostname,
|
||||
@ -1721,6 +1728,8 @@ class HPE3PARCommon(object):
|
||||
# host, so it is worth the unlikely risk.
|
||||
|
||||
try:
|
||||
# TODO(sonivi): since multiattach is not supported for now,
|
||||
# delete only single host, if its not exported to volume.
|
||||
self._delete_3par_host(hostname)
|
||||
except Exception as ex:
|
||||
# Any exception down here is only logged. The vlun is deleted.
|
||||
@ -2928,8 +2937,9 @@ class HPE3PARCommon(object):
|
||||
elif iqn:
|
||||
hosts = self.client.queryHost(iqns=[iqn])
|
||||
|
||||
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
||||
hostname = hosts['members'][0]['name']
|
||||
if hosts is not None:
|
||||
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
||||
hostname = hosts['members'][0]['name']
|
||||
|
||||
try:
|
||||
self.delete_vlun(volume, hostname, wwn=wwn, iqn=iqn)
|
||||
@ -2950,12 +2960,19 @@ class HPE3PARCommon(object):
|
||||
"secondary target.")
|
||||
return
|
||||
else:
|
||||
# use the wwn to see if we can find the hostname
|
||||
hostname = self._get_3par_hostname_from_wwn_iqn(wwn, iqn)
|
||||
# no 3par host, re-throw
|
||||
if hostname is None:
|
||||
LOG.error("Exception: %s", e)
|
||||
if hosts is None:
|
||||
# In case of 'force detach', hosts is None
|
||||
LOG.exception("Exception: %s", e)
|
||||
raise
|
||||
else:
|
||||
# use the wwn to see if we can find the hostname
|
||||
hostname = self._get_3par_hostname_from_wwn_iqn(
|
||||
wwn,
|
||||
iqn)
|
||||
# no 3par host, re-throw
|
||||
if hostname is None:
|
||||
LOG.exception("Exception: %s", e)
|
||||
raise
|
||||
else:
|
||||
# not a 'host does not exist' HTTPNotFound exception, re-throw
|
||||
LOG.error("Exception: %s", e)
|
||||
|
@ -108,10 +108,11 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
4.0.1 - Added check to remove FC zones. bug #1730720
|
||||
4.0.2 - Create one vlun in single path configuration. bug #1727176
|
||||
4.0.3 - Create FC vlun as host sees. bug #1734505
|
||||
4.0.4 - Handle force detach case. bug #1686745
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "4.0.3"
|
||||
VERSION = "4.0.4"
|
||||
|
||||
# The name of the CI wiki page.
|
||||
CI_WIKI_NAME = "HPE_Storage_CI"
|
||||
@ -209,28 +210,35 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
"""Driver entry point to unattach a volume from an instance."""
|
||||
common = self._login()
|
||||
try:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
common.terminate_connection(volume, hostname,
|
||||
wwn=connector['wwpns'])
|
||||
is_force_detach = connector is None
|
||||
if is_force_detach:
|
||||
common.terminate_connection(volume, None, None)
|
||||
# TODO(sonivi): remove zones, if not required
|
||||
# for now, do not remove zones
|
||||
zone_remove = False
|
||||
else:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
common.terminate_connection(volume, hostname,
|
||||
wwn=connector['wwpns'])
|
||||
|
||||
zone_remove = True
|
||||
try:
|
||||
vluns = common.client.getHostVLUNs(hostname)
|
||||
except hpeexceptions.HTTPNotFound:
|
||||
# No more exports for this host.
|
||||
pass
|
||||
else:
|
||||
# Vlun exists, so check for wwpn entry.
|
||||
for wwpn in connector.get('wwpns'):
|
||||
for vlun in vluns:
|
||||
if (vlun.get('active') and
|
||||
vlun.get('remoteName') == wwpn.upper()):
|
||||
zone_remove = False
|
||||
break
|
||||
|
||||
info = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
|
||||
zone_remove = True
|
||||
try:
|
||||
vluns = common.client.getHostVLUNs(hostname)
|
||||
except hpeexceptions.HTTPNotFound:
|
||||
# No more exports for this host.
|
||||
pass
|
||||
else:
|
||||
# Vlun exists, so check for wwpn entry.
|
||||
for wwpn in connector.get('wwpns'):
|
||||
for vlun in vluns:
|
||||
if vlun.get('active') and \
|
||||
vlun.get('remoteName') == wwpn.upper():
|
||||
zone_remove = False
|
||||
break
|
||||
|
||||
if zone_remove:
|
||||
LOG.info("Need to remove FC Zone, building initiator "
|
||||
"target map")
|
||||
|
@ -122,10 +122,11 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
4.0.0 - Adds base class.
|
||||
4.0.1 - Update CHAP on host record when volume is migrated
|
||||
to new compute host. bug # 1737181
|
||||
4.0.2 - Handle force detach case. bug #1686745
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "4.0.1"
|
||||
VERSION = "4.0.2"
|
||||
|
||||
# The name of the CI wiki page.
|
||||
CI_WIKI_NAME = "HPE_Storage_CI"
|
||||
@ -364,11 +365,15 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
||||
"""Driver entry point to unattach a volume from an instance."""
|
||||
common = self._login()
|
||||
try:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
common.terminate_connection(
|
||||
volume,
|
||||
hostname,
|
||||
iqn=connector['initiator'])
|
||||
is_force_detach = connector is None
|
||||
if is_force_detach:
|
||||
common.terminate_connection(volume, None, None)
|
||||
else:
|
||||
hostname = common._safe_hostname(connector['host'])
|
||||
common.terminate_connection(
|
||||
volume,
|
||||
hostname,
|
||||
iqn=connector['initiator'])
|
||||
self._clear_chap_3par(common, volume)
|
||||
finally:
|
||||
self._logout(common)
|
||||
|
4
releasenotes/notes/bug-1686745-e8f1569455f998ba.yaml
Normal file
4
releasenotes/notes/bug-1686745-e8f1569455f998ba.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support to force detach a volume from all hosts on 3PAR.
|
Loading…
Reference in New Issue
Block a user