Merge "Add version discovery support to BaseAuthPlugin"

This commit is contained in:
Jenkins 2017-10-06 17:11:08 +00:00 committed by Gerrit Code Review
commit 89333b6fa0
4 changed files with 179 additions and 2 deletions

View File

@ -43,7 +43,6 @@ class BaseIdentityPlugin(plugin.BaseAuthPlugin):
self.auth_ref = None
self.reauthenticate = reauthenticate
self._discovery_cache = {}
self._lock = threading.Lock()
@abc.abstractmethod

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystoneauth1 import discover
# NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be
# requested from get_endpoint. If a plugin receives this as the value of
# 'interface' it should return the initial URL that was passed to the plugin.
@ -27,6 +29,9 @@ class BaseAuthPlugin(object):
"""
def __init__(self):
self._discovery_cache = {}
def get_token(self, session, **kwargs):
"""Obtain a token.
@ -94,6 +99,58 @@ class BaseAuthPlugin(object):
return {IDENTITY_AUTH_HEADER_NAME: token}
def get_endpoint_data(self, session,
endpoint_override=None,
discover_versions=True,
**kwargs):
"""Return a valid endpoint data for a the service.
:param session: A session object that can be used for communication.
:type session: keystoneauth1.session.Session
:param str endpoint_override: URL to use for version discovery.
:param bool discover_versions: Whether to get version metadata from
the version discovery document even
if it major api version info can be
inferred from the url.
(optional, defaults to True)
:param kwargs: Ignored.
:raises keystoneauth1.exceptions.http.HttpError: An error from an
invalid HTTP response.
:return: Valid EndpointData or None if not available.
:rtype: `keystoneauth1.discover.EndpointData` or None
"""
if not endpoint_override:
return None
endpoint_data = discover.EndpointData(catalog_url=endpoint_override)
if endpoint_data.api_version and not discover_versions:
return endpoint_data
return endpoint_data.get_versioned_data(
session, cache=self._discovery_cache,
discover_versions=discover_versions)
def get_api_major_version(self, session, endpoint_override=None, **kwargs):
"""Get the major API version from the endpoint.
:param session: A session object that can be used for communication.
:type session: keystoneauth1.session.Session
:param str endpoint_override: URL to use for version discovery.
:param kwargs: Ignored.
:raises keystoneauth1.exceptions.http.HttpError: An error from an
invalid HTTP response.
:return: Valid EndpointData or None if not available.
:rtype: `keystoneauth1.discover.EndpointData` or None
"""
endpoint_data = self.get_endpoint_data(
session, endpoint_override=endpoint_override,
discover_versions=False, **kwargs)
return endpoint_data.api_version
def get_endpoint(self, session, **kwargs):
"""Return an endpoint for the client.
@ -114,7 +171,11 @@ class BaseAuthPlugin(object):
service or None if not available.
:rtype: string
"""
return None
endpoint_data = self.get_endpoint_data(
session, discover_versions=False, **kwargs)
if not endpoint_data:
return None
return endpoint_data.url
def get_connection_params(self, session, **kwargs):
"""Return any additional connection parameters required for the plugin.

View File

@ -16,11 +16,14 @@ import re
from testtools import matchers
from keystoneauth1 import adapter
from keystoneauth1 import discover
from keystoneauth1 import exceptions
from keystoneauth1 import fixture
from keystoneauth1 import noauth
from keystoneauth1 import session
from keystoneauth1.tests.unit import utils
from keystoneauth1 import token_endpoint
BASE_HOST = 'http://keystone.example.com'
@ -587,6 +590,92 @@ class VersionDataTests(utils.TestCase):
# Badly-formatted next_min_version
test_exc({'next_min_version': 'bogus', 'not_before': '2019-07-01'})
def test_endpoint_data_noauth_discover(self):
mock = self.requests_mock.get(
V3_URL, status_code=200, json=V3_VERSION_ENTRY)
plugin = noauth.NoAuth()
data = plugin.get_endpoint_data(self.session, endpoint_override=V3_URL)
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(
plugin.get_api_major_version(
self.session, endpoint_override=V3_URL),
(3, 0))
self.assertEqual(
plugin.get_endpoint(self.session, endpoint_override=V3_URL),
V3_URL)
self.assertTrue(mock.called_once)
def test_endpoint_data_noauth_no_discover(self):
plugin = noauth.NoAuth()
data = plugin.get_endpoint_data(
self.session, endpoint_override=V3_URL, discover_versions=False)
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(
plugin.get_api_major_version(
self.session, endpoint_override=V3_URL),
(3, 0))
self.assertEqual(
plugin.get_endpoint(self.session, endpoint_override=V3_URL),
V3_URL)
def test_endpoint_data_noauth_adapter(self):
mock = self.requests_mock.get(
V3_URL, status_code=200, json=V3_VERSION_ENTRY)
client = adapter.Adapter(
session.Session(noauth.NoAuth()),
endpoint_override=V3_URL)
data = client.get_endpoint_data()
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(client.get_api_major_version(), (3, 0))
self.assertEqual(client.get_endpoint(), V3_URL)
self.assertTrue(mock.called_once)
def test_endpoint_data_token_endpoint_discover(self):
mock = self.requests_mock.get(
V3_URL, status_code=200, json=V3_VERSION_ENTRY)
plugin = token_endpoint.Token(endpoint=V3_URL, token='bogus')
data = plugin.get_endpoint_data(self.session)
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(plugin.get_api_major_version(self.session), (3, 0))
self.assertEqual(plugin.get_endpoint(self.session), V3_URL)
self.assertTrue(mock.called_once)
def test_endpoint_data_token_endpoint_no_discover(self):
plugin = token_endpoint.Token(endpoint=V3_URL, token='bogus')
data = plugin.get_endpoint_data(self.session, discover_versions=False)
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(plugin.get_api_major_version(self.session), (3, 0))
self.assertEqual(plugin.get_endpoint(self.session), V3_URL)
def test_endpoint_data_token_endpoint_adapter(self):
mock = self.requests_mock.get(
V3_URL, status_code=200, json=V3_VERSION_ENTRY)
plugin = token_endpoint.Token(endpoint=V3_URL, token='bogus')
client = adapter.Adapter(session.Session(plugin))
data = client.get_endpoint_data()
self.assertEqual(data.api_version, (3, 0))
self.assertEqual(data.url, V3_URL)
self.assertEqual(client.get_api_major_version(), (3, 0))
self.assertEqual(client.get_endpoint(), V3_URL)
self.assertTrue(mock.called_once)
def test_data_for_url(self):
mock = self.requests_mock.get(V3_URL,
status_code=200,

View File

@ -21,6 +21,7 @@ class Token(plugin.BaseAuthPlugin):
"""
def __init__(self, endpoint, token):
super(Token, self).__init__()
# NOTE(jamielennox): endpoint is reserved for when plugins
# can be used to provide that information
self.endpoint = endpoint
@ -29,6 +30,33 @@ class Token(plugin.BaseAuthPlugin):
def get_token(self, session):
return self.token
def get_endpoint_data(self, session,
endpoint_override=None,
discover_versions=True, **kwargs):
"""Return a valid endpoint data for a the service.
:param session: A session object that can be used for communication.
:type session: keystoneauth1.session.Session
:param str endpoint_override: URL to use for version discovery other
than the endpoint stored in the plugin.
(optional, defaults to None)
:param bool discover_versions: Whether to get version metadata from
the version discovery document even
if it major api version info can be
inferred from the url.
(optional, defaults to True)
:param kwargs: Ignored.
:raises keystoneauth1.exceptions.http.HttpError: An error from an
invalid HTTP response.
:return: Valid EndpointData or None if not available.
:rtype: `keystoneauth1.discover.EndpointData` or None
"""
return super(Token, self).get_endpoint_data(
session, endpoint_override=endpoint_override or self.endpoint,
discover_versions=discover_versions, **kwargs)
def get_endpoint(self, session, **kwargs):
"""Return the supplied endpoint.