Allows specifying a name for a particular endpoint.
Previously, if there were multiple endpoints with the same type and region, or without a region, the first endpoint would be returned. Now, by specifying the name, a specific one can be used. Co-Authored-By: Franklin Naval <franklin.naval@gmail.com> Change-Id: Ife6d435e2aa84153d8717463930d45e5f21272f7 Closes-Bug: #1486834
This commit is contained in:
parent
66a162131e
commit
54c7bd4982
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Tempest library auth interface now supports
|
||||||
|
filtering with catalog name. Note that filtering by
|
||||||
|
name is only successful if a known service type is
|
||||||
|
provided.
|
|
@ -1,4 +1,5 @@
|
||||||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright 2016 Rackspace Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
@ -368,18 +369,24 @@ class KeystoneV2AuthProvider(KeystoneAuthProvider):
|
||||||
def base_url(self, filters, auth_data=None):
|
def base_url(self, filters, auth_data=None):
|
||||||
"""Base URL from catalog
|
"""Base URL from catalog
|
||||||
|
|
||||||
Filters can be:
|
:param filters: Used to filter results
|
||||||
- service: compute, image, etc
|
Filters can be:
|
||||||
- region: the service region
|
- service: service type name such as compute, image, etc.
|
||||||
- endpoint_type: adminURL, publicURL, internalURL
|
- region: service region name
|
||||||
- api_version: replace catalog version with this
|
- name: service name, only if service exists
|
||||||
- skip_path: take just the base URL
|
- endpoint_type: type of endpoint such as
|
||||||
|
adminURL, publicURL, internalURL
|
||||||
|
- api_version: the version of api used to replace catalog version
|
||||||
|
- skip_path: skips the suffix path of the url and uses base URL
|
||||||
|
:rtype string
|
||||||
|
:return url with filters applied
|
||||||
"""
|
"""
|
||||||
if auth_data is None:
|
if auth_data is None:
|
||||||
auth_data = self.get_auth()
|
auth_data = self.get_auth()
|
||||||
token, _auth_data = auth_data
|
token, _auth_data = auth_data
|
||||||
service = filters.get('service')
|
service = filters.get('service')
|
||||||
region = filters.get('region')
|
region = filters.get('region')
|
||||||
|
name = filters.get('name')
|
||||||
endpoint_type = filters.get('endpoint_type', 'publicURL')
|
endpoint_type = filters.get('endpoint_type', 'publicURL')
|
||||||
|
|
||||||
if service is None:
|
if service is None:
|
||||||
|
@ -388,17 +395,19 @@ class KeystoneV2AuthProvider(KeystoneAuthProvider):
|
||||||
_base_url = None
|
_base_url = None
|
||||||
for ep in _auth_data['serviceCatalog']:
|
for ep in _auth_data['serviceCatalog']:
|
||||||
if ep["type"] == service:
|
if ep["type"] == service:
|
||||||
|
if name is not None and ep["name"] != name:
|
||||||
|
continue
|
||||||
for _ep in ep['endpoints']:
|
for _ep in ep['endpoints']:
|
||||||
if region is not None and _ep['region'] == region:
|
if region is not None and _ep['region'] == region:
|
||||||
_base_url = _ep.get(endpoint_type)
|
_base_url = _ep.get(endpoint_type)
|
||||||
if not _base_url:
|
if not _base_url:
|
||||||
# No region matching, use the first
|
# No region or name matching, use the first
|
||||||
_base_url = ep['endpoints'][0].get(endpoint_type)
|
_base_url = ep['endpoints'][0].get(endpoint_type)
|
||||||
break
|
break
|
||||||
if _base_url is None:
|
if _base_url is None:
|
||||||
raise exceptions.EndpointNotFound(
|
raise exceptions.EndpointNotFound(
|
||||||
"service: %s, region: %s, endpoint_type: %s" %
|
"service: %s, region: %s, endpoint_type: %s, name: %s" %
|
||||||
(service, region, endpoint_type))
|
(service, region, endpoint_type, name))
|
||||||
return apply_url_filters(_base_url, filters)
|
return apply_url_filters(_base_url, filters)
|
||||||
|
|
||||||
def is_expired(self, auth_data):
|
def is_expired(self, auth_data):
|
||||||
|
@ -489,18 +498,24 @@ class KeystoneV3AuthProvider(KeystoneAuthProvider):
|
||||||
the auth_data. In such case, as long as the requested service is
|
the auth_data. In such case, as long as the requested service is
|
||||||
'identity', we can use the original auth URL to build the base_url.
|
'identity', we can use the original auth URL to build the base_url.
|
||||||
|
|
||||||
Filters can be:
|
:param filters: Used to filter results
|
||||||
- service: compute, image, etc
|
Filters can be:
|
||||||
- region: the service region
|
- service: service type name such as compute, image, etc.
|
||||||
- endpoint_type: adminURL, publicURL, internalURL
|
- region: service region name
|
||||||
- api_version: replace catalog version with this
|
- name: service name, only if service exists
|
||||||
- skip_path: take just the base URL
|
- endpoint_type: type of endpoint such as
|
||||||
|
adminURL, publicURL, internalURL
|
||||||
|
- api_version: the version of api used to replace catalog version
|
||||||
|
- skip_path: skips the suffix path of the url and uses base URL
|
||||||
|
:rtype string
|
||||||
|
:return url with filters applied
|
||||||
"""
|
"""
|
||||||
if auth_data is None:
|
if auth_data is None:
|
||||||
auth_data = self.get_auth()
|
auth_data = self.get_auth()
|
||||||
token, _auth_data = auth_data
|
token, _auth_data = auth_data
|
||||||
service = filters.get('service')
|
service = filters.get('service')
|
||||||
region = filters.get('region')
|
region = filters.get('region')
|
||||||
|
name = filters.get('name')
|
||||||
endpoint_type = filters.get('endpoint_type', 'public')
|
endpoint_type = filters.get('endpoint_type', 'public')
|
||||||
|
|
||||||
if service is None:
|
if service is None:
|
||||||
|
@ -513,7 +528,15 @@ class KeystoneV3AuthProvider(KeystoneAuthProvider):
|
||||||
# Select entries with matching service type
|
# Select entries with matching service type
|
||||||
service_catalog = [ep for ep in catalog if ep['type'] == service]
|
service_catalog = [ep for ep in catalog if ep['type'] == service]
|
||||||
if len(service_catalog) > 0:
|
if len(service_catalog) > 0:
|
||||||
service_catalog = service_catalog[0]['endpoints']
|
if name is not None:
|
||||||
|
service_catalog = (
|
||||||
|
[ep for ep in service_catalog if ep['name'] == name])
|
||||||
|
if len(service_catalog) > 0:
|
||||||
|
service_catalog = service_catalog[0]['endpoints']
|
||||||
|
else:
|
||||||
|
raise exceptions.EndpointNotFound(name)
|
||||||
|
else:
|
||||||
|
service_catalog = service_catalog[0]['endpoints']
|
||||||
else:
|
else:
|
||||||
if len(catalog) == 0 and service == 'identity':
|
if len(catalog) == 0 and service == 'identity':
|
||||||
# NOTE(andreaf) If there's no catalog at all and the service
|
# NOTE(andreaf) If there's no catalog at all and the service
|
||||||
|
@ -533,7 +556,7 @@ class KeystoneV3AuthProvider(KeystoneAuthProvider):
|
||||||
filtered_catalog = [ep for ep in filtered_catalog if
|
filtered_catalog = [ep for ep in filtered_catalog if
|
||||||
ep['region'] == region]
|
ep['region'] == region]
|
||||||
if len(filtered_catalog) == 0:
|
if len(filtered_catalog) == 0:
|
||||||
# No matching region, take the first endpoint
|
# No matching region (or name), take the first endpoint
|
||||||
filtered_catalog = [service_catalog[0]]
|
filtered_catalog = [service_catalog[0]]
|
||||||
# There should be only one match. If not take the first.
|
# There should be only one match. If not take the first.
|
||||||
_base_url = filtered_catalog[0].get('url', None)
|
_base_url = filtered_catalog[0].get('url', None)
|
||||||
|
|
|
@ -54,6 +54,8 @@ class RestClient(object):
|
||||||
:param auth_provider: an auth provider object used to wrap requests in auth
|
:param auth_provider: an auth provider object used to wrap requests in auth
|
||||||
:param str service: The service name to use for the catalog lookup
|
:param str service: The service name to use for the catalog lookup
|
||||||
:param str region: The region to use for the catalog lookup
|
:param str region: The region to use for the catalog lookup
|
||||||
|
:param str name: The endpoint name to use for the catalog lookup; this
|
||||||
|
returns only if the service exists
|
||||||
:param str endpoint_type: The endpoint type to use for the catalog lookup
|
:param str endpoint_type: The endpoint type to use for the catalog lookup
|
||||||
:param int build_interval: Time in seconds between to status checks in
|
:param int build_interval: Time in seconds between to status checks in
|
||||||
wait loops
|
wait loops
|
||||||
|
@ -76,10 +78,11 @@ class RestClient(object):
|
||||||
endpoint_type='publicURL',
|
endpoint_type='publicURL',
|
||||||
build_interval=1, build_timeout=60,
|
build_interval=1, build_timeout=60,
|
||||||
disable_ssl_certificate_validation=False, ca_certs=None,
|
disable_ssl_certificate_validation=False, ca_certs=None,
|
||||||
trace_requests=''):
|
trace_requests='', name=None):
|
||||||
self.auth_provider = auth_provider
|
self.auth_provider = auth_provider
|
||||||
self.service = service
|
self.service = service
|
||||||
self.region = region
|
self.region = region
|
||||||
|
self.name = name
|
||||||
self.endpoint_type = endpoint_type
|
self.endpoint_type = endpoint_type
|
||||||
self.build_interval = build_interval
|
self.build_interval = build_interval
|
||||||
self.build_timeout = build_timeout
|
self.build_timeout = build_timeout
|
||||||
|
@ -191,7 +194,8 @@ class RestClient(object):
|
||||||
_filters = dict(
|
_filters = dict(
|
||||||
service=self.service,
|
service=self.service,
|
||||||
endpoint_type=self.endpoint_type,
|
endpoint_type=self.endpoint_type,
|
||||||
region=self.region
|
region=self.region,
|
||||||
|
name=self.name
|
||||||
)
|
)
|
||||||
if self.api_version is not None:
|
if self.api_version is not None:
|
||||||
_filters['api_version'] = self.api_version
|
_filters['api_version'] = self.api_version
|
||||||
|
|
|
@ -100,7 +100,8 @@ COMPUTE_ENDPOINTS_V3 = {
|
||||||
|
|
||||||
],
|
],
|
||||||
"type": "compute",
|
"type": "compute",
|
||||||
"id": "fake_compute_endpoint"
|
"id": "fake_compute_endpoint",
|
||||||
|
"name": "nova"
|
||||||
}
|
}
|
||||||
|
|
||||||
CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ]
|
CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ]
|
||||||
|
|
|
@ -360,6 +360,58 @@ class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
|
||||||
self.assertRaises(exceptions.EndpointNotFound,
|
self.assertRaises(exceptions.EndpointNotFound,
|
||||||
self._test_base_url_helper, None, self.filters)
|
self._test_base_url_helper, None, self.filters)
|
||||||
|
|
||||||
|
def test_base_url_with_known_name(self):
|
||||||
|
"""If name and service is known, return the endpoint."""
|
||||||
|
self.filters = {
|
||||||
|
'service': 'compute',
|
||||||
|
'endpoint_type': 'publicURL',
|
||||||
|
'region': 'FakeRegion',
|
||||||
|
'name': 'nova'
|
||||||
|
}
|
||||||
|
expected = self._get_result_url_from_endpoint(
|
||||||
|
self._endpoints[0]['endpoints'][1])
|
||||||
|
self._test_base_url_helper(expected, self.filters)
|
||||||
|
|
||||||
|
def test_base_url_with_known_name_and_unknown_servce(self):
|
||||||
|
"""Test with Known Name and Unknown service
|
||||||
|
|
||||||
|
If the name is known but the service is unknown, raise an exception.
|
||||||
|
"""
|
||||||
|
self.filters = {
|
||||||
|
'service': 'AintNoBodyKnowThatService',
|
||||||
|
'endpoint_type': 'publicURL',
|
||||||
|
'region': 'FakeRegion',
|
||||||
|
'name': 'AintNoBodyKnowThatName'
|
||||||
|
}
|
||||||
|
self.assertRaises(exceptions.EndpointNotFound,
|
||||||
|
self._test_base_url_helper, None, self.filters)
|
||||||
|
|
||||||
|
def test_base_url_with_unknown_name_and_known_service(self):
|
||||||
|
"""Test with Unknown Name and Known Service
|
||||||
|
|
||||||
|
If the name is unknown, raise an exception. Note that filtering by
|
||||||
|
name is only successful service exists.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.filters = {
|
||||||
|
'service': 'compute',
|
||||||
|
'endpoint_type': 'publicURL',
|
||||||
|
'region': 'FakeRegion',
|
||||||
|
'name': 'AintNoBodyKnowThatName'
|
||||||
|
}
|
||||||
|
self.assertRaises(exceptions.EndpointNotFound,
|
||||||
|
self._test_base_url_helper, None, self.filters)
|
||||||
|
|
||||||
|
def test_base_url_without_name(self):
|
||||||
|
self.filters = {
|
||||||
|
'service': 'compute',
|
||||||
|
'endpoint_type': 'publicURL',
|
||||||
|
'region': 'FakeRegion',
|
||||||
|
}
|
||||||
|
expected = self._get_result_url_from_endpoint(
|
||||||
|
self._endpoints[0]['endpoints'][1])
|
||||||
|
self._test_base_url_helper(expected, self.filters)
|
||||||
|
|
||||||
def test_base_url_with_api_version_filter(self):
|
def test_base_url_with_api_version_filter(self):
|
||||||
self.filters = {
|
self.filters = {
|
||||||
'service': 'compute',
|
'service': 'compute',
|
||||||
|
|
|
@ -633,6 +633,7 @@ class TestProperties(BaseRestClientTestClass):
|
||||||
expected = {'api_version': 'v1',
|
expected = {'api_version': 'v1',
|
||||||
'endpoint_type': 'publicURL',
|
'endpoint_type': 'publicURL',
|
||||||
'region': None,
|
'region': None,
|
||||||
|
'name': None,
|
||||||
'service': None,
|
'service': None,
|
||||||
'skip_path': True}
|
'skip_path': True}
|
||||||
self.rest_client.skip_path()
|
self.rest_client.skip_path()
|
||||||
|
@ -643,6 +644,7 @@ class TestProperties(BaseRestClientTestClass):
|
||||||
expected = {'api_version': 'v1',
|
expected = {'api_version': 'v1',
|
||||||
'endpoint_type': 'publicURL',
|
'endpoint_type': 'publicURL',
|
||||||
'region': None,
|
'region': None,
|
||||||
|
'name': None,
|
||||||
'service': None}
|
'service': None}
|
||||||
self.assertEqual(expected, self.rest_client.filters)
|
self.assertEqual(expected, self.rest_client.filters)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue