Merge "Fixed _create_3par_iscsi_host(), added unit test for 3PAR"
This commit is contained in:
commit
50a886ec3a
@ -5796,6 +5796,160 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver, test.TestCase):
|
|||||||
expected_properties['data']['encrypted'] = True
|
expected_properties['data']['encrypted'] = True
|
||||||
self.assertDictMatch(self.properties, result)
|
self.assertDictMatch(self.properties, result)
|
||||||
|
|
||||||
|
def test_terminate_connection_for_clear_chap_creds_not_found(self):
|
||||||
|
# setup_mock_client drive with default configuration
|
||||||
|
# and return the mock HTTP 3PAR client
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
mock_client.getHostVLUNs.return_value = [
|
||||||
|
{'active': False,
|
||||||
|
'volumeName': self.VOLUME_3PAR_NAME,
|
||||||
|
'lun': None, 'type': 0}]
|
||||||
|
|
||||||
|
mock_client.queryHost.return_value = {
|
||||||
|
'members': [{
|
||||||
|
'name': self.FAKE_HOST
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
mock_client.getStorageSystemInfo.return_value = {
|
||||||
|
'id': self.CLIENT_ID
|
||||||
|
}
|
||||||
|
# Test for clear CHAP creds fails with HTTPNotFound
|
||||||
|
mock_client.removeVolumeMetaData.side_effect = [
|
||||||
|
hpeexceptions.HTTPNotFound,
|
||||||
|
hpeexceptions.HTTPNotFound]
|
||||||
|
|
||||||
|
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,
|
||||||
|
self.connector,
|
||||||
|
force=True)
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.queryHost(iqns=[self.connector['initiator']]),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteVLUN(
|
||||||
|
self.VOLUME_3PAR_NAME,
|
||||||
|
None,
|
||||||
|
hostname=self.FAKE_HOST),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteHost(self.FAKE_HOST),
|
||||||
|
mock.call.removeVolumeMetaData(
|
||||||
|
self.VOLUME_3PAR_NAME, CHAP_USER_KEY),
|
||||||
|
mock.call.removeVolumeMetaData(
|
||||||
|
self.VOLUME_3PAR_NAME, CHAP_PASS_KEY)]
|
||||||
|
|
||||||
|
mock_client.assert_has_calls(
|
||||||
|
self.get_id_login +
|
||||||
|
self.standard_logout +
|
||||||
|
self.standard_login +
|
||||||
|
expected +
|
||||||
|
self.standard_logout)
|
||||||
|
|
||||||
|
def test_terminate_connection_for_clear_chap_user_key_bad_request(self):
|
||||||
|
# setup_mock_client drive with default configuration
|
||||||
|
# and return the mock HTTP 3PAR client
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
mock_client.getHostVLUNs.return_value = [
|
||||||
|
{'active': False,
|
||||||
|
'volumeName': self.VOLUME_3PAR_NAME,
|
||||||
|
'lun': None, 'type': 0}]
|
||||||
|
|
||||||
|
mock_client.queryHost.return_value = {
|
||||||
|
'members': [{
|
||||||
|
'name': self.FAKE_HOST
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
mock_client.getStorageSystemInfo.return_value = {
|
||||||
|
'id': self.CLIENT_ID
|
||||||
|
}
|
||||||
|
# Test for CHAP USER KEY fails with HTTPBadRequest
|
||||||
|
mock_client.removeVolumeMetaData.side_effect = [
|
||||||
|
hpeexceptions.HTTPBadRequest]
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
|
||||||
|
self.assertRaises(hpeexceptions.HTTPBadRequest,
|
||||||
|
self.driver.terminate_connection,
|
||||||
|
self.volume,
|
||||||
|
self.connector,
|
||||||
|
force=True)
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.queryHost(iqns=[self.connector['initiator']]),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteVLUN(
|
||||||
|
self.VOLUME_3PAR_NAME,
|
||||||
|
None,
|
||||||
|
hostname=self.FAKE_HOST),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteHost(self.FAKE_HOST),
|
||||||
|
mock.call.removeVolumeMetaData(
|
||||||
|
self.VOLUME_3PAR_NAME, CHAP_USER_KEY)]
|
||||||
|
|
||||||
|
mock_client.assert_has_calls(
|
||||||
|
self.get_id_login +
|
||||||
|
self.standard_logout +
|
||||||
|
self.standard_login +
|
||||||
|
expected +
|
||||||
|
self.standard_logout)
|
||||||
|
|
||||||
|
def test_terminate_connection_for_clear_chap_pass_key_bad_request(self):
|
||||||
|
# setup_mock_client drive with default configuration
|
||||||
|
# and return the mock HTTP 3PAR client
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
mock_client.getHostVLUNs.return_value = [
|
||||||
|
{'active': False,
|
||||||
|
'volumeName': self.VOLUME_3PAR_NAME,
|
||||||
|
'lun': None, 'type': 0}]
|
||||||
|
|
||||||
|
mock_client.queryHost.return_value = {
|
||||||
|
'members': [{
|
||||||
|
'name': self.FAKE_HOST
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
mock_client.getStorageSystemInfo.return_value = {
|
||||||
|
'id': self.CLIENT_ID,
|
||||||
|
}
|
||||||
|
# Test for CHAP PASS KEY fails with HTTPBadRequest
|
||||||
|
mock_client.removeVolumeMetaData.side_effect = [
|
||||||
|
None,
|
||||||
|
hpeexceptions.HTTPBadRequest]
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
|
||||||
|
self.assertRaises(hpeexceptions.HTTPBadRequest,
|
||||||
|
self.driver.terminate_connection,
|
||||||
|
self.volume,
|
||||||
|
self.connector,
|
||||||
|
force=True)
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.queryHost(iqns=[self.connector['initiator']]),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteVLUN(
|
||||||
|
self.VOLUME_3PAR_NAME,
|
||||||
|
None,
|
||||||
|
hostname=self.FAKE_HOST),
|
||||||
|
mock.call.getHostVLUNs(self.FAKE_HOST),
|
||||||
|
mock.call.deleteHost(self.FAKE_HOST),
|
||||||
|
mock.call.removeVolumeMetaData(
|
||||||
|
self.VOLUME_3PAR_NAME, CHAP_USER_KEY),
|
||||||
|
mock.call.removeVolumeMetaData(
|
||||||
|
self.VOLUME_3PAR_NAME, CHAP_PASS_KEY)]
|
||||||
|
|
||||||
|
mock_client.assert_has_calls(
|
||||||
|
self.get_id_login +
|
||||||
|
self.standard_logout +
|
||||||
|
self.standard_login +
|
||||||
|
expected +
|
||||||
|
self.standard_logout)
|
||||||
|
|
||||||
def test_get_volume_stats(self):
|
def test_get_volume_stats(self):
|
||||||
# setup_mock_client drive with the configuration
|
# setup_mock_client drive with the configuration
|
||||||
# and return the mock HTTP 3PAR client
|
# and return the mock HTTP 3PAR client
|
||||||
@ -6201,6 +6355,58 @@ 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_chap_enabled_and_host_without_chap_cred(self):
|
||||||
|
# setup_mock_client driver
|
||||||
|
# and return the mock HTTP 3PAR client
|
||||||
|
config = self.setup_configuration()
|
||||||
|
config.hpe3par_iscsi_chap_enabled = True
|
||||||
|
mock_client = self.setup_driver(config=config)
|
||||||
|
mock_client.getVolume.return_value = {'userCPG': HPE3PAR_CPG}
|
||||||
|
mock_client.getCPG.return_value = {}
|
||||||
|
|
||||||
|
expected_mod_request = {
|
||||||
|
'chapOperation': mock_client.HOST_EDIT_ADD,
|
||||||
|
'chapOperationMode': mock_client.CHAP_INITIATOR,
|
||||||
|
'chapName': 'test-user',
|
||||||
|
'chapSecret': 'test-pass'
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_side_effect(*args):
|
||||||
|
data = {'value': None}
|
||||||
|
if args[1] == CHAP_USER_KEY:
|
||||||
|
data['value'] = 'test-user'
|
||||||
|
elif args[1] == CHAP_PASS_KEY:
|
||||||
|
data['value'] = 'test-pass'
|
||||||
|
return data
|
||||||
|
|
||||||
|
mock_client.getVolumeMetaData.side_effect = get_side_effect
|
||||||
|
mock_client.getHost.return_value = {
|
||||||
|
'name': self.FAKE_HOST,
|
||||||
|
'initiatorChapEnabled': False,
|
||||||
|
'iSCSIPaths': [{
|
||||||
|
"name": "iqn.1993-08.org.debian:01:222"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
common = self.driver._login()
|
||||||
|
host, auth_username, auth_password = self.driver._create_host(
|
||||||
|
common, self.volume, self.connector)
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
mock.call.getVolume('osv-0DM4qZEVSKON-DXN-NwVpw'),
|
||||||
|
mock.call.getCPG(HPE3PAR_CPG),
|
||||||
|
mock.call.getVolumeMetaData(
|
||||||
|
'osv-0DM4qZEVSKON-DXN-NwVpw', CHAP_USER_KEY),
|
||||||
|
mock.call.getVolumeMetaData(
|
||||||
|
'osv-0DM4qZEVSKON-DXN-NwVpw', CHAP_PASS_KEY),
|
||||||
|
mock.call.getHost(self.FAKE_HOST),
|
||||||
|
mock.call.modifyHost(self.FAKE_HOST, expected_mod_request)]
|
||||||
|
|
||||||
|
mock_client.assert_has_calls(expected)
|
||||||
|
|
||||||
def test_create_invalid_host(self):
|
def test_create_invalid_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,7 +36,6 @@ except ImportError:
|
|||||||
hpeexceptions = None
|
hpeexceptions = None
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LW
|
from cinder.i18n import _, _LE, _LW
|
||||||
@ -114,10 +113,12 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
3.0.8 - Update replication to version 2.1
|
3.0.8 - Update replication to version 2.1
|
||||||
3.0.9 - Use same LUN ID for each VLUN path #1551994
|
3.0.9 - Use same LUN ID for each VLUN path #1551994
|
||||||
3.0.10 - Remove metadata that tracks the instance ID. bug #1572665
|
3.0.10 - Remove metadata that tracks the instance ID. bug #1572665
|
||||||
|
3.0.11 - _create_3par_iscsi_host() now accepts iscsi_iqn as list only.
|
||||||
|
Bug #1590180
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "3.0.10"
|
VERSION = "3.0.11"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(HPE3PARISCSIDriver, self).__init__(*args, **kwargs)
|
super(HPE3PARISCSIDriver, self).__init__(*args, **kwargs)
|
||||||
@ -501,7 +502,8 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
"""
|
"""
|
||||||
# first search for an existing host
|
# first search for an existing host
|
||||||
host_found = None
|
host_found = None
|
||||||
hosts = common.client.queryHost(iqns=[iscsi_iqn])
|
|
||||||
|
hosts = common.client.queryHost(iqns=iscsi_iqn)
|
||||||
|
|
||||||
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
if hosts and hosts['members'] and 'name' in hosts['members'][0]:
|
||||||
host_found = hosts['members'][0]['name']
|
host_found = hosts['members'][0]['name']
|
||||||
@ -509,12 +511,8 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
if host_found is not None:
|
if host_found is not None:
|
||||||
return host_found
|
return host_found
|
||||||
else:
|
else:
|
||||||
if isinstance(iscsi_iqn, six.string_types):
|
|
||||||
iqn = [iscsi_iqn]
|
|
||||||
else:
|
|
||||||
iqn = iscsi_iqn
|
|
||||||
persona_id = int(persona_id)
|
persona_id = int(persona_id)
|
||||||
common.client.createHost(hostname, iscsiNames=iqn,
|
common.client.createHost(hostname, iscsiNames=iscsi_iqn,
|
||||||
optional={'domain': domain,
|
optional={'domain': domain,
|
||||||
'persona': persona_id})
|
'persona': persona_id})
|
||||||
return hostname
|
return hostname
|
||||||
@ -562,7 +560,7 @@ class HPE3PARISCSIDriver(driver.TransferVD,
|
|||||||
# host doesn't exist, we have to create it
|
# host doesn't exist, we have to create it
|
||||||
hostname = self._create_3par_iscsi_host(common,
|
hostname = self._create_3par_iscsi_host(common,
|
||||||
hostname,
|
hostname,
|
||||||
connector['initiator'],
|
[connector['initiator']],
|
||||||
domain,
|
domain,
|
||||||
persona_id)
|
persona_id)
|
||||||
self._set_3par_chaps(common, hostname, volume, username, password)
|
self._set_3par_chaps(common, hostname, volume, username, password)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user