Merge "HPE3PAR: handle conflict in iscsi host create"
This commit is contained in:
commit
03f9de7fb7
@ -5521,8 +5521,8 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
|
|||||||
|
|
||||||
self.assertEqual('fakehost.foo', host['name'])
|
self.assertEqual('fakehost.foo', host['name'])
|
||||||
|
|
||||||
def test_concurrent_create_host(self):
|
def test_create_host_concurrent(self):
|
||||||
# tests concurrent requests to create host
|
# tests concurrent requests of create host
|
||||||
# setup_mock_client driver with default configuration
|
# setup_mock_client driver with default configuration
|
||||||
# and return the mock HTTP 3PAR client
|
# and return the mock HTTP 3PAR client
|
||||||
mock_client = self.setup_driver()
|
mock_client = self.setup_driver()
|
||||||
@ -5538,23 +5538,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
|
|||||||
'desc': 'host WWN/iSCSI name already used by another host'})]
|
'desc': 'host WWN/iSCSI name already used by another host'})]
|
||||||
mock_client.getHost.side_effect = [
|
mock_client.getHost.side_effect = [
|
||||||
hpeexceptions.HTTPNotFound('fake'),
|
hpeexceptions.HTTPNotFound('fake'),
|
||||||
{'name': self.FAKE_HOST,
|
{'name': self.FAKE_HOST}]
|
||||||
'FCPaths': [{'driverVersion': None,
|
|
||||||
'firmwareVersion': None,
|
|
||||||
'hostSpeed': 0,
|
|
||||||
'model': None,
|
|
||||||
'portPos': {'cardPort': 1, 'node': 1,
|
|
||||||
'slot': 2},
|
|
||||||
'vendor': None,
|
|
||||||
'wwn': self.wwn[0]},
|
|
||||||
{'driverVersion': None,
|
|
||||||
'firmwareVersion': None,
|
|
||||||
'hostSpeed': 0,
|
|
||||||
'model': None,
|
|
||||||
'portPos': {'cardPort': 1, 'node': 0,
|
|
||||||
'slot': 2},
|
|
||||||
'vendor': None,
|
|
||||||
'wwn': self.wwn[1]}]}]
|
|
||||||
|
|
||||||
with mock.patch.object(hpecommon.HPE3PARCommon,
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
'_create_client') as mock_create_client:
|
'_create_client') as mock_create_client:
|
||||||
@ -6687,6 +6671,45 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver, test.TestCase):
|
|||||||
self.assertEqual('test-user', auth_username)
|
self.assertEqual('test-user', auth_username)
|
||||||
self.assertEqual('test-pass', auth_password)
|
self.assertEqual('test-pass', auth_password)
|
||||||
|
|
||||||
|
def test_create_host_concurrent(self):
|
||||||
|
# tests concurrent requests of create host
|
||||||
|
# setup_mock_client driver with default configuration
|
||||||
|
# and return the mock HTTP 3PAR client
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
mock_client.getVolume.return_value = {'userCPG': HPE3PAR_CPG}
|
||||||
|
mock_client.getCPG.return_value = {}
|
||||||
|
mock_client.queryHost.side_effect = [
|
||||||
|
None, {'members': [{'name': self.FAKE_HOST}]}]
|
||||||
|
mock_client.createHost.side_effect = [
|
||||||
|
hpeexceptions.HTTPConflict(
|
||||||
|
{'code': EXISTENT_PATH,
|
||||||
|
'desc': 'host WWN/iSCSI name already used by another host'})]
|
||||||
|
mock_client.getHost.side_effect = [
|
||||||
|
hpeexceptions.HTTPNotFound('fake'),
|
||||||
|
{'name': self.FAKE_HOST}]
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
common = self.driver._login()
|
||||||
|
host, user, pwd = self.driver._create_host(
|
||||||
|
common, self.volume, self.connector)
|
||||||
|
expected = [
|
||||||
|
mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
|
||||||
|
mock.call.getCPG(HPE3PAR_CPG),
|
||||||
|
mock.call.getHost(self.FAKE_HOST),
|
||||||
|
mock.call.queryHost(iqns=['iqn.1993-08.org.debian:01:222']),
|
||||||
|
mock.call.createHost(
|
||||||
|
self.FAKE_HOST,
|
||||||
|
optional={'domain': None, 'persona': 2},
|
||||||
|
iscsiNames=['iqn.1993-08.org.debian:01:222']),
|
||||||
|
mock.call.queryHost(iqns=['iqn.1993-08.org.debian:01:222']),
|
||||||
|
mock.call.getHost(self.FAKE_HOST)]
|
||||||
|
|
||||||
|
mock_client.assert_has_calls(expected)
|
||||||
|
|
||||||
|
self.assertEqual(self.FAKE_HOST, host['name'])
|
||||||
|
|
||||||
def test_create_modify_host(self):
|
def test_create_modify_host(self):
|
||||||
# setup_mock_client drive with default configuration
|
# setup_mock_client drive with default configuration
|
||||||
# and return the mock HTTP 3PAR client
|
# and return the mock HTTP 3PAR client
|
||||||
|
@ -36,6 +36,7 @@ except ImportError:
|
|||||||
hpeexceptions = None
|
hpeexceptions = None
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils.excutils import save_and_reraise_exception
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LW
|
from cinder.i18n import _, _LE, _LW
|
||||||
@ -47,6 +48,9 @@ from cinder.volume.drivers.san import san
|
|||||||
from cinder.volume import utils as volume_utils
|
from cinder.volume import utils as volume_utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# EXISTENT_PATH error code returned from hpe3parclient
|
||||||
|
EXISTENT_PATH = 73
|
||||||
DEFAULT_ISCSI_PORT = 3260
|
DEFAULT_ISCSI_PORT = 3260
|
||||||
CHAP_USER_KEY = "HPQ-cinder-CHAP-name"
|
CHAP_USER_KEY = "HPQ-cinder-CHAP-name"
|
||||||
CHAP_PASS_KEY = "HPQ-cinder-CHAP-secret"
|
CHAP_PASS_KEY = "HPQ-cinder-CHAP-secret"
|
||||||
@ -119,10 +123,12 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
3.0.11 - _create_3par_iscsi_host() now accepts iscsi_iqn as list only.
|
3.0.11 - _create_3par_iscsi_host() now accepts iscsi_iqn as list only.
|
||||||
Bug #1590180
|
Bug #1590180
|
||||||
3.0.12 - Added entry point tracing
|
3.0.12 - Added entry point tracing
|
||||||
|
3.0.13 - Handling HTTP conflict 409, host WWN/iSCSI name already used
|
||||||
|
by another host, while creating 3PAR iSCSI Host. bug #1642945
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "3.0.12"
|
VERSION = "3.0.13"
|
||||||
|
|
||||||
# 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"
|
||||||
@ -528,9 +534,29 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
return host_found
|
return host_found
|
||||||
else:
|
else:
|
||||||
persona_id = int(persona_id)
|
persona_id = int(persona_id)
|
||||||
common.client.createHost(hostname, iscsiNames=iscsi_iqn,
|
try:
|
||||||
optional={'domain': domain,
|
common.client.createHost(hostname, iscsiNames=iscsi_iqn,
|
||||||
'persona': persona_id})
|
optional={'domain': domain,
|
||||||
|
'persona': persona_id})
|
||||||
|
except hpeexceptions.HTTPConflict as path_conflict:
|
||||||
|
msg = _LE("Create iSCSI host caught HTTP conflict code: %s")
|
||||||
|
with save_and_reraise_exception(reraise=False) as ctxt:
|
||||||
|
if path_conflict.get_code() is EXISTENT_PATH:
|
||||||
|
# Handle exception : EXISTENT_PATH - host WWN/iSCSI
|
||||||
|
# name already used by another host
|
||||||
|
hosts = common.client.queryHost(iqns=iscsi_iqn)
|
||||||
|
if hosts and hosts['members'] and (
|
||||||
|
'name' in hosts['members'][0]):
|
||||||
|
hostname = hosts['members'][0]['name']
|
||||||
|
else:
|
||||||
|
# re-raise last caught exception
|
||||||
|
ctxt.reraise = True
|
||||||
|
LOG.exception(msg, path_conflict.get_code())
|
||||||
|
else:
|
||||||
|
# re-raise last caught exception
|
||||||
|
# for other HTTP conflict
|
||||||
|
ctxt.reraise = True
|
||||||
|
LOG.exception(msg, path_conflict.get_code())
|
||||||
return hostname
|
return hostname
|
||||||
|
|
||||||
def _modify_3par_iscsi_host(self, common, hostname, iscsi_iqn):
|
def _modify_3par_iscsi_host(self, common, hostname, iscsi_iqn):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user