Merge "Provide a conversion function for creating session"
This commit is contained in:
@@ -14,13 +14,14 @@
|
|||||||
|
|
||||||
from keystoneclient import discover
|
from keystoneclient import discover
|
||||||
from keystoneclient import httpclient
|
from keystoneclient import httpclient
|
||||||
|
from keystoneclient import session as client_session
|
||||||
|
|
||||||
|
|
||||||
# Using client.HTTPClient is deprecated. Use httpclient.HTTPClient instead.
|
# Using client.HTTPClient is deprecated. Use httpclient.HTTPClient instead.
|
||||||
HTTPClient = httpclient.HTTPClient
|
HTTPClient = httpclient.HTTPClient
|
||||||
|
|
||||||
|
|
||||||
def Client(version=None, unstable=False, **kwargs):
|
def Client(version=None, unstable=False, session=None, **kwargs):
|
||||||
"""Factory function to create a new identity service client.
|
"""Factory function to create a new identity service client.
|
||||||
|
|
||||||
:param tuple version: The required version of the identity API. If
|
:param tuple version: The required version of the identity API. If
|
||||||
@@ -29,6 +30,9 @@ def Client(version=None, unstable=False, **kwargs):
|
|||||||
at least the specified minor version. For example to
|
at least the specified minor version. For example to
|
||||||
specify the 3.1 API use (3, 1).
|
specify the 3.1 API use (3, 1).
|
||||||
:param bool unstable: Accept endpoints not marked as 'stable'. (optional)
|
:param bool unstable: Accept endpoints not marked as 'stable'. (optional)
|
||||||
|
:param Session session: A session object to be used for communication. If
|
||||||
|
one is not provided it will be constructed from the
|
||||||
|
provided kwargs. (optional)
|
||||||
:param kwargs: Additional arguments are passed through to the client
|
:param kwargs: Additional arguments are passed through to the client
|
||||||
that is being created.
|
that is being created.
|
||||||
:returns: New keystone client object
|
:returns: New keystone client object
|
||||||
@@ -37,6 +41,8 @@ def Client(version=None, unstable=False, **kwargs):
|
|||||||
:raises: DiscoveryFailure if the server's response is invalid
|
:raises: DiscoveryFailure if the server's response is invalid
|
||||||
:raises: VersionNotAvailable if a suitable client cannot be found.
|
:raises: VersionNotAvailable if a suitable client cannot be found.
|
||||||
"""
|
"""
|
||||||
|
if not session:
|
||||||
|
session = client_session.Session.construct(kwargs)
|
||||||
|
|
||||||
return discover.Discover(**kwargs).create_client(version=version,
|
d = discover.Discover(session=session, **kwargs)
|
||||||
unstable=unstable)
|
return d.create_client(version=version, unstable=unstable)
|
||||||
|
@@ -17,7 +17,7 @@ import logging
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from keystoneclient import exceptions
|
from keystoneclient import exceptions
|
||||||
from keystoneclient import httpclient
|
from keystoneclient import session as client_session
|
||||||
from keystoneclient.v2_0 import client as v2_client
|
from keystoneclient.v2_0 import client as v2_client
|
||||||
from keystoneclient.v3 import client as v3_client
|
from keystoneclient.v3 import client as v3_client
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class _KeystoneVersion(object):
|
|||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.version == other.version and self.status == other.status
|
return self.version == other.version and self.status == other.status
|
||||||
|
|
||||||
def __call__(self, **kwargs):
|
def create_client(self, **kwargs):
|
||||||
if kwargs:
|
if kwargs:
|
||||||
client_kwargs = self.client_kwargs.copy()
|
client_kwargs = self.client_kwargs.copy()
|
||||||
client_kwargs.update(kwargs)
|
client_kwargs.update(kwargs)
|
||||||
@@ -89,6 +89,9 @@ class _KeystoneVersion(object):
|
|||||||
client_kwargs = self.client_kwargs
|
client_kwargs = self.client_kwargs
|
||||||
return self.client_class(**client_kwargs)
|
return self.client_class(**client_kwargs)
|
||||||
|
|
||||||
|
def __call__(self, **kwargs):
|
||||||
|
return self.create_client(**kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _str_ver(self):
|
def _str_ver(self):
|
||||||
ver = ".".join([str(v) for v in self.version])
|
ver = ".".join([str(v) for v in self.version])
|
||||||
@@ -132,12 +135,19 @@ def _normalize_version_number(version):
|
|||||||
raise TypeError("Invalid version specified: %s" % version)
|
raise TypeError("Invalid version specified: %s" % version)
|
||||||
|
|
||||||
|
|
||||||
def available_versions(url, **kwargs):
|
def available_versions(url, session=None, **kwargs):
|
||||||
headers = {'Accept': 'application/json'}
|
headers = {'Accept': 'application/json'}
|
||||||
|
|
||||||
client = httpclient.HTTPClient(**kwargs)
|
if not session:
|
||||||
resp, body_resp = client.request(url, 'GET', headers=headers)
|
session = client_session.Session.construct(kwargs)
|
||||||
|
|
||||||
|
resp = session.get(url, headers=headers)
|
||||||
|
|
||||||
|
try:
|
||||||
|
body_resp = resp.json()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
# In the event of querying a root URL we will get back a list of
|
# In the event of querying a root URL we will get back a list of
|
||||||
# available versions.
|
# available versions.
|
||||||
try:
|
try:
|
||||||
@@ -149,11 +159,11 @@ def available_versions(url, **kwargs):
|
|||||||
# just the one available version.
|
# just the one available version.
|
||||||
try:
|
try:
|
||||||
return [body_resp['version']]
|
return [body_resp['version']]
|
||||||
except (KeyError, TypeError):
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
raise exceptions.DiscoveryFailure("Invalid Response - Bad version"
|
raise exceptions.DiscoveryFailure("Invalid Response - Bad version"
|
||||||
" data returned: %s" % body_resp)
|
" data returned: %s" % resp.text)
|
||||||
|
|
||||||
|
|
||||||
class Discover(object):
|
class Discover(object):
|
||||||
@@ -164,7 +174,7 @@ class Discover(object):
|
|||||||
operates upon the data that was retrieved.
|
operates upon the data that was retrieved.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, session=None, **kwargs):
|
||||||
"""Construct a new discovery object.
|
"""Construct a new discovery object.
|
||||||
|
|
||||||
The connection parameters associated with this method are the same
|
The connection parameters associated with this method are the same
|
||||||
@@ -178,6 +188,9 @@ class Discover(object):
|
|||||||
|
|
||||||
The initialization process also queries the server.
|
The initialization process also queries the server.
|
||||||
|
|
||||||
|
:param Session session: A session object that will be used for
|
||||||
|
communication. Clients will also be constructed
|
||||||
|
with this session.
|
||||||
:param string auth_url: Identity service endpoint for authorization.
|
:param string auth_url: Identity service endpoint for authorization.
|
||||||
(optional)
|
(optional)
|
||||||
:param string endpoint: A user-supplied endpoint URL for the identity
|
:param string endpoint: A user-supplied endpoint URL for the identity
|
||||||
@@ -185,26 +198,42 @@ class Discover(object):
|
|||||||
:param string original_ip: The original IP of the requesting user
|
:param string original_ip: The original IP of the requesting user
|
||||||
which will be sent to identity service in a
|
which will be sent to identity service in a
|
||||||
'Forwarded' header. (optional)
|
'Forwarded' header. (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
:param boolean debug: Enables debug logging of all request and
|
:param boolean debug: Enables debug logging of all request and
|
||||||
responses to the identity service.
|
responses to the identity service.
|
||||||
default False (optional)
|
default False (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
:param string cacert: Path to the Privacy Enhanced Mail (PEM) file
|
:param string cacert: Path to the Privacy Enhanced Mail (PEM) file
|
||||||
which contains the trusted authority X.509
|
which contains the trusted authority X.509
|
||||||
certificates needed to established SSL connection
|
certificates needed to established SSL connection
|
||||||
with the identity service. (optional)
|
with the identity service. (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
:param string key: Path to the Privacy Enhanced Mail (PEM) file which
|
:param string key: Path to the Privacy Enhanced Mail (PEM) file which
|
||||||
contains the unencrypted client private key needed
|
contains the unencrypted client private key needed
|
||||||
to established two-way SSL connection with the
|
to established two-way SSL connection with the
|
||||||
identity service. (optional)
|
identity service. (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
:param string cert: Path to the Privacy Enhanced Mail (PEM) file which
|
:param string cert: Path to the Privacy Enhanced Mail (PEM) file which
|
||||||
contains the corresponding X.509 client certificate
|
contains the corresponding X.509 client certificate
|
||||||
needed to established two-way SSL connection with
|
needed to established two-way SSL connection with
|
||||||
the identity service. (optional)
|
the identity service. (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
:param boolean insecure: Does not perform X.509 certificate validation
|
:param boolean insecure: Does not perform X.509 certificate validation
|
||||||
when establishing SSL connection with identity
|
when establishing SSL connection with identity
|
||||||
service. default: False (optional)
|
service. default: False (optional)
|
||||||
|
DEPRECATED: use the session object. This is
|
||||||
|
ignored if a session is provided.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not session:
|
||||||
|
session = client_session.Session.construct(kwargs)
|
||||||
|
kwargs['session'] = session
|
||||||
|
|
||||||
url = kwargs.get('endpoint') or kwargs.get('auth_url')
|
url = kwargs.get('endpoint') or kwargs.get('auth_url')
|
||||||
if not url:
|
if not url:
|
||||||
raise exceptions.DiscoveryFailure('Not enough information to '
|
raise exceptions.DiscoveryFailure('Not enough information to '
|
||||||
@@ -212,7 +241,7 @@ class Discover(object):
|
|||||||
'auth_url or endpoint')
|
'auth_url or endpoint')
|
||||||
|
|
||||||
self._client_kwargs = kwargs
|
self._client_kwargs = kwargs
|
||||||
self._available_versions = available_versions(url, **kwargs)
|
self._available_versions = available_versions(url, session=session)
|
||||||
|
|
||||||
def _get_client_constructor_kwargs(self, kwargs_dict={}, **kwargs):
|
def _get_client_constructor_kwargs(self, kwargs_dict={}, **kwargs):
|
||||||
client_kwargs = self._client_kwargs.copy()
|
client_kwargs = self._client_kwargs.copy()
|
||||||
@@ -420,4 +449,4 @@ class Discover(object):
|
|||||||
|
|
||||||
raise exceptions.VersionNotAvailable(msg)
|
raise exceptions.VersionNotAvailable(msg)
|
||||||
|
|
||||||
return chosen()
|
return chosen.create_client()
|
||||||
|
@@ -55,14 +55,13 @@ request = client_session.request
|
|||||||
class HTTPClient(object):
|
class HTTPClient(object):
|
||||||
|
|
||||||
def __init__(self, username=None, tenant_id=None, tenant_name=None,
|
def __init__(self, username=None, tenant_id=None, tenant_name=None,
|
||||||
password=None, auth_url=None, region_name=None, timeout=None,
|
password=None, auth_url=None, region_name=None, endpoint=None,
|
||||||
endpoint=None, token=None, cacert=None, key=None,
|
token=None, debug=False, auth_ref=None, use_keyring=False,
|
||||||
cert=None, insecure=False, original_ip=None, debug=False,
|
force_new_token=False, stale_duration=None, user_id=None,
|
||||||
auth_ref=None, use_keyring=False, force_new_token=False,
|
user_domain_id=None, user_domain_name=None, domain_id=None,
|
||||||
stale_duration=None, user_id=None, user_domain_id=None,
|
domain_name=None, project_id=None, project_name=None,
|
||||||
user_domain_name=None, domain_id=None, domain_name=None,
|
project_domain_id=None, project_domain_name=None,
|
||||||
project_id=None, project_name=None, project_domain_id=None,
|
trust_id=None, session=None, **kwargs):
|
||||||
project_domain_name=None, trust_id=None, session=None):
|
|
||||||
"""Construct a new http client
|
"""Construct a new http client
|
||||||
|
|
||||||
:param string user_id: User ID for authentication. (optional)
|
:param string user_id: User ID for authentication. (optional)
|
||||||
@@ -223,22 +222,7 @@ class HTTPClient(object):
|
|||||||
self._auth_token = None
|
self._auth_token = None
|
||||||
|
|
||||||
if not session:
|
if not session:
|
||||||
verify = cacert or True
|
session = client_session.Session.construct(kwargs)
|
||||||
if insecure:
|
|
||||||
verify = False
|
|
||||||
|
|
||||||
session_cert = None
|
|
||||||
if cert and key:
|
|
||||||
session_cert = (cert, key)
|
|
||||||
elif cert:
|
|
||||||
_logger.warn("Client cert was provided without corresponding "
|
|
||||||
"key. Ignoring.")
|
|
||||||
|
|
||||||
timeout = float(timeout) if timeout is not None else None
|
|
||||||
session = client_session.Session(verify=verify,
|
|
||||||
cert=session_cert,
|
|
||||||
original_ip=original_ip,
|
|
||||||
timeout=timeout)
|
|
||||||
|
|
||||||
self.session = session
|
self.session = session
|
||||||
self.domain = ''
|
self.domain = ''
|
||||||
|
@@ -249,3 +249,40 @@ class Session(object):
|
|||||||
|
|
||||||
def patch(self, url, **kwargs):
|
def patch(self, url, **kwargs):
|
||||||
return self.request(url, 'PATCH', **kwargs)
|
return self.request(url, 'PATCH', **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def construct(cls, kwargs):
|
||||||
|
"""Handles constructing a session from the older HTTPClient args as
|
||||||
|
well as the new request style arguments.
|
||||||
|
|
||||||
|
*DEPRECATED*: This function is purely for bridging the gap between
|
||||||
|
older client arguments and the session arguments that they relate to.
|
||||||
|
It is not intended to be used as a generic Session Factory.
|
||||||
|
|
||||||
|
This function purposefully modifies the input kwargs dictionary so that
|
||||||
|
the remaining kwargs dict can be reused and passed on to other
|
||||||
|
functionswithout session arguments.
|
||||||
|
|
||||||
|
"""
|
||||||
|
verify = kwargs.pop('verify', None)
|
||||||
|
cacert = kwargs.pop('cacert', None)
|
||||||
|
cert = kwargs.pop('cert', None)
|
||||||
|
key = kwargs.pop('key', None)
|
||||||
|
insecure = kwargs.pop('insecure', False)
|
||||||
|
|
||||||
|
if verify is None:
|
||||||
|
if insecure:
|
||||||
|
verify = False
|
||||||
|
else:
|
||||||
|
verify = cacert or True
|
||||||
|
|
||||||
|
if cert and key:
|
||||||
|
# passing cert and key together is deprecated in favour of the
|
||||||
|
# requests lib form of having the cert and key as a tuple
|
||||||
|
cert = (cert, key)
|
||||||
|
|
||||||
|
return cls(verify=verify, cert=cert,
|
||||||
|
timeout=kwargs.pop('timeout', None),
|
||||||
|
session=kwargs.pop('session', None),
|
||||||
|
original_ip=kwargs.pop('original_ip', None),
|
||||||
|
user_agent=kwargs.pop('user_agent', None))
|
||||||
|
@@ -222,3 +222,33 @@ class RedirectTests(utils.TestCase):
|
|||||||
for r, s in zip(req_resp.history, ses_resp.history):
|
for r, s in zip(req_resp.history, ses_resp.history):
|
||||||
self.assertEqual(r.url, s.url)
|
self.assertEqual(r.url, s.url)
|
||||||
self.assertEqual(r.status_code, s.status_code)
|
self.assertEqual(r.status_code, s.status_code)
|
||||||
|
|
||||||
|
|
||||||
|
class ConstructSessionFromArgsTests(utils.TestCase):
|
||||||
|
|
||||||
|
KEY = 'keyfile'
|
||||||
|
CERT = 'certfile'
|
||||||
|
CACERT = 'cacert-path'
|
||||||
|
|
||||||
|
def _s(self, k=None, **kwargs):
|
||||||
|
k = k or kwargs
|
||||||
|
return client_session.Session.construct(k)
|
||||||
|
|
||||||
|
def test_verify(self):
|
||||||
|
self.assertFalse(self._s(insecure=True).verify)
|
||||||
|
self.assertTrue(self._s(verify=True, insecure=True).verify)
|
||||||
|
self.assertFalse(self._s(verify=False, insecure=True).verify)
|
||||||
|
self.assertEqual(self._s(cacert=self.CACERT).verify, self.CACERT)
|
||||||
|
|
||||||
|
def test_cert(self):
|
||||||
|
tup = (self.CERT, self.KEY)
|
||||||
|
self.assertEqual(self._s(cert=tup).cert, tup)
|
||||||
|
self.assertEqual(self._s(cert=self.CERT, key=self.KEY).cert, tup)
|
||||||
|
self.assertIsNone(self._s(key=self.KEY).cert)
|
||||||
|
|
||||||
|
def test_pass_through(self):
|
||||||
|
value = 42 # only a number because timeout needs to be
|
||||||
|
for key in ['timeout', 'session', 'original_ip', 'user_agent']:
|
||||||
|
args = {key: value}
|
||||||
|
self.assertEqual(getattr(self._s(args), key), value)
|
||||||
|
self.assertNotIn(key, args)
|
||||||
|
Reference in New Issue
Block a user