Add keystone v3 auth support

This change enables the neutron client to use the keystone v3 API (in
addition to v2).  This allows user domains and tenant/project domains to
be specified.  This is necessary because keystone v2 API is deprecated
as of Icehouse.

The keystone session object (and auth plugin) can now be specified
and are required to use the keystone v3 API.  The existing HTTPClient
is retained for backward compatibility.  See changes in shell.py for
an example of how to construct the session and auth plugin.

Implements: blueprint keystone-api-v3-support

Change-Id: I9d0395d405b9fbe4db08ad3727f9413be7b82811
This commit is contained in:
Bradley Klein 2014-05-05 15:00:03 -04:00
parent d07c65c7fc
commit 2203b013fb
9 changed files with 942 additions and 128 deletions

@ -22,6 +22,7 @@ import logging
import os
from keystoneclient import access
from keystoneclient.auth.identity.base import BaseIdentityPlugin
import requests
from neutronclient.common import exceptions
@ -41,11 +42,25 @@ else:
logging.getLogger("requests").setLevel(_requests_log_level)
class HTTPClient(object):
"""Handles the REST calls and responses, include authn."""
class NeutronClientMixin(object):
USER_AGENT = 'python-neutronclient'
def get_status_code(self, response):
"""Returns the integer status code from the response.
Either a Webob.Response (used in testing) or requests.Response
is returned.
"""
if hasattr(response, 'status_int'):
return response.status_int
else:
return response.status_code
class HTTPClient(NeutronClientMixin):
"""Handles the REST calls and responses, include authn."""
def __init__(self, username=None, user_id=None,
tenant_name=None, tenant_id=None,
password=None, auth_url=None,
@ -265,13 +280,122 @@ class HTTPClient(object):
'auth_user_id': self.auth_user_id,
'endpoint_url': self.endpoint_url}
def get_status_code(self, response):
"""Returns the integer status code from the response.
Either a Webob.Response (used in testing) or requests.Response
is returned.
"""
if hasattr(response, 'status_int'):
return response.status_int
else:
return response.status_code
class SessionClient(NeutronClientMixin):
def __init__(self,
session,
auth,
interface=None,
service_type=None,
region_name=None):
self.session = session
self.auth = auth
self.interface = interface
self.service_type = service_type
self.region_name = region_name
self.auth_token = None
self.endpoint_url = None
def request(self, url, method, **kwargs):
kwargs.setdefault('user_agent', self.USER_AGENT)
kwargs.setdefault('auth', self.auth)
kwargs.setdefault('authenticated', False)
try:
kwargs['data'] = kwargs.pop('body')
except KeyError:
pass
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
endpoint_filter.setdefault('interface', self.interface)
endpoint_filter.setdefault('service_type', self.service_type)
endpoint_filter.setdefault('region_name', self.region_name)
kwargs = utils.safe_encode_dict(kwargs)
resp = self.session.request(url, method, **kwargs)
return resp, resp.text
def do_request(self, url, method, **kwargs):
kwargs.setdefault('authenticated', True)
return self.request(url, method, **kwargs)
def authenticate(self):
# This method is provided for backward compatibility only.
# We only care about setting the service endpoint.
self.endpoint_url = self.session.get_endpoint(
self.auth,
service_type=self.service_type,
region_name=self.region_name,
interface=self.interface)
def authenticate_and_fetch_endpoint_url(self):
# This method is provided for backward compatibility only.
# We only care about setting the service endpoint.
self.authenticate()
def get_auth_info(self):
# This method is provided for backward compatibility only.
if not isinstance(self.auth, BaseIdentityPlugin):
msg = ('Auth info not available. Auth plugin is not an identity '
'auth plugin.')
raise exceptions.NeutronClientException(message=msg)
access_info = self.auth.get_access(self.session)
endpoint_url = self.auth.get_endpoint(self.session,
service_type=self.service_type,
region_name=self.region_name,
interface=self.interface)
return {'auth_token': access_info.auth_token,
'auth_tenant_id': access_info.tenant_id,
'auth_user_id': access_info.user_id,
'endpoint_url': endpoint_url}
# FIXME(bklei): Should refactor this to use kwargs and only
# explicitly list arguments that are not None.
def construct_http_client(username=None,
user_id=None,
tenant_name=None,
tenant_id=None,
password=None,
auth_url=None,
token=None,
region_name=None,
timeout=None,
endpoint_url=None,
insecure=False,
endpoint_type='publicURL',
log_credentials=None,
auth_strategy='keystone',
ca_cert=None,
service_type='network',
session=None,
auth=None):
if session:
return SessionClient(session=session,
auth=auth,
interface=endpoint_type,
service_type=service_type,
region_name=region_name)
else:
# FIXME(bklei): username and password are now optional. Need
# to test that they were provided in this mode. Should also
# refactor to use kwargs.
return HTTPClient(username=username,
password=password,
tenant_id=tenant_id,
tenant_name=tenant_name,
user_id=user_id,
auth_url=auth_url,
token=token,
endpoint_url=endpoint_url,
insecure=insecure,
timeout=timeout,
region_name=region_name,
endpoint_type=endpoint_type,
service_type=service_type,
ca_cert=ca_cert,
log_credentials=log_credentials,
auth_strategy=auth_strategy)

