3PAR driver fails to validate conf share server IPs
With 3PAR, share server(VFS) can have up to 4 IP addresses. During bootup, driver queries 3PAR to get list of all IP addresses and validates it against IP addresses provided in manila.conf. If there is a mismatch, driver throws exception. The bug was with 3PAR file client which always returns only one IP address. To make driver backward compatible with 3PAR client, mediator.py formats the value retured by client and passes it to driver.py. This patch now correctly accepts all the IP addresses as obtained from 3PAR and validates configured IPs against it. Also removing unused function. Updated and added new unit tests Added release notes Closes-Bug: #1621016 Change-Id: I1eeb18cc9905a71cd38c383bc0ab49e0a560ffc9
This commit is contained in:
parent
3f922aab6e
commit
cef6dddcee
@ -212,10 +212,12 @@ class HPE3ParShareDriver(driver.ShareDriver):
|
||||
when a share is deleted #1582931
|
||||
2.0.5 - Add update_access support
|
||||
2.0.6 - Multi pool support per backend
|
||||
2.0.7 - Fix get_vfs() to correctly validate conf IP addresses at
|
||||
boot up #1621016
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "2.0.6"
|
||||
VERSION = "2.0.7"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HPE3ParShareDriver, self).__init__((True, False),
|
||||
@ -265,7 +267,6 @@ class HPE3ParShareDriver(driver.ShareDriver):
|
||||
def _validate_pool_ips(addresses, conf_pool_ips):
|
||||
# Pool configured IP addresses should be subset of IP addresses
|
||||
# retured from vfs
|
||||
addresses = to_list(addresses)
|
||||
if not set(conf_pool_ips) <= set(addresses):
|
||||
msg = _("Incorrect configuration. "
|
||||
"Configuration pool IP address did not match with "
|
||||
@ -287,8 +288,6 @@ class HPE3ParShareDriver(driver.ShareDriver):
|
||||
vfs_info = mediator.get_vfs(pool_name)
|
||||
if self.driver_handles_share_servers:
|
||||
# Use discovered IP(s) from array
|
||||
vfs_info['vfsip']['address'] = to_list(
|
||||
vfs_info['vfsip']['address'])
|
||||
self.fpgs[pool_name] = {
|
||||
vfs_info['vfsname']: vfs_info['vfsip']['address']}
|
||||
elif conf_pool_ips == []:
|
||||
@ -301,8 +300,6 @@ class HPE3ParShareDriver(driver.ShareDriver):
|
||||
raise exception.HPE3ParInvalid(err=msg)
|
||||
else:
|
||||
# Use discovered pool ips
|
||||
vfs_info['vfsip']['address'] = to_list(
|
||||
vfs_info['vfsip']['address'])
|
||||
self.fpgs[pool_name] = {
|
||||
vfs_info['vfsname']: vfs_info['vfsip']['address']}
|
||||
else:
|
||||
|
@ -78,10 +78,12 @@ class HPE3ParMediator(object):
|
||||
2.0.6 - Read-write share from snapshot (using driver mount and copy)
|
||||
2.0.7 - Add update_access support
|
||||
2.0.8 - Multi pools support per backend
|
||||
2.0.9 - Fix get_vfs() to correctly validate conf IP addresses at
|
||||
boot up #1621016
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "2.0.8"
|
||||
VERSION = "2.0.9"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
@ -1042,9 +1044,6 @@ class HPE3ParMediator(object):
|
||||
'share_name': SUPER_SHARE})
|
||||
return path
|
||||
|
||||
def get_vfs_name(self, fpg):
|
||||
return self.get_vfs(fpg)['vfsname']
|
||||
|
||||
def get_vfs(self, fpg, vfs=None):
|
||||
"""Get the VFS or raise an exception."""
|
||||
|
||||
@ -1074,7 +1073,23 @@ class HPE3ParMediator(object):
|
||||
LOG.error(message)
|
||||
raise exception.ShareBackendException(msg=message)
|
||||
|
||||
return result['members'][0]
|
||||
value = result['members'][0]
|
||||
if isinstance(value['vfsip'], dict):
|
||||
# This is for 3parclient returning only one VFS entry
|
||||
LOG.debug("3parclient version up to 4.2.1 is in use. Client "
|
||||
"upgrade may be needed if using a VFS with multiple "
|
||||
"IP addresses.")
|
||||
value['vfsip']['address'] = [value['vfsip']['address']]
|
||||
else:
|
||||
# This is for 3parclient returning list of VFS entries
|
||||
# Format get_vfs ret value to combine all IP addresses
|
||||
discovered_vfs_ips = []
|
||||
for vfs_entry in value['vfsip']:
|
||||
if vfs_entry['address']:
|
||||
discovered_vfs_ips.append(vfs_entry['address'])
|
||||
value['vfsip'] = value['vfsip'][0]
|
||||
value['vfsip']['address'] = discovered_vfs_ips
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def _is_share_from_snapshot(fshare):
|
||||
|
@ -33,6 +33,7 @@ CIDR_PREFIX = '24'
|
||||
|
||||
# Constants to use with Mock and expect in results
|
||||
EXPECTED_IP_10203040 = '10.20.30.40'
|
||||
EXPECTED_IP_10203041 = '10.20.30.41'
|
||||
EXPECTED_IP_1234 = '1.2.3.4'
|
||||
EXPECTED_MY_IP = '9.8.7.6'
|
||||
EXPECTED_IP_127 = '127.0.0.1'
|
||||
@ -48,6 +49,7 @@ SHARE_ID = 'share-id'
|
||||
EXPECTED_SHARE_ID = 'osf-share-id'
|
||||
EXPECTED_SHARE_ID_RO = 'osf-ro-share-id'
|
||||
EXPECTED_SHARE_NAME = 'share-name'
|
||||
EXPECTED_NET_NAME = 'testnet'
|
||||
EXPECTED_FPG = 'pool'
|
||||
EXPECTED_HOST = 'hostname@backend#' + EXPECTED_FPG
|
||||
UNEXPECTED_FPG = 'not_a_pool'
|
||||
@ -64,8 +66,82 @@ EXPECTED_FPG_CONF = [{EXPECTED_FPG: [EXPECTED_IP_10203040]}]
|
||||
EXPECTED_FSTORE = EXPECTED_PROJECT_ID
|
||||
EXPECTED_VFS = 'test_vfs'
|
||||
EXPECTED_GET_VFS = {'vfsname': EXPECTED_VFS,
|
||||
'vfsip': {'address': EXPECTED_IP_10203040}}
|
||||
'vfsip': {'address': [EXPECTED_IP_10203040]}}
|
||||
EXPECTED_GET_VFS_MULTIPLES = {
|
||||
'vfsname': EXPECTED_VFS,
|
||||
'vfsip': {'address': [EXPECTED_IP_10203041, EXPECTED_IP_10203040]}}
|
||||
|
||||
EXPECTED_CLIENT_GET_VFS_MEMBERS_MULTI = {
|
||||
'fspname': EXPECTED_VFS,
|
||||
'vfsip': [
|
||||
{'networkName': EXPECTED_NET_NAME,
|
||||
'fspool': EXPECTED_VFS,
|
||||
'address': EXPECTED_IP_10203040,
|
||||
'prefixLen': EXPECTED_SUBNET,
|
||||
'vfs': EXPECTED_VFS,
|
||||
'vlanTag': EXPECTED_VLAN_TAG,
|
||||
},
|
||||
{'networkName': EXPECTED_NET_NAME,
|
||||
'fspool': EXPECTED_VFS,
|
||||
'address': EXPECTED_IP_10203041,
|
||||
'prefixLen': EXPECTED_SUBNET,
|
||||
'vfs': EXPECTED_VFS,
|
||||
'vlanTag': EXPECTED_VLAN_TAG,
|
||||
},
|
||||
],
|
||||
'vfsname': EXPECTED_VFS,
|
||||
}
|
||||
EXPECTED_MEDIATOR_GET_VFS_RET_VAL_MULTI = {
|
||||
'fspname': EXPECTED_VFS,
|
||||
'vfsip': {
|
||||
'networkName': EXPECTED_NET_NAME,
|
||||
'fspool': EXPECTED_VFS,
|
||||
'address': [
|
||||
EXPECTED_IP_10203040,
|
||||
EXPECTED_IP_10203041,
|
||||
],
|
||||
'prefixLen': EXPECTED_SUBNET,
|
||||
'vfs': EXPECTED_VFS,
|
||||
'vlanTag': EXPECTED_VLAN_TAG
|
||||
},
|
||||
'vfsname': EXPECTED_VFS,
|
||||
}
|
||||
|
||||
EXPECTED_CLIENT_GET_VFS_MEMBERS = {
|
||||
'fspname': EXPECTED_VFS,
|
||||
'vfsip': {
|
||||
'networkName': EXPECTED_NET_NAME,
|
||||
'fspool': EXPECTED_VFS,
|
||||
'address': EXPECTED_IP_10203040,
|
||||
'prefixLen': EXPECTED_SUBNET,
|
||||
'vfs': EXPECTED_VFS,
|
||||
'vlanTag': EXPECTED_VLAN_TAG,
|
||||
},
|
||||
'vfsname': EXPECTED_VFS,
|
||||
}
|
||||
EXPECTED_MEDIATOR_GET_VFS_RET_VAL = {
|
||||
'fspname': EXPECTED_VFS,
|
||||
'vfsip': {
|
||||
'networkName': EXPECTED_NET_NAME,
|
||||
'fspool': EXPECTED_VFS,
|
||||
'address': [EXPECTED_IP_10203040],
|
||||
'prefixLen': EXPECTED_SUBNET,
|
||||
'vfs': EXPECTED_VFS,
|
||||
'vlanTag': EXPECTED_VLAN_TAG,
|
||||
},
|
||||
'vfsname': EXPECTED_VFS,
|
||||
}
|
||||
EXPECTED_CLIENT_GET_VFS_RETURN_VALUE = {
|
||||
'total': 1,
|
||||
'members': [EXPECTED_CLIENT_GET_VFS_MEMBERS],
|
||||
}
|
||||
EXPECTED_CLIENT_GET_VFS_RETURN_VALUE_MULTI = {
|
||||
'total': 1,
|
||||
'members': [EXPECTED_CLIENT_GET_VFS_MEMBERS_MULTI],
|
||||
}
|
||||
EXPECTED_FPG_MAP = {EXPECTED_FPG: {EXPECTED_VFS: [EXPECTED_IP_10203040]}}
|
||||
EXPECTED_FPG_MAP_MULTI_VFS = {EXPECTED_FPG: {
|
||||
EXPECTED_VFS: [EXPECTED_IP_10203041, EXPECTED_IP_10203040]}}
|
||||
EXPECTED_SHARE_IP = '10.50.3.8'
|
||||
EXPECTED_HPE_DEBUG = True
|
||||
EXPECTED_COMMENT = "OpenStack Manila - foo-comment"
|
||||
|
@ -117,10 +117,11 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
self.driver = hpe3pardriver.HPE3ParShareDriver(
|
||||
configuration=self.conf)
|
||||
|
||||
def test_driver_setup_success(self):
|
||||
def test_driver_setup_success(self,
|
||||
get_vfs_ret_val=constants.EXPECTED_GET_VFS):
|
||||
"""Driver do_setup without any errors."""
|
||||
|
||||
self.mock_mediator.get_vfs.return_value = constants.EXPECTED_GET_VFS
|
||||
self.mock_mediator.get_vfs.return_value = get_vfs_ret_val
|
||||
|
||||
self.driver.do_setup(None)
|
||||
conf = self.conf
|
||||
@ -162,6 +163,15 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
self.test_driver_setup_success()
|
||||
self.assertEqual(constants.EXPECTED_FPG_MAP, self.driver.fpgs)
|
||||
|
||||
def test_driver_setup_no_dhss_multi_getvfs_success(self):
|
||||
"""Driver do_setup when dhss=False, getvfs returns multiple IPs."""
|
||||
|
||||
self.conf.driver_handles_share_servers = False
|
||||
self.test_driver_setup_success(
|
||||
get_vfs_ret_val=constants.EXPECTED_GET_VFS_MULTIPLES)
|
||||
self.assertEqual(constants.EXPECTED_FPG_MAP,
|
||||
self.driver.fpgs)
|
||||
|
||||
def test_driver_setup_success_no_dhss_no_conf_ss_ip(self):
|
||||
"""test driver's do_setup()
|
||||
|
||||
@ -177,7 +187,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
self.test_driver_setup_success()
|
||||
|
||||
self.assertEqual(constants.EXPECTED_FPG_MAP, self.driver.fpgs)
|
||||
self.conf.hpe3par_fpg = original_fpg
|
||||
constants.EXPECTED_FPG_CONF = original_fpg
|
||||
|
||||
def test_driver_setup_failure_no_dhss_no_conf_ss_ip(self):
|
||||
"""Configured IP address is required for dhss=False."""
|
||||
@ -193,7 +203,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
|
||||
self.assertRaises(exception.HPE3ParInvalid,
|
||||
self.driver.do_setup, None)
|
||||
self.conf.hpe3par_fpg = fpg_without_ss_ip
|
||||
constants.EXPECTED_FPG_CONF = fpg_without_ss_ip
|
||||
|
||||
def test_driver_setup_mediator_error(self):
|
||||
"""Driver do_setup when the mediator setup fails."""
|
||||
|
@ -121,12 +121,12 @@ class HPE3ParMediatorTestCase(test.TestCase):
|
||||
conn_timeout=constants.TIMEOUT)])
|
||||
|
||||
def test_mediator_vfs_exception(self):
|
||||
"""Backend exception during get_vfs_name."""
|
||||
"""Backend exception during get_vfs."""
|
||||
|
||||
self.init_mediator()
|
||||
self.mock_client.getvfs.side_effect = Exception('non-manila-except')
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self.mediator.get_vfs_name,
|
||||
self.mediator.get_vfs,
|
||||
fpg=constants.EXPECTED_FPG)
|
||||
expected_calls = [
|
||||
mock.call.getvfs(fpg=constants.EXPECTED_FPG, vfs=None),
|
||||
@ -138,13 +138,30 @@ class HPE3ParMediatorTestCase(test.TestCase):
|
||||
self.init_mediator()
|
||||
self.mock_client.getvfs.return_value = {'total': 0}
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self.mediator.get_vfs_name,
|
||||
self.mediator.get_vfs,
|
||||
fpg=constants.EXPECTED_FPG)
|
||||
expected_calls = [
|
||||
mock.call.getvfs(fpg=constants.EXPECTED_FPG, vfs=None),
|
||||
]
|
||||
self.mock_client.assert_has_calls(expected_calls)
|
||||
|
||||
@ddt.data((constants.EXPECTED_CLIENT_GET_VFS_RETURN_VALUE,
|
||||
constants.EXPECTED_MEDIATOR_GET_VFS_RET_VAL),
|
||||
(constants.EXPECTED_CLIENT_GET_VFS_RETURN_VALUE_MULTI,
|
||||
constants.EXPECTED_MEDIATOR_GET_VFS_RET_VAL_MULTI))
|
||||
@ddt.unpack
|
||||
def test_mediator_get_vfs(self, get_vfs_val, exp_vfs_val):
|
||||
"""VFS not found."""
|
||||
self.init_mediator()
|
||||
self.mock_client.getvfs.return_value = get_vfs_val
|
||||
|
||||
ret_val = self.mediator.get_vfs(constants.EXPECTED_FPG)
|
||||
self.assertEqual(exp_vfs_val, ret_val)
|
||||
expected_calls = [
|
||||
mock.call.getvfs(fpg=constants.EXPECTED_FPG, vfs=None),
|
||||
]
|
||||
self.mock_client.assert_has_calls(expected_calls)
|
||||
|
||||
def init_mediator(self):
|
||||
"""Basic mediator setup for re-use with tests that need one."""
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
issues:
|
||||
- 3parclient up to version 4.2.1 always returns only 1 VFS IP address.
|
||||
This may cause 3PAR driver boot up failure while validating VFS IP
|
||||
addresses against IP addresses configured in manila.conf.
|
||||
fixes:
|
||||
- Fixed 3PAR driver boot up failure while validating share server IP address
|
||||
provided in manila.conf against IP address set on array.
|
Loading…
Reference in New Issue
Block a user