HPE 3PAR - Fix detach of multiattach volumes
Currently, volume detach call for the first instance deletes the luns and host entry from 3par and due to this the other instances still attached to volume loose the connectivity. This causes the volume to go in 'detaching' state. Change-Id: I31658cf986602d056978c29e12c0fc3cdbac7150 Closes-bug: #1834660
This commit is contained in:
parent
9dd5232ea5
commit
ee8a2d8e99
|
@ -19,6 +19,7 @@ import copy
|
|||
import mock
|
||||
|
||||
from oslo_utils import units
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
|
@ -155,13 +156,25 @@ class HPE3PARBaseDriver(test.TestCase):
|
|||
'iSCSIName': ('iqn.2000-05.com.3pardata:'
|
||||
'21810002ac00383d'),
|
||||
'linkState': 4}
|
||||
volume = {'name': VOLUME_NAME,
|
||||
'id': VOLUME_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': FAKE_CINDER_HOST,
|
||||
'volume_type': None,
|
||||
'volume_type_id': None}
|
||||
|
||||
volume_snapshot = {'name': VOLUME_NAME,
|
||||
'id': VOLUME_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': FAKE_CINDER_HOST,
|
||||
'volume_type': None,
|
||||
'volume_type_id': None}
|
||||
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
context.get_admin_context(),
|
||||
name=VOLUME_NAME,
|
||||
id=VOLUME_ID,
|
||||
display_name='Foo Volume',
|
||||
size=2,
|
||||
host=FAKE_CINDER_HOST,
|
||||
volume_type=None,
|
||||
volume_type_id=None,
|
||||
multiattach=False)
|
||||
|
||||
volume_src_cg = {'name': SRC_CG_VOLUME_NAME,
|
||||
'id': SRC_CG_VOLUME_ID,
|
||||
|
@ -205,14 +218,16 @@ class HPE3PARBaseDriver(test.TestCase):
|
|||
|
||||
list_rep_targets = [{'backend_id': 'target'}]
|
||||
|
||||
volume_encrypted = {'name': VOLUME_NAME,
|
||||
'id': VOLUME_ID,
|
||||
'display_name': 'Foo Volume',
|
||||
'size': 2,
|
||||
'host': FAKE_CINDER_HOST,
|
||||
'volume_type': None,
|
||||
'volume_type_id': None,
|
||||
'encryption_key_id': 'fake_key'}
|
||||
volume_encrypted = fake_volume.fake_volume_obj(
|
||||
context.get_admin_context(),
|
||||
name=VOLUME_NAME,
|
||||
id=VOLUME_ID,
|
||||
display_name='Foo Volume',
|
||||
size=2,
|
||||
host=FAKE_CINDER_HOST,
|
||||
volume_type=None,
|
||||
volume_type_id=None,
|
||||
encryption_key_id=uuidutils.generate_uuid())
|
||||
|
||||
volume_dedup_compression = {'name': VOLUME_NAME,
|
||||
'id': VOLUME_ID,
|
||||
|
@ -2046,7 +2061,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
self.standard_logout +
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout, any_order =True)
|
||||
self.standard_logout, any_order=True)
|
||||
|
||||
@mock.patch.object(volume_types, 'get_volume_type')
|
||||
def test_retype_rep_type_to_rep_type(self, _mock_volume_types):
|
||||
|
@ -2162,7 +2177,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
self.standard_logout +
|
||||
self.standard_login +
|
||||
expected +
|
||||
self.standard_logout, any_order =True)
|
||||
self.standard_logout, any_order=True)
|
||||
|
||||
@mock.patch.object(volume_types, 'get_volume_type')
|
||||
def test_retype_qos_spec(self, _mock_volume_types):
|
||||
|
@ -2273,7 +2288,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
self.standard_logout)
|
||||
|
||||
def _FakeRetrying(wait_func=None,
|
||||
original_retrying = hpecommon.utils.retrying.Retrying,
|
||||
original_retrying=hpecommon.utils.retrying.Retrying,
|
||||
*args, **kwargs):
|
||||
return original_retrying(wait_func=lambda *a, **k: 0,
|
||||
*args, **kwargs)
|
||||
|
@ -3235,7 +3250,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
self.driver._login()
|
||||
volume = self.volume.copy()
|
||||
volume = self.volume_snapshot.copy()
|
||||
model_update = self.driver.create_volume_from_snapshot(
|
||||
volume,
|
||||
self.snapshot)
|
||||
|
@ -3295,7 +3310,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
self.driver._login()
|
||||
volume = self.volume.copy()
|
||||
volume = self.volume_snapshot.copy()
|
||||
model_update = self.driver.create_volume_from_snapshot(
|
||||
volume,
|
||||
self.snapshot)
|
||||
|
@ -3336,7 +3351,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
mock_create_client.return_value = mock_client
|
||||
common = self.driver._login()
|
||||
|
||||
volume = self.volume.copy()
|
||||
volume = self.volume_snapshot.copy()
|
||||
volume['size'] = self.volume['size'] + 10
|
||||
model_update = self.driver.create_volume_from_snapshot(
|
||||
volume,
|
||||
|
@ -3455,7 +3470,7 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
|
|||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||
'_create_client') as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
volume = self.volume.copy()
|
||||
volume = self.volume_snapshot.copy()
|
||||
volume['size'] = self.volume['size'] + 10
|
||||
|
||||
self.assertRaises(exception.CinderException,
|
||||
|
@ -10122,6 +10137,29 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver):
|
|||
def test_migrate_volume_attached(self):
|
||||
self.migrate_volume_attached()
|
||||
|
||||
def test_terminate_connection_multiattach(self):
|
||||
ctx = context.get_admin_context()
|
||||
mock_client = self.setup_driver()
|
||||
att_1 = fake_volume.fake_volume_attachment_obj(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
att_2 = fake_volume.fake_volume_attachment_obj(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, multiattach=True, host=self.FAKE_CINDER_HOST)
|
||||
volume.volume_attachment.objects = [att_1, att_2]
|
||||
with mock.patch.object(hpecommon.HPE3PARCommon, '_create_client'
|
||||
) as mock_create_client:
|
||||
mock_create_client.return_value = mock_client
|
||||
self.driver.terminate_connection(volume, self.connector)
|
||||
|
||||
# When volume is having mulitple instances attached, there
|
||||
# should be no call to delete the VLUN(s) or the host. We
|
||||
# can assert these methods were not called to make sure the
|
||||
# proper code execution is followed.
|
||||
|
||||
self.assertEqual(0, mock_client.deleteVLUN.call_count)
|
||||
self.assertEqual(0, mock_client.deleteHost.call_count)
|
||||
|
||||
def test_terminate_connection(self):
|
||||
# setup_mock_client drive with default configuration
|
||||
# and return the mock HTTP 3PAR client
|
||||
|
|
|
@ -279,11 +279,13 @@ class HPE3PARCommon(object):
|
|||
4.0.10 - Added retry in delete_volume. bug #1783934
|
||||
4.0.11 - Added extra spec hpe3par:convert_to_base
|
||||
4.0.12 - Added multiattach support
|
||||
4.0.13 - Fixed detaching issue for volume with type multiattach
|
||||
enabled. bug #1834660
|
||||
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "4.0.12"
|
||||
VERSION = "4.0.13"
|
||||
|
||||
stats = {}
|
||||
|
||||
|
@ -3022,7 +3024,24 @@ class HPE3PARCommon(object):
|
|||
return host['name']
|
||||
|
||||
def terminate_connection(self, volume, hostname, wwn=None, iqn=None):
|
||||
"""Driver entry point to unattach a volume from an instance."""
|
||||
"""Driver entry point to detach a volume from an instance."""
|
||||
if volume.multiattach:
|
||||
attachment_list = volume.volume_attachment
|
||||
LOG.debug("Volume attachment list: %(atl)s",
|
||||
{'atl': attachment_list})
|
||||
try:
|
||||
attachment_list = attachment_list.objects
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if attachment_list is not None and len(attachment_list) > 1:
|
||||
LOG.info("Volume %(volume)s is attached to multiple "
|
||||
"instances on host %(host_name)s, "
|
||||
"skip terminate volume connection",
|
||||
{'volume': volume.name,
|
||||
'host_name': volume.host.split('@')[0]})
|
||||
return
|
||||
|
||||
# does 3par know this host by a different name?
|
||||
hosts = None
|
||||
if wwn:
|
||||
|
|
|
@ -37,6 +37,7 @@ except ImportError:
|
|||
from oslo_log import log as logging
|
||||
from oslo_utils.excutils import save_and_reraise_exception
|
||||
|
||||
from cinder import coordination
|
||||
from cinder import interface
|
||||
from cinder import utils
|
||||
from cinder.volume.drivers.hpe import hpe_3par_base as hpebasedriver
|
||||
|
@ -125,6 +126,7 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
|||
self.protocol = 'FC'
|
||||
|
||||
@utils.trace
|
||||
@coordination.synchronized('3par-{volume.id}')
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Assigns the volume to a server.
|
||||
|
||||
|
@ -208,8 +210,9 @@ class HPE3PARFCDriver(hpebasedriver.HPE3PARDriverBase):
|
|||
self._logout(common)
|
||||
|
||||
@utils.trace
|
||||
@coordination.synchronized('3par-{volume.id}')
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Driver entry point to unattach a volume from an instance."""
|
||||
"""Driver entry point to detach a volume from an instance."""
|
||||
array_id = self.get_volume_replication_driver_data(volume)
|
||||
common = self._login(array_id=array_id)
|
||||
try:
|
||||
|
|
|
@ -38,6 +38,7 @@ except ImportError:
|
|||
from oslo_log import log as logging
|
||||
from oslo_utils.excutils import save_and_reraise_exception
|
||||
|
||||
from cinder import coordination
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder import interface
|
||||
|
@ -206,6 +207,7 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
|||
self.iscsi_ips[common._client_conf['hpe3par_api_url']] = iscsi_ip_list
|
||||
|
||||
@utils.trace
|
||||
@coordination.synchronized('3par-{volume.id}')
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Assigns the volume to a server.
|
||||
|
||||
|
@ -364,8 +366,9 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
|
|||
self._logout(common)
|
||||
|
||||
@utils.trace
|
||||
@coordination.synchronized('3par-{volume.id}')
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Driver entry point to unattach a volume from an instance."""
|
||||
"""Driver entry point to detach a volume from an instance."""
|
||||
array_id = self.get_volume_replication_driver_data(volume)
|
||||
common = self._login(array_id=array_id)
|
||||
try:
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
features:
|
||||
- Fixed detach issue for multiattach capability in hpe3par driver.
|
|
@ -727,7 +727,7 @@ driver.dell_emc_vnx=missing
|
|||
driver.dell_emc_vxflexos=complete
|
||||
driver.dell_emc_xtremio=complete
|
||||
driver.fujitsu_eternus=missing
|
||||
driver.hpe_3par=missing
|
||||
driver.hpe_3par=complete
|
||||
driver.hpe_lefthand=complete
|
||||
driver.hpe_mmsa=missing
|
||||
driver.huawei_t_v1=missing
|
||||
|
|
Loading…
Reference in New Issue