@ -66,7 +66,9 @@ class ClientManager(object):
service_type=None,
timeout=None,
retries=0,
raise_errors=True
raise_errors=True,
session=None,
auth=None,
):
self._token = token
self._url = url
@ -88,10 +90,13 @@ class ClientManager(object):
self._timeout = timeout
self._retries = retries
self._raise_errors = raise_errors
self._session = session
self._auth = auth
return
def initialize(self):
if not self._url:
httpclient = client.HTTPClient(
httpclient = client.construct_http_client(
username=self._username,
user_id=self._user_id,
tenant_name=self._tenant_name,
@ -103,8 +108,10 @@ class ClientManager(object):
endpoint_type=self._endpoint_type,
insecure=self._insecure,
ca_cert=self._ca_cert,
log_credentials=self._log_credentials,
timeout=self._timeout)
timeout=self._timeout,
session=self._session,
auth=self._auth,
log_credentials=self._log_credentials)
httpclient.authenticate()
# Populate other password flow attributes
self._token = httpclient.auth_token

@ -48,7 +48,9 @@ def make_client(instance):
insecure=instance._insecure,
ca_cert=instance._ca_cert,
retries=instance._retries,
raise_errors=instance._raise_errors)
raise_errors=instance._raise_errors,
session=instance._session,
auth=instance._auth)
return client
else:
raise exceptions.UnsupportedVersion(_("API version %s is not "

@ -25,6 +25,13 @@ import logging
import os
import sys
from keystoneclient.auth.identity import v2 as v2_auth
from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import discover
from keystoneclient.openstack.common.apiclient import exceptions as ks_exc
from keystoneclient import session
import six.moves.urllib.parse as urlparse
from cliff import app
from cliff import commandmanager
@ -386,13 +393,50 @@ class NeutronShell(app.App):
default=0,
help=_("How many times the request to the Neutron server should "
"be retried if it fails."))
# Global arguments
# FIXME(bklei): this method should come from python-keystoneclient
self._append_global_identity_args(parser)
return parser
def _append_global_identity_args(self, parser):
# FIXME(bklei): these are global identity (Keystone) arguments which
# should be consistent and shared by all service clients. Therefore,
# they should be provided by python-keystoneclient. We will need to
# refactor this code once this functionality is available in
# python-keystoneclient.
#
# Note: At that time we'll need to decide if we can just abandon
# the deprecated args (--service-type and --endpoint-type).
parser.add_argument(
'--os-service-type', metavar='<os-service-type>',
default=env('OS_NETWORK_SERVICE_TYPE', default='network'),
help=_('Defaults to env[OS_NETWORK_SERVICE_TYPE] or network.'))
parser.add_argument(
'--os-endpoint-type', metavar='<os-endpoint-type>',
default=env('OS_ENDPOINT_TYPE', default='publicURL'),
help=_('Defaults to env[OS_ENDPOINT_TYPE] or publicURL.'))
# FIXME(bklei): --service-type is deprecated but kept in for
# backward compatibility.
parser.add_argument(
'--service-type', metavar='<service-type>',
default=env('OS_NETWORK_SERVICE_TYPE', default='network'),
help=_('DEPRECATED! Use --os-service-type.'))
# FIXME(bklei): --endpoint-type is deprecated but kept in for
# backward compatibility.
parser.add_argument(
'--endpoint-type', metavar='<endpoint-type>',
default=env('OS_ENDPOINT_TYPE', default='publicURL'),
help=_('DEPRECATED! Use --os-endpoint-type.'))
parser.add_argument(
'--os-auth-strategy', metavar='<auth-strategy>',
default=env('OS_AUTH_STRATEGY', default='keystone'),
help=_('Authentication strategy, defaults to '
'env[OS_AUTH_STRATEGY] or keystone. For now, any '
'other value will disable the authentication.'))
help=_('DEPRECATED! Only keystone is supported.'))
parser.add_argument(
'--os_auth_strategy',
help=argparse.SUPPRESS)
@ -405,20 +449,39 @@ class NeutronShell(app.App):
'--os_auth_url',
help=argparse.SUPPRESS)
parser.add_argument(
project_name_group = parser.add_mutually_exclusive_group()
project_name_group.add_argument(
'--os-tenant-name', metavar='<auth-tenant-name>',
default=env('OS_TENANT_NAME'),
help=_('Authentication tenant name, defaults to '
'env[OS_TENANT_NAME].'))
project_name_group.add_argument(
'--os-project-name',
metavar='<auth-project-name>',
default=utils.env('OS_PROJECT_NAME'),
help='Another way to specify tenant name. '
'This option is mutually exclusive with '
' --os-tenant-name. '
'Defaults to env[OS_PROJECT_NAME].')
parser.add_argument(
'--os_tenant_name',
help=argparse.SUPPRESS)
parser.add_argument(
project_id_group = parser.add_mutually_exclusive_group()
project_id_group.add_argument(
'--os-tenant-id', metavar='<auth-tenant-id>',
default=env('OS_TENANT_ID'),
help=_('Authentication tenant ID, defaults to '
'env[OS_TENANT_ID].'))
project_id_group.add_argument(
'--os-project-id',
metavar='<auth-project-id>',
default=utils.env('OS_PROJECT_ID'),
help='Another way to specify tenant ID. '
'This option is mutually exclusive with '
' --os-tenant-id. '
'Defaults to env[OS_PROJECT_ID].')
parser.add_argument(
'--os-username', metavar='<auth-username>',
@ -433,6 +496,78 @@ class NeutronShell(app.App):
default=env('OS_USER_ID'),
help=_('Authentication user ID (Env: OS_USER_ID)'))
parser.add_argument(
'--os_user_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--os-user-domain-id',
metavar='<auth-user-domain-id>',
default=utils.env('OS_USER_DOMAIN_ID'),
help='OpenStack user domain ID. '
'Defaults to env[OS_USER_DOMAIN_ID].')
parser.add_argument(
'--os_user_domain_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--os-user-domain-name',
metavar='<auth-user-domain-name>',
default=utils.env('OS_USER_DOMAIN_NAME'),
help='OpenStack user domain name. '
'Defaults to env[OS_USER_DOMAIN_NAME].')
parser.add_argument(
'--os_user_domain_name',
help=argparse.SUPPRESS)
parser.add_argument(
'--os_project_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--os_project_name',
help=argparse.SUPPRESS)
parser.add_argument(
'--os-project-domain-id',
metavar='<auth-project-domain-id>',
default=utils.env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
parser.add_argument(
'--os-project-domain-name',
metavar='<auth-project-domain-name>',
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
parser.add_argument(
'--os-cert',
metavar='<certificate>',
default=utils.env('OS_CERT'),
help=_("Path of certificate file to use in SSL "
"connection. This file can optionally be "
"prepended with the private key. Defaults "
"to env[OS_CERT]"))
parser.add_argument(
'--os-cacert',
metavar='<ca-certificate>',
default=env('OS_CACERT', default=None),
help=_("Specify a CA bundle file to use in "
"verifying a TLS (https) server certificate. "
"Defaults to env[OS_CACERT]"))
parser.add_argument(
'--os-key',
metavar='<key>',
default=utils.env('OS_KEY'),
help=_("Path of client key to use in SSL "
"connection. This option is not necessary "
"if your key is prepended to your certificate "
"file. Defaults to env[OS_KEY]"))
parser.add_argument(
'--os-password', metavar='<auth-password>',
default=utils.env('OS_PASSWORD'),
@ -458,22 +593,12 @@ class NeutronShell(app.App):
'--os_token',
help=argparse.SUPPRESS)
parser.add_argument(
'--service-type', metavar='<service-type>',
default=env('OS_NETWORK_SERVICE_TYPE', default='network'),
help=_('Defaults to env[OS_NETWORK_SERVICE_TYPE] or network.'))
parser.add_argument(
'--timeout', metavar='<seconds>',
default=env('OS_NETWORK_TIMEOUT', default=None), type=float,
help=_('Timeout in seconds to wait for an HTTP response. Defaults '
'to env[OS_NETWORK_TIMEOUT] or None if not specified.'))
parser.add_argument(
'--endpoint-type', metavar='<endpoint-type>',
default=env('OS_ENDPOINT_TYPE', default='publicURL'),
help=_('Defaults to env[OS_ENDPOINT_TYPE] or publicURL.'))
parser.add_argument(
'--os-url', metavar='<url>',
default=env('OS_URL'),
@ -482,14 +607,6 @@ class NeutronShell(app.App):
'--os_url',
help=argparse.SUPPRESS)
parser.add_argument(
'--os-cacert',
metavar='<ca-certificate>',
default=env('OS_CACERT', default=None),
help=_("Specify a CA bundle file to use in "
"verifying a TLS (https) server certificate. "
"Defaults to env[OS_CACERT]."))
parser.add_argument(
'--insecure',
action='store_true',
@ -499,8 +616,6 @@ class NeutronShell(app.App):
"not be verified against any certificate authorities. "
"This option should be used with caution."))
return parser
def _bash_completion(self):
"""Prints all of the commands and options for bash-completion."""
commands = set()
@ -622,6 +737,13 @@ class NeutronShell(app.App):
else:
# Validate password flow auth
project_info = (self.options.os_tenant_name or
self.options.os_tenant_id or
(self.options.os_project_name and
(self.options.project_domain_name or
self.options.project_domain_id)) or
self.options.os_project_id)
if (not self.options.os_username
and not self.options.os_user_id):
raise exc.CommandError(
@ -634,12 +756,19 @@ class NeutronShell(app.App):
_("You must provide a password via"
" either --os-password or env[OS_PASSWORD]"))
if (not self.options.os_tenant_name
and not self.options.os_tenant_id):
if (not project_info):
# tenent is deprecated in Keystone v3. Use the latest
# terminology instead.
raise exc.CommandError(
_("You must provide a tenant_name or tenant_id via"
" --os-tenant-name, env[OS_TENANT_NAME]"
" --os-tenant-id, or via env[OS_TENANT_ID]"))
_("You must provide a project_id or project_name ("
"with project_domain_name or project_domain_id) "
"via "
" --os-project-id (env[OS_PROJECT_ID])"
" --os-project-name (env[OS_PROJECT_NAME]),"
" --os-project-domain-id "
"(env[OS_PROJECT_DOMAIN_ID])"
" --os-project-domain-name "
"(env[OS_PROJECT_DOMAIN_NAME])"))
if not self.options.os_auth_url:
raise exc.CommandError(
@ -651,6 +780,8 @@ class NeutronShell(app.App):
_("You must provide a service URL via"
" either --os-url or env[OS_URL]"))
auth_session = self._get_keystone_session()
self.client_manager = clientmanager.ClientManager(
token=self.options.os_token,
url=self.options.os_url,
@ -663,13 +794,18 @@ class NeutronShell(app.App):
region_name=self.options.os_region_name,
api_version=self.api_version,
auth_strategy=self.options.os_auth_strategy,
service_type=self.options.service_type,
endpoint_type=self.options.endpoint_type,
# FIXME (bklei) honor deprecated service_type and
# endpoint type until they are removed
service_type=self.options.os_service_type or
self.options.service_type,
endpoint_type=self.options.os_endpoint_type or self.endpoint_type,
insecure=self.options.insecure,
ca_cert=self.options.os_cacert,
timeout=self.options.timeout,
retries=self.options.retries,
raise_errors=False,
session=auth_session,
auth=auth_session.auth,
log_credentials=True)
return
@ -721,6 +857,89 @@ class NeutronShell(app.App):
root_logger.addHandler(console)
return
def get_v2_auth(self, v2_auth_url):
return v2_auth.Password(
v2_auth_url,
username=self.options.os_username,
password=self.options.os_password,
tenant_id=self.options.os_tenant_id,
tenant_name=self.options.os_tenant_name)
def get_v3_auth(self, v3_auth_url):
project_id = self.options.os_project_id or self.options.os_tenant_id
project_name = (self.options.os_project_name or
self.options.os_tenant_name)
return v3_auth.Password(
v3_auth_url,
username=self.options.os_username,
password=self.options.os_password,
user_id=self.options.os_user_id,
user_domain_name=self.options.os_user_domain_name,
user_domain_id=self.options.os_user_domain_id,
project_id=project_id,
project_name=project_name,
project_domain_name=self.options.os_project_domain_name,
project_domain_id=self.options.os_project_domain_id
)
def _discover_auth_versions(self, session, auth_url):
# discover the API versions the server is supporting base on the
# given URL
try:
ks_discover = discover.Discover(session=session, auth_url=auth_url)
return (ks_discover.url_for('2.0'), ks_discover.url_for('3.0'))
except ks_exc.ClientException:
# Identity service may not support discover API version.
# Lets try to figure out the API version from the original URL.
url_parts = urlparse.urlparse(auth_url)
(scheme, netloc, path, params, query, fragment) = url_parts
path = path.lower()
if path.startswith('/v3'):
return (None, auth_url)
elif path.startswith('/v2'):
return (auth_url, None)
else:
# not enough information to determine the auth version
msg = _('Unable to determine the Keystone version '
'to authenticate with using the given '
'auth_url. Identity service may not support API '
'version discovery. Please provide a versioned '
'auth_url instead.')
raise exc.CommandError(msg)
def _get_keystone_session(self):
# first create a Keystone session
cacert = self.options.os_cacert or None
cert = self.options.os_cert or None
key = self.options.os_key or None
insecure = self.options.insecure or False
ks_session = session.Session.construct(dict(cacert=cacert,
cert=cert,
key=key,
insecure=insecure))
# discover the supported keystone versions using the given url
(v2_auth_url, v3_auth_url) = self._discover_auth_versions(
session=ks_session,
auth_url=self.options.os_auth_url)
# Determine which authentication plugin to use. First inspect the
# auth_url to see the supported version. If both v3 and v2 are
# supported, then use the highest version if possible.
user_domain_name = self.options.os_user_domain_name or None
user_domain_id = self.options.os_user_domain_id or None
project_domain_name = self.options.os_project_domain_name or None
project_domain_id = self.options.os_project_domain_id or None
domain_info = (user_domain_name or user_domain_id or
project_domain_name or project_domain_id)
if (v2_auth_url and not domain_info) or not v3_auth_url:
ks_session.auth = self.get_v2_auth(v2_auth_url)
else:
ks_session.auth = self.get_v3_auth(v3_auth_url)
return ks_session
def main(argv=sys.argv[1:]):
try:

@ -14,18 +14,25 @@
# under the License.
#
import copy
import json
import uuid
from keystoneclient import exceptions as k_exceptions
import httpretty
from mox3 import mox
import requests
import testtools
from keystoneclient.auth.identity import v2 as ks_v2_auth
from keystoneclient.auth.identity import v3 as ks_v3_auth
from keystoneclient import exceptions as ks_exceptions
from keystoneclient.fixture import v2 as ks_v2_fixture
from keystoneclient.fixture import v3 as ks_v3_fixture
from keystoneclient import session
from neutronclient import client
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.openstack.common import jsonutils
USERNAME = 'testuser'
@ -33,11 +40,14 @@ USER_ID = 'testuser_id'
TENANT_NAME = 'testtenant'
TENANT_ID = 'testtenant_id'
PASSWORD = 'password'
AUTH_URL = 'authurl'
ENDPOINT_URL = 'localurl'
PUBLIC_ENDPOINT_URL = 'public_%s' % ENDPOINT_URL
ADMIN_ENDPOINT_URL = 'admin_%s' % ENDPOINT_URL
INTERNAL_ENDPOINT_URL = 'internal_%s' % ENDPOINT_URL
ENDPOINT_OVERRIDE = 'otherurl'
TOKEN = 'tokentoken'
REGION = 'RegionTest'
TOKENID = uuid.uuid4().hex
REGION = 'RegionOne'
NOAUTH = 'noauth'
KS_TOKEN_RESULT = {
@ -69,6 +79,55 @@ ENDPOINTS_RESULT = {
}]
}
BASE_HOST = 'http://keystone.example.com'
BASE_URL = "%s:5000/" % BASE_HOST
UPDATED = '2013-03-06T00:00:00Z'
# FIXME (bklei): A future release of keystoneclient will support
# a discovery fixture which can replace these constants and clean
# this up.
V2_URL = "%sv2.0" % BASE_URL
V2_DESCRIBED_BY_HTML = {'href': 'http://docs.openstack.org/api/'
'openstack-identity-service/2.0/content/',
'rel': 'describedby',
'type': 'text/html'}
V2_DESCRIBED_BY_PDF = {'href': 'http://docs.openstack.org/api/openstack-ident'
'ity-service/2.0/identity-dev-guide-2.0.pdf',
'rel': 'describedby',
'type': 'application/pdf'}
V2_VERSION = {'id': 'v2.0',
'links': [{'href': V2_URL, 'rel': 'self'},
V2_DESCRIBED_BY_HTML, V2_DESCRIBED_BY_PDF],
'status': 'stable',
'updated': UPDATED}
V3_URL = "%sv3" % BASE_URL
V3_MEDIA_TYPES = [{'base': 'application/json',
'type': 'application/vnd.openstack.identity-v3+json'},
{'base': 'application/xml',
'type': 'application/vnd.openstack.identity-v3+xml'}]
V3_VERSION = {'id': 'v3.0',
'links': [{'href': V3_URL, 'rel': 'self'}],
'media-types': V3_MEDIA_TYPES,
'status': 'stable',
'updated': UPDATED}
def _create_version_entry(version):
return jsonutils.dumps({'version': version})
def _create_version_list(versions):
return jsonutils.dumps({'versions': {'values': versions}})
V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION])
V3_VERSION_ENTRY = _create_version_entry(V3_VERSION)
V2_VERSION_ENTRY = _create_version_entry(V2_VERSION)
def get_response(status_code, headers=None):
response = mox.Mox().CreateMock(requests.Response)
@ -77,6 +136,49 @@ def get_response(status_code, headers=None):
return response
def setup_keystone_v2():
v2_token = ks_v2_fixture.Token(token_id=TOKENID)
service = v2_token.add_service('network')
service.add_endpoint(PUBLIC_ENDPOINT_URL, region=REGION)
httpretty.register_uri(httpretty.POST,
'%s/tokens' % (V2_URL),
body=json.dumps(v2_token))
auth_session = session.Session()
auth_plugin = ks_v2_auth.Password(V2_URL, 'xx', 'xx')
return auth_session, auth_plugin
def setup_keystone_v3():
httpretty.register_uri(httpretty.GET,
V3_URL,
body=V3_VERSION_ENTRY)
v3_token = ks_v3_fixture.Token()
service = v3_token.add_service('network')
service.add_standard_endpoints(public=PUBLIC_ENDPOINT_URL,
admin=ADMIN_ENDPOINT_URL,
internal=INTERNAL_ENDPOINT_URL,
region=REGION)
httpretty.register_uri(httpretty.POST,
'%s/auth/tokens' % (V3_URL),
body=json.dumps(v3_token),
adding_headers={'X-Subject-Token': TOKENID})
auth_session = session.Session()
auth_plugin = ks_v3_auth.Password(V3_URL,
username='xx',
user_id='xx',
user_domain_name='xx',
user_domain_id='xx')
return auth_session, auth_plugin
AUTH_URL = V2_URL
class CLITestAuthNoAuth(testtools.TestCase):
def setUp(self):
@ -109,20 +211,18 @@ class CLITestAuthNoAuth(testtools.TestCase):
class CLITestAuthKeystone(testtools.TestCase):
# Auth Body expected
auth_body = ('{"auth": {"tenantName": "testtenant", '
'"passwordCredentials": '
'{"username": "testuser", "password": "password"}}}')
def setUp(self):
"""Prepare the test environment."""
super(CLITestAuthKeystone, self).setUp()
self.mox = mox.Mox()
self.client = client.HTTPClient(username=USERNAME,
tenant_name=TENANT_NAME,
password=PASSWORD,
auth_url=AUTH_URL,
region_name=REGION)
self.client = client.construct_http_client(
username=USERNAME,
tenant_name=TENANT_NAME,
password=PASSWORD,
auth_url=AUTH_URL,
region_name=REGION)
self.addCleanup(self.mox.VerifyAll)
self.addCleanup(self.mox.UnsetStubs)
@ -142,24 +242,30 @@ class CLITestAuthKeystone(testtools.TestCase):
'endpoint_url': self.client.endpoint_url}
self.assertEqual(client_.get_auth_info(), expected)
@httpretty.activate
def test_get_token(self):
self.mox.StubOutWithMock(self.client, "request")
auth_session, auth_plugin = setup_keystone_v2()
self.client = client.construct_http_client(
username=USERNAME,
tenant_name=TENANT_NAME,
password=PASSWORD,
auth_url=AUTH_URL,
region_name=REGION,
session=auth_session,
auth=auth_plugin)
self.mox.StubOutWithMock(self.client, "request")
res200 = get_response(200)
self.client.request(
AUTH_URL + '/tokens', 'POST',
body=self.auth_body, headers=mox.IsA(dict)
).AndReturn((res200, json.dumps(KS_TOKEN_RESULT)))
self.client.request(
mox.StrContains(ENDPOINT_URL + '/resource'), 'GET',
headers=mox.ContainsKeyValue('X-Auth-Token', TOKEN)
'/resource', 'GET',
authenticated=True
).AndReturn((res200, ''))
self.mox.ReplayAll()
self.client.do_request('/resource', 'GET')
self.assertEqual(self.client.endpoint_url, ENDPOINT_URL)
self.assertEqual(self.client.auth_token, TOKEN)
def test_refresh_token(self):
self.mox.StubOutWithMock(self.client, "request")
@ -292,53 +398,55 @@ class CLITestAuthKeystone(testtools.TestCase):
self.mox.ReplayAll()
self.client.do_request('/resource', 'GET')
@httpretty.activate
def test_endpoint_type(self):
resources = copy.deepcopy(KS_TOKEN_RESULT)
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
endpoints['internalURL'] = 'internal'
endpoints['adminURL'] = 'admin'
endpoints['publicURL'] = 'public'
auth_session, auth_plugin = setup_keystone_v3()
# Test default behavior is to choose public.
self.client = client.HTTPClient(
self.client = client.construct_http_client(
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
auth_url=AUTH_URL, region_name=REGION)
auth_url=AUTH_URL, region_name=REGION,
session=auth_session, auth=auth_plugin)
self.client._extract_service_catalog(resources)
self.assertEqual(self.client.endpoint_url, 'public')
self.client.authenticate()
self.assertEqual(self.client.endpoint_url, PUBLIC_ENDPOINT_URL)
# Test admin url
self.client = client.HTTPClient(
self.client = client.construct_http_client(
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
auth_url=AUTH_URL, region_name=REGION, endpoint_type='adminURL')
auth_url=AUTH_URL, region_name=REGION, endpoint_type='adminURL',
session=auth_session, auth=auth_plugin)
self.client._extract_service_catalog(resources)
self.assertEqual(self.client.endpoint_url, 'admin')
self.client.authenticate()
self.assertEqual(self.client.endpoint_url, ADMIN_ENDPOINT_URL)
# Test public url
self.client = client.HTTPClient(
self.client = client.construct_http_client(
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
auth_url=AUTH_URL, region_name=REGION, endpoint_type='publicURL')
auth_url=AUTH_URL, region_name=REGION, endpoint_type='publicURL',
session=auth_session, auth=auth_plugin)
self.client._extract_service_catalog(resources)
self.assertEqual(self.client.endpoint_url, 'public')
self.client.authenticate()
self.assertEqual(self.client.endpoint_url, PUBLIC_ENDPOINT_URL)
# Test internal url
self.client = client.HTTPClient(
self.client = client.construct_http_client(
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
auth_url=AUTH_URL, region_name=REGION, endpoint_type='internalURL')
auth_url=AUTH_URL, region_name=REGION, endpoint_type='internalURL',
session=auth_session, auth=auth_plugin)
self.client._extract_service_catalog(resources)
self.assertEqual(self.client.endpoint_url, 'internal')
self.client.authenticate()
self.assertEqual(self.client.endpoint_url, INTERNAL_ENDPOINT_URL)
# Test url that isn't found in the service catalog
self.client = client.HTTPClient(
self.client = client.construct_http_client(
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL')
auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL',
session=auth_session, auth=auth_plugin)
self.assertRaises(k_exceptions.EndpointNotFound,
self.client._extract_service_catalog,
resources)
self.assertRaises(
ks_exceptions.EndpointNotFound,
self.client.authenticate)
def test_strip_credentials_from_log(self):
def verify_no_credentials(kwargs):
@ -370,11 +478,6 @@ class CLITestAuthKeystone(testtools.TestCase):
class CLITestAuthKeystoneWithId(CLITestAuthKeystone):
# Auth Body expected
auth_body = ('{"auth": {"passwordCredentials": '
'{"password": "password", "userId": "testuser_id"}, '
'"tenantId": "testtenant_id"}}')
def setUp(self):
"""Prepare the test environment."""
super(CLITestAuthKeystoneWithId, self).setUp()
@ -387,11 +490,6 @@ class CLITestAuthKeystoneWithId(CLITestAuthKeystone):
class CLITestAuthKeystoneWithIdandName(CLITestAuthKeystone):
# Auth Body expected
auth_body = ('{"auth": {"passwordCredentials": '
'{"password": "password", "userId": "testuser_id"}, '
'"tenantId": "testtenant_id"}}')
def setUp(self):
"""Prepare the test environment."""
super(CLITestAuthKeystoneWithIdandName, self).setUp()
@ -402,3 +500,61 @@ class CLITestAuthKeystoneWithIdandName(CLITestAuthKeystone):
password=PASSWORD,
auth_url=AUTH_URL,
region_name=REGION)
class TestKeystoneClientVersions(testtools.TestCase):
def setUp(self):
"""Prepare the test environment."""
super(TestKeystoneClientVersions, self).setUp()
self.mox = mox.Mox()
self.addCleanup(self.mox.VerifyAll)
self.addCleanup(self.mox.UnsetStubs)
@httpretty.activate
def test_v2_auth(self):
auth_session, auth_plugin = setup_keystone_v2()
res200 = get_response(200)
self.client = client.construct_http_client(
username=USERNAME,
tenant_name=TENANT_NAME,
password=PASSWORD,
auth_url=AUTH_URL,
region_name=REGION,
session=auth_session,
auth=auth_plugin)
self.mox.StubOutWithMock(self.client, "request")
self.client.request(
'/resource', 'GET',
authenticated=True
).AndReturn((res200, ''))
self.mox.ReplayAll()
self.client.do_request('/resource', 'GET')
@httpretty.activate
def test_v3_auth(self):
auth_session, auth_plugin = setup_keystone_v3()
res200 = get_response(200)
self.client = client.construct_http_client(
user_id=USER_ID,
tenant_id=TENANT_ID,
password=PASSWORD,
auth_url=V3_URL,
region_name=REGION,
session=auth_session,
auth=auth_plugin)
self.mox.StubOutWithMock(self.client, "request")
self.client.request(
'/resource', 'GET',
authenticated=True
).AndReturn((res200, ''))
self.mox.ReplayAll()
self.client.do_request('/resource', 'GET')

