diff --git a/manila/share/drivers/hpe/hpe_3par_driver.py b/manila/share/drivers/hpe/hpe_3par_driver.py index b00829e9..78f139d0 100644 --- a/manila/share/drivers/hpe/hpe_3par_driver.py +++ b/manila/share/drivers/hpe/hpe_3par_driver.py @@ -211,10 +211,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), @@ -264,7 +266,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 " @@ -286,8 +287,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 == []: @@ -300,8 +299,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: diff --git a/manila/share/drivers/hpe/hpe_3par_mediator.py b/manila/share/drivers/hpe/hpe_3par_mediator.py index 1d6ef33d..4d19ce5a 100644 --- a/manila/share/drivers/hpe/hpe_3par_mediator.py +++ b/manila/share/drivers/hpe/hpe_3par_mediator.py @@ -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): diff --git a/manila/tests/share/drivers/hpe/test_hpe_3par_constants.py b/manila/tests/share/drivers/hpe/test_hpe_3par_constants.py index 638b8bbe..e8663776 100644 --- a/manila/tests/share/drivers/hpe/test_hpe_3par_constants.py +++ b/manila/tests/share/drivers/hpe/test_hpe_3par_constants.py @@ -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" diff --git a/manila/tests/share/drivers/hpe/test_hpe_3par_driver.py b/manila/tests/share/drivers/hpe/test_hpe_3par_driver.py index 690a20eb..78bb10c2 100644 --- a/manila/tests/share/drivers/hpe/test_hpe_3par_driver.py +++ b/manila/tests/share/drivers/hpe/test_hpe_3par_driver.py @@ -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.""" diff --git a/manila/tests/share/drivers/hpe/test_hpe_3par_mediator.py b/manila/tests/share/drivers/hpe/test_hpe_3par_mediator.py index 62c6b000..ee9eb1b1 100644 --- a/manila/tests/share/drivers/hpe/test_hpe_3par_mediator.py +++ b/manila/tests/share/drivers/hpe/test_hpe_3par_mediator.py @@ -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.""" diff --git a/releasenotes/notes/3par-fix-get_vfs-driver-bootup-db6b085eb6094f5f.yaml b/releasenotes/notes/3par-fix-get_vfs-driver-bootup-db6b085eb6094f5f.yaml new file mode 100644 index 00000000..6e4831a9 --- /dev/null +++ b/releasenotes/notes/3par-fix-get_vfs-driver-bootup-db6b085eb6094f5f.yaml @@ -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.