Merge "3PAR: Add force detach support" into stable/queens
This commit is contained in:
@@ -7015,6 +7015,45 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver):
|
|||||||
expected +
|
expected +
|
||||||
self.standard_logout)
|
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')
|
@mock.patch('cinder.zonemanager.utils.create_lookup_service')
|
||||||
def test_terminate_connection_with_lookup(self, mock_lookup):
|
def test_terminate_connection_with_lookup(self, mock_lookup):
|
||||||
# setup_mock_client drive with default configuration
|
# 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
|
differs from volume present in the source group in terms of
|
||||||
extra-specs. bug #1744025
|
extra-specs. bug #1744025
|
||||||
4.0.6 - Monitor task of promoting a virtual copy. bug #1749642
|
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 = {}
|
stats = {}
|
||||||
|
|
||||||
@@ -1659,7 +1660,11 @@ class HPE3PARCommon(object):
|
|||||||
|
|
||||||
def delete_vlun(self, volume, hostname, wwn=None, iqn=None):
|
def delete_vlun(self, volume, hostname, wwn=None, iqn=None):
|
||||||
volume_name = self._get_3par_vol_name(volume['id'])
|
volume_name = self._get_3par_vol_name(volume['id'])
|
||||||
|
if hostname:
|
||||||
vluns = self.client.getHostVLUNs(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
|
# When deleteing VLUNs, you simply need to remove the template VLUN
|
||||||
# and any active VLUNs will be automatically removed. The template
|
# 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
|
# VLUN Type of MATCHED_SET 4 requires the port to be provided
|
||||||
for vlun in volume_vluns:
|
for vlun in volume_vluns:
|
||||||
|
if hostname is None:
|
||||||
|
hostname = vlun.get('hostname')
|
||||||
if 'portPos' in vlun:
|
if 'portPos' in vlun:
|
||||||
self.client.deleteVLUN(volume_name, vlun['lun'],
|
self.client.deleteVLUN(volume_name, vlun['lun'],
|
||||||
hostname=hostname,
|
hostname=hostname,
|
||||||
@@ -1721,6 +1728,8 @@ class HPE3PARCommon(object):
|
|||||||
# host, so it is worth the unlikely risk.
|
# host, so it is worth the unlikely risk.
|
||||||
|
|
||||||
try:
|
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)
|
self._delete_3par_host(hostname)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
# Any exception down here is only logged. The vlun is deleted.
|
# Any exception down here is only logged. The vlun is deleted.
|
||||||
@@ -2928,6 +2937,7 @@ class HPE3PARCommon(object):
|
|||||||
elif iqn:
|
elif iqn:
|
||||||
hosts = self.client.queryHost(iqns=[iqn])
|
hosts = self.client.queryHost(iqns=[iqn])
|
||||||
|
|
||||||
|
if hosts is not None:
|
||||||
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
||||||
hostname = hosts['members'][0]['name']
|
hostname = hosts['members'][0]['name']
|
||||||
|
|
||||||
@@ -2949,12 +2959,19 @@ class HPE3PARCommon(object):
|
|||||||
"The volume can now be attached to the "
|
"The volume can now be attached to the "
|
||||||
"secondary target.")
|
"secondary target.")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
if hosts is None:
|
||||||
|
# In case of 'force detach', hosts is None
|
||||||
|
LOG.exception("Exception: %s", e)
|
||||||
|
raise
|
||||||
else:
|
else:
|
||||||
# use the wwn to see if we can find the hostname
|
# use the wwn to see if we can find the hostname
|
||||||
hostname = self._get_3par_hostname_from_wwn_iqn(wwn, iqn)
|
hostname = self._get_3par_hostname_from_wwn_iqn(
|
||||||
|
wwn,
|
||||||
|
iqn)
|
||||||
# no 3par host, re-throw
|
# no 3par host, re-throw
|
||||||
if hostname is None:
|
if hostname is None:
|
||||||
LOG.error("Exception: %s", e)
|
LOG.exception("Exception: %s", e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
# not a 'host does not exist' HTTPNotFound exception, re-throw
|
# not a 'host does not exist' HTTPNotFound exception, re-throw
|
||||||
|
|||||||
@@ -108,10 +108,11 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
|||||||
4.0.1 - Added check to remove FC zones. bug #1730720
|
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.2 - Create one vlun in single path configuration. bug #1727176
|
||||||
4.0.3 - Create FC vlun as host sees. bug #1734505
|
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.
|
# The name of the CI wiki page.
|
||||||
CI_WIKI_NAME = "HPE_Storage_CI"
|
CI_WIKI_NAME = "HPE_Storage_CI"
|
||||||
@@ -209,13 +210,17 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
|||||||
"""Driver entry point to unattach a volume from an instance."""
|
"""Driver entry point to unattach a volume from an instance."""
|
||||||
common = self._login()
|
common = self._login()
|
||||||
try:
|
try:
|
||||||
|
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'])
|
hostname = common._safe_hostname(connector['host'])
|
||||||
common.terminate_connection(volume, hostname,
|
common.terminate_connection(volume, hostname,
|
||||||
wwn=connector['wwpns'])
|
wwn=connector['wwpns'])
|
||||||
|
|
||||||
info = {'driver_volume_type': 'fibre_channel',
|
|
||||||
'data': {}}
|
|
||||||
|
|
||||||
zone_remove = True
|
zone_remove = True
|
||||||
try:
|
try:
|
||||||
vluns = common.client.getHostVLUNs(hostname)
|
vluns = common.client.getHostVLUNs(hostname)
|
||||||
@@ -226,11 +231,14 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
|||||||
# Vlun exists, so check for wwpn entry.
|
# Vlun exists, so check for wwpn entry.
|
||||||
for wwpn in connector.get('wwpns'):
|
for wwpn in connector.get('wwpns'):
|
||||||
for vlun in vluns:
|
for vlun in vluns:
|
||||||
if vlun.get('active') and \
|
if (vlun.get('active') and
|
||||||
vlun.get('remoteName') == wwpn.upper():
|
vlun.get('remoteName') == wwpn.upper()):
|
||||||
zone_remove = False
|
zone_remove = False
|
||||||
break
|
break
|
||||||
|
|
||||||
|
info = {'driver_volume_type': 'fibre_channel',
|
||||||
|
'data': {}}
|
||||||
|
|
||||||
if zone_remove:
|
if zone_remove:
|
||||||
LOG.info("Need to remove FC Zone, building initiator "
|
LOG.info("Need to remove FC Zone, building initiator "
|
||||||
"target map")
|
"target map")
|
||||||
|
|||||||
@@ -122,10 +122,11 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
|||||||
4.0.0 - Adds base class.
|
4.0.0 - Adds base class.
|
||||||
4.0.1 - Update CHAP on host record when volume is migrated
|
4.0.1 - Update CHAP on host record when volume is migrated
|
||||||
to new compute host. bug # 1737181
|
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.
|
# The name of the CI wiki page.
|
||||||
CI_WIKI_NAME = "HPE_Storage_CI"
|
CI_WIKI_NAME = "HPE_Storage_CI"
|
||||||
@@ -364,6 +365,10 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
|||||||
"""Driver entry point to unattach a volume from an instance."""
|
"""Driver entry point to unattach a volume from an instance."""
|
||||||
common = self._login()
|
common = self._login()
|
||||||
try:
|
try:
|
||||||
|
is_force_detach = connector is None
|
||||||
|
if is_force_detach:
|
||||||
|
common.terminate_connection(volume, None, None)
|
||||||
|
else:
|
||||||
hostname = common._safe_hostname(connector['host'])
|
hostname = common._safe_hostname(connector['host'])
|
||||||
common.terminate_connection(
|
common.terminate_connection(
|
||||||
volume,
|
volume,
|
||||||
|
|||||||
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.
|
||||||
Reference in New Issue
Block a user