@ -20,13 +20,19 @@ import re
import sys
import fixtures
import httpretty
from mox3 import mox
import six
import testtools
from testtools import matchers
from keystoneclient.auth.identity import v2 as v2_auth
from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import session
from neutronclient.common import clientmanager
from neutronclient import shell as openstack_shell
from neutronclient.tests.unit import test_auth as auth
DEFAULT_USERNAME = 'username'
@ -91,6 +97,14 @@ class ShellTest(testtools.TestCase):
matchers.MatchesRegex(required))
self.assertFalse(stderr)
def test_bash_completion(self):
required = '.*os_user_domain_id.*'
bash_completion, stderr = self.shell('bash-completion')
self.assertThat(
bash_completion,
matchers.MatchesRegex(required))
self.assertFalse(stderr)
def test_help_on_subcommand(self):
required = [
'.*?^usage: .* quota-list']
@ -116,27 +130,287 @@ class ShellTest(testtools.TestCase):
self.assertEqual('You must provide a service URL via '
'either --os-url or env[OS_URL]', stderr.strip())
@httpretty.activate
def test_auth(self):
#import pdb; pdb.set_trace()
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V3_URL,
body=auth.V3_VERSION_ENTRY)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url='http://127.0.0.1:5000/',
token='', url='', auth_url=auth.V3_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None, retries=0,
raise_errors=False, log_credentials=True, timeout=None)
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v3_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--os-auth-url http://127.0.0.1:5000/ '
'--os-auth-strategy keystone quota-list')
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V3_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_auth_cert_and_key(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V3_URL,
body=auth.V3_VERSION_ENTRY)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.V3_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
raise_errors=False,
endpoint_type='publicURL', insecure=False, ca_cert=None, retries=0,
timeout=None,
auth=mox.IsA(v3_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--os-cert test '
'--os-key test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V3_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_v2_auth(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V2_URL,
body=auth.V2_VERSION_ENTRY)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.V2_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v2_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V2_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_failed_auth_version_discovery_v3_auth_url(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V3_URL,
status=405)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.V3_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v3_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-user-domain-name test '
'--os-tenant-name test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V3_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_failed_auth_version_discovery_v2_auth_url(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V2_URL,
status=405)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.V2_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v2_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V2_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_auth_version_discovery_v3(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.BASE_URL,
body=auth.V3_VERSION_LIST)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.BASE_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v3_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-user-domain-name test '
'--os-tenant-name test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.BASE_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_auth_version_discovery_v2(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.BASE_URL,
body=auth.V3_VERSION_LIST)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.BASE_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=False, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IsA(v2_auth.Password),
session=mox.IsA(session.Session),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.BASE_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_insecure_auth(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V2_URL,
body=auth.V2_VERSION_ENTRY)
neutron_shell = openstack_shell.NeutronShell('2.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
self.mox.StubOutWithMock(neutron_shell, 'run_subcommand')
clientmanager.ClientManager.__init__(
token='', url='', auth_url=auth.V2_URL,
tenant_name='test', tenant_id='tenant_id',
username='test', user_id='',
password='test', region_name='', api_version={'network': '2.0'},
auth_strategy='keystone', service_type='network',
endpoint_type='publicURL', insecure=True, ca_cert=None,
timeout=None,
raise_errors=False,
retries=0,
auth=mox.IgnoreArg(),
session=mox.IgnoreArg(),
log_credentials=True)
neutron_shell.run_subcommand(['quota-list'])
self.mox.ReplayAll()
cmdline = ('--os-username test '
'--os-password test '
'--os-tenant-name test '
'--insecure '
'--os-auth-url %s '
'--os-auth-strategy keystone quota-list'
% auth.V2_URL)
neutron_shell.run(cmdline.split())
self.mox.VerifyAll()
@ -162,13 +436,13 @@ class ShellTest(testtools.TestCase):
shell = openstack_shell.NeutronShell('2.0')
parser = shell.build_option_parser('descr', '2.0')
# Neither $OS_ENDPOINT_TYPE nor --endpoint-type
# Neither $OS_ENDPOINT_TYPE nor --os-endpoint-type
namespace = parser.parse_args([])
self.assertEqual('publicURL', namespace.endpoint_type)
self.assertEqual('publicURL', namespace.os_endpoint_type)
# --endpoint-type but not $OS_ENDPOINT_TYPE
namespace = parser.parse_args(['--endpoint-type=admin'])
self.assertEqual('admin', namespace.endpoint_type)
namespace = parser.parse_args(['--os-endpoint-type=admin'])
self.assertEqual('admin', namespace.os_endpoint_type)
def test_endpoint_environment_variable(self):
fixture = fixtures.EnvironmentVariable("OS_ENDPOINT_TYPE",
@ -180,7 +454,7 @@ class ShellTest(testtools.TestCase):
# $OS_ENDPOINT_TYPE but not --endpoint-type
namespace = parser.parse_args([])
self.assertEqual("public", namespace.endpoint_type)
self.assertEqual("public", namespace.os_endpoint_type)
# --endpoint-type and $OS_ENDPOINT_TYPE
namespace = parser.parse_args(['--endpoint-type=admin'])

@ -14,15 +14,17 @@
# under the License.
import fixtures
from mox3 import mox
import requests
import testtools
import httpretty
from mox3 import mox
from neutronclient.client import HTTPClient
from neutronclient.common.clientmanager import ClientManager
from neutronclient.common import exceptions
from neutronclient import shell as openstack_shell
from neutronclient.tests.unit import test_auth as auth
AUTH_TOKEN = 'test_token'
END_URL = 'test_url'
@ -41,7 +43,13 @@ class TestSSL(testtools.TestCase):
self.mox = mox.Mox()
self.addCleanup(self.mox.UnsetStubs)
@httpretty.activate
def test_ca_cert_passed(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V3_URL,
body=auth.V3_VERSION_ENTRY)
self.mox.StubOutWithMock(ClientManager, '__init__')
self.mox.StubOutWithMock(openstack_shell.NeutronShell, 'interact')
@ -66,14 +74,27 @@ class TestSSL(testtools.TestCase):
raise_errors=mox.IgnoreArg(),
log_credentials=mox.IgnoreArg(),
timeout=mox.IgnoreArg(),
auth=mox.IgnoreArg(),
session=mox.IgnoreArg()
)
openstack_shell.NeutronShell.interact().AndReturn(0)
self.mox.ReplayAll()
openstack_shell.NeutronShell('2.0').run(['--os-cacert', CA_CERT])
cmdline = (
'--os-cacert %s --os-auth-url %s' %
(CA_CERT, auth.V3_URL))
openstack_shell.NeutronShell('2.0').run(cmdline.split())
self.mox.VerifyAll()
@httpretty.activate
def test_ca_cert_passed_as_env_var(self):
# emulate Keystone version discovery
httpretty.register_uri(httpretty.GET,
auth.V3_URL,
body=auth.V3_VERSION_ENTRY)
self.useFixture(fixtures.EnvironmentVariable('OS_CACERT', CA_CERT))
self.mox.StubOutWithMock(ClientManager, '__init__')
@ -100,11 +121,15 @@ class TestSSL(testtools.TestCase):
raise_errors=mox.IgnoreArg(),
log_credentials=mox.IgnoreArg(),
timeout=mox.IgnoreArg(),
auth=mox.IgnoreArg(),
session=mox.IgnoreArg()
)
openstack_shell.NeutronShell.interact().AndReturn(0)
self.mox.ReplayAll()
openstack_shell.NeutronShell('2.0').run([])
cmdline = ('--os-auth-url %s' % auth.V3_URL)
openstack_shell.NeutronShell('2.0').run(cmdline.split())
self.mox.VerifyAll()
def test_client_manager_properly_creates_httpclient_instance(self):
@ -121,8 +146,12 @@ class TestSSL(testtools.TestCase):
tenant_name=mox.IgnoreArg(),
token=mox.IgnoreArg(),
username=mox.IgnoreArg(),
retries=mox.IgnoreArg(),
raise_errors=mox.IgnoreArg(),
user_id=mox.IgnoreArg(),
tenant_id=mox.IgnoreArg(),
timeout=mox.IgnoreArg(),
log_credentials=mox.IgnoreArg(),
service_type=mox.IgnoreArg(),
endpoint_type=mox.IgnoreArg()
)
self.mox.ReplayAll()

@ -135,6 +135,8 @@ class Client(object):
:param bool raise_errors: If True then exceptions caused by connection
failure are propagated to the caller.
(default: True)
:param session: Keystone client auth session to use. (optional)
:param auth: Keystone auth plugin to use. (optional)
Example::
@ -1196,12 +1198,12 @@ class Client(object):
def __init__(self, **kwargs):
"""Initialize a new client for the Neutron v2.0 API."""
super(Client, self).__init__()
self.httpclient = client.HTTPClient(**kwargs)
self.retries = kwargs.pop('retries', 0)
self.raise_errors = kwargs.pop('raise_errors', True)
self.httpclient = client.construct_http_client(**kwargs)
self.version = '2.0'
self.format = 'json'
self.action_prefix = "/v%s" % (self.version)
self.retries = kwargs.get('retries', 0)
self.raise_errors = kwargs.get('raise_errors', True)
self.retry_interval = 1
def _handle_fault_response(self, status_code, response_body):

@ -4,6 +4,7 @@ cliff-tablib>=1.0
coverage>=3.6
discover
fixtures>=0.3.14
httpretty>=0.8.0,!=0.8.1,!=0.8.2
mox3>=0.7.0
oslosphinx
oslotest