Adding keystoneauth sessions support
This patch introduces the possibility of instantiating monascaclient using a keystoneauth session by doing the following: * Introduces new SessionClient object; * Refactor the keystoneclient wrapper module with keystoneauth; * Updates documentation. Client code and tests are also updated. Change-Id: I99ae10b2832869cf68d8219468400a421b6fa12b Closes-Bug: 1569505
This commit is contained in:
parent
962f2deb6a
commit
4c103fdf49
42
README.rst
42
README.rst
|
@ -80,10 +80,13 @@ When using Keystone to obtain the token and endpoint::
|
|||
export OS_PASSWORD=
|
||||
export OS_USER_DOMAIN_NAME=
|
||||
export OS_PROJECT_NAME=
|
||||
export OS_PROJECT_DOMAIN_NAME=
|
||||
export OS_PROJECT_NAME=
|
||||
export OS_AUTH_URL=
|
||||
export OS_REGION_NAME=
|
||||
|
||||
When OS_USER_DOMAIN_NAME is not set, then 'Default' is assumed. Alternatively IDs can be used instead of names.
|
||||
When OS_USER_DOMAIN_NAME and OS_PROJECT_DOMAIN_NAME are not set, then 'Default'
|
||||
is assumed. Alternatively IDs can be used instead of names.
|
||||
|
||||
When using Vagrant Environment with middleware disabled::
|
||||
|
||||
|
@ -102,7 +105,7 @@ You'll find complete documentation on the shell by running
|
|||
[--os-password OS_PASSWORD] [--os-project-id OS_PROJECT_ID]
|
||||
[--os-user-domain-id OS_USER_DOMAIN_ID] [--os-user-domain-name OS_USER_DOMAIN_NAME]
|
||||
[--os-project-name OS_PROJECT_NAME]
|
||||
[--os-domain-id OS_DOMAIN_ID] [--os-domain-name OS_DOMAIN_NAME]
|
||||
[--os-project-domain-id OS_PROJECT_DOMAIN_ID] [--os-project-domain-name OS_PROJECT_DOMAIN_NAME]
|
||||
[--os-auth-url OS_AUTH_URL] [--os-region-name OS_REGION_NAME]
|
||||
[--os-auth-token OS_AUTH_TOKEN] [--os-no-client-auth]
|
||||
[--monasca-api-url MONASCA_API_URL]
|
||||
|
@ -169,10 +172,10 @@ You'll find complete documentation on the shell by running
|
|||
Defaults to env[OS_PROJECT_ID].
|
||||
--os-project-name OS_PROJECT_NAME
|
||||
Defaults to env[OS_PROJECT_NAME].
|
||||
--os-domain-id OS_DOMAIN_ID
|
||||
Defaults to env[OS_DOMAIN_ID].
|
||||
--os-domain-name OS_DOMAIN_NAME
|
||||
Defaults to env[OS_DOMAIN_NAME].
|
||||
--os-project-domain-id OS_PROJECT_DOMAIN_ID
|
||||
Defaults to env[OS_PROJECT_DOMAIN_ID].
|
||||
--os-project-domain-name OS_PROJECT_DOMAIN_NAME
|
||||
Defaults to env[OS_PROJECT_DOMAIN_NAME].
|
||||
--os-auth-url OS_AUTH_URL Defaults to env[OS_AUTH_URL].
|
||||
--os-region-name OS_REGION_NAME
|
||||
Defaults to env[OS_REGION_NAME].
|
||||
|
@ -340,14 +343,20 @@ Python API
|
|||
There's also a complete Python API.
|
||||
|
||||
In order to use the python api directly, you must pass in a valid auth token and
|
||||
monasca api endpoint, or you can pass in the credentials required by the keystone
|
||||
client and let the Python API do the authentication. The user can obtain the token
|
||||
and endpoint using the keystone client api:
|
||||
http://docs.openstack.org/developer/python-keystoneclient/.
|
||||
monasca api endpoint or, preferably, a `keystoneauth session
|
||||
<http://docs.openstack.org/developer/keystoneauth/using-sessions.html>`.
|
||||
Alternatively, you can pass in the credentials required by the keystoneauth
|
||||
and let the Python API do the authentication. The user can obtain the session,
|
||||
token and endpoint using the keystoneauth api:
|
||||
http://docs.openstack.org/developer/keystoneauth.
|
||||
The service catalog name for our API endpoint is "monasca".
|
||||
|
||||
Start using the monascaclient API by constructing the monascaclient client.Client class.
|
||||
The Client class takes these parameters: api_version, endpoint, and token.
|
||||
The Client class takes these parameters:
|
||||
|
||||
#. api_version, session
|
||||
#. api_version, endpoint, and token (when using the client without a session)
|
||||
|
||||
The Client class is used to call all monasca-api resource commands (i.e.
|
||||
client.Client.metrics.create(fields)).
|
||||
|
||||
|
@ -358,7 +367,9 @@ up to the user to get a new token from keystone which can be passed
|
|||
into the client.Client.replace_token(token) method. If you constructed
|
||||
the Client with all the keystone credentials needed to authenticate,
|
||||
then the API will automatically try one time to re-authenticate with
|
||||
keystone whenever the token expires.
|
||||
keystone whenever the token expires. When using a session, though, this case
|
||||
will be handled by keystoneauth and replacing the session token will
|
||||
not be supported.
|
||||
|
||||
The api_version matches the version of the Monasca API. Currently it is 'v2_0'.
|
||||
|
||||
|
@ -377,10 +388,13 @@ Refer to the example in python-monascaclient/client_api_example.py for more deta
|
|||
|
||||
# Authenticate to Keystone
|
||||
keystone_url = 'http://keystone:5000/v3'
|
||||
ks = ksclient.KSClient(auth_url=keystone_url, username='user', password='password')
|
||||
ks = ksclient.KSClient(auth_url=keystone_url, username='user',
|
||||
password='password', project_name='project_name',
|
||||
project_domain_name='project_domain_name',
|
||||
user_domain_name='user_domain_name')
|
||||
|
||||
# construct the mon client
|
||||
monasca_client = client.Client(api_version, ks.monasca_url, token=ks.token)
|
||||
monasca_client = client.Client(api_version, session=ks.session)
|
||||
|
||||
# call the metric-create command
|
||||
dimensions = {'instance_id': '12345', 'service': 'hello'}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
""" An example using monascaclient via the Python API """
|
||||
|
||||
from monascaclient import client
|
||||
from monascaclient import ksclient
|
||||
import monascaclient.exc as exc
|
||||
import time
|
||||
|
||||
|
@ -27,15 +28,14 @@ endpoint = 'http://192.168.10.4:8080/v2.0'
|
|||
api_version = '2_0'
|
||||
|
||||
# Pass in the keystone authentication kwargs to construct a monasca client.
|
||||
# The monasca_client will try to authenticate with keystone one time
|
||||
# when it sees a 401 unauthorized resp, to take care of a stale token.
|
||||
# In this example no token is input, so it will get a 401 when executing the
|
||||
# first metrics.create request, and will authenticate and try again.
|
||||
auth_kwargs = {'username': 'mini-mon',
|
||||
'password': 'password',
|
||||
'user_domain_name': 'mini-mon',
|
||||
'project_name': 'mini-mon',
|
||||
'project_domain_name': 'mini-mon',
|
||||
'auth_url': 'http://192.168.10.5:35357/v3/'}
|
||||
monasca_client = client.Client(api_version, endpoint, **auth_kwargs)
|
||||
ksclient = ksclient.KSClient(**auth_kwargs)
|
||||
monasca_client = client.Client(api_version, session=ksclient.session)
|
||||
|
||||
# you can reference the monascaclient.v2_0.shell.py
|
||||
# do_commands for command field initialization.
|
||||
|
|
|
@ -11,5 +11,5 @@ X-Python-Version: >= 2.6
|
|||
Package: python-monclient
|
||||
Architecture: all
|
||||
Section: python
|
||||
Depends: ${misc:Depends}, ${python:Depends}, libpython2.7, python-pkg-resources, python-pbr, python-keystoneclient, python-yaml, python-requests, python-prettytable, python-six
|
||||
Depends: ${misc:Depends}, ${python:Depends}, libpython2.7, python-pkg-resources, python-pbr, keystoneauth1, python-yaml, python-requests, python-prettytable, python-six
|
||||
Description: CLI for Monitoring
|
||||
|
|
|
@ -18,6 +18,7 @@ import logging
|
|||
import os
|
||||
import socket
|
||||
|
||||
from keystoneauth1 import adapter
|
||||
import requests
|
||||
import six
|
||||
|
||||
|
@ -53,6 +54,12 @@ def get_system_ca_file():
|
|||
LOG.warn("System ca file could not be found.")
|
||||
|
||||
|
||||
def unauthorized(resp):
|
||||
status401 = (resp.status_code == 401)
|
||||
status500 = (resp.status_code == 500 and "(HTTP 401)" in resp.content)
|
||||
return status401 or status500
|
||||
|
||||
|
||||
class HTTPClient(object):
|
||||
|
||||
def __init__(self, endpoint, write_timeout=None, read_timeout=None, **kwargs):
|
||||
|
@ -74,8 +81,8 @@ class HTTPClient(object):
|
|||
self.project_name = kwargs.get('project_name')
|
||||
self.region_name = kwargs.get('region_name')
|
||||
self.project_id = kwargs.get('project_id')
|
||||
self.domain_id = kwargs.get('domain_id')
|
||||
self.domain_name = kwargs.get('domain_name')
|
||||
self.project_domain_id = kwargs.get('project_domain_id')
|
||||
self.project_domain_name = kwargs.get('project_domain_name')
|
||||
self.endpoint_type = kwargs.get('endpoint_type')
|
||||
self.service_type = kwargs.get('service_type')
|
||||
self.keystone_timeout = kwargs.get('keystone_timeout')
|
||||
|
@ -114,8 +121,8 @@ class HTTPClient(object):
|
|||
'os_cacert': self.ssl_connection_params['os_cacert'],
|
||||
'project_id': self.project_id,
|
||||
'project_name': self.project_name,
|
||||
'domain_id': self.domain_id,
|
||||
'domain_name': self.domain_name,
|
||||
'project_domain_id': self.project_domain_id,
|
||||
'project_domain_name': self.project_domain_name,
|
||||
'insecure': self.ssl_connection_params['insecure'],
|
||||
'region_name': self.region_name,
|
||||
'keystone_timeout': self.keystone_timeout
|
||||
|
@ -213,7 +220,7 @@ class HTTPClient(object):
|
|||
|
||||
resp = self._make_request(method, url, allow_redirects, timeout,
|
||||
**kwargs)
|
||||
if self._unauthorized(resp):
|
||||
if unauthorized(resp):
|
||||
try:
|
||||
# re-authenticate and attempt one more request
|
||||
self.re_authenticate()
|
||||
|
@ -227,13 +234,8 @@ class HTTPClient(object):
|
|||
self._check_status_code(resp, method, **kwargs)
|
||||
return resp
|
||||
|
||||
def _unauthorized(self, resp):
|
||||
status401 = (resp.status_code == 401)
|
||||
status500 = (resp.status_code == 500 and "(HTTP 401)" in resp.content)
|
||||
return status401 or status500
|
||||
|
||||
def _check_status_code(self, resp, method, **kwargs):
|
||||
if self._unauthorized(resp):
|
||||
if unauthorized(resp):
|
||||
message = "Unauthorized error"
|
||||
raise exc.HTTPUnauthorized(message=message)
|
||||
elif 400 <= resp.status_code < 600:
|
||||
|
@ -338,3 +340,81 @@ class HTTPClient(object):
|
|||
|
||||
def patch(self, url, **kwargs):
|
||||
return self.client_request("PATCH", url, **kwargs)
|
||||
|
||||
|
||||
class SessionClient(adapter.LegacyJsonAdapter):
|
||||
"""HTTP client based on keystoneauth session."""
|
||||
|
||||
def __init__(self, user_agent=USER_AGENT, logger=LOG, *args, **kwargs):
|
||||
super(SessionClient, self).__init__(*args, **kwargs)
|
||||
|
||||
def _http_request(self, url, method, **kwargs):
|
||||
kwargs.setdefault('user_agent', self.user_agent)
|
||||
kwargs.setdefault('auth', self.auth)
|
||||
kwargs.setdefault('endpoint_override', self.endpoint_override)
|
||||
|
||||
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)
|
||||
|
||||
resp = self.session.request(url, method, raise_exc=False, **kwargs)
|
||||
|
||||
if unauthorized(resp):
|
||||
message = "Unauthorized error"
|
||||
raise exc.HTTPUnauthorized(message=message)
|
||||
if 400 <= resp.status_code < 600:
|
||||
raise exc.from_response(resp)
|
||||
elif resp.status_code in (301, 302, 305):
|
||||
# Redirected. Reissue the request to the new location.
|
||||
location = resp.headers.get('location')
|
||||
resp = self._http_request(location, method, **kwargs)
|
||||
elif resp.status_code == 300:
|
||||
raise exc.from_response(resp)
|
||||
|
||||
return resp
|
||||
|
||||
def json_request(self, method, url, **kwargs):
|
||||
kwargs.setdefault('headers', {})
|
||||
kwargs['headers'].setdefault('Content-Type', 'application/json')
|
||||
kwargs['headers'].setdefault('Accept', 'application/json')
|
||||
|
||||
if 'data' in kwargs:
|
||||
kwargs['data'] = jsonutils.dumps(kwargs['data'])
|
||||
|
||||
resp = self._http_request(url, method, **kwargs)
|
||||
body = resp.content
|
||||
content_type = resp.headers.get('content-type', None)
|
||||
status = resp.status_code
|
||||
|
||||
if status == 204 or status == 205 or content_type is None:
|
||||
return resp, list()
|
||||
|
||||
if 'application/json' in content_type:
|
||||
try:
|
||||
body = resp.json()
|
||||
except ValueError:
|
||||
LOG.error('Could not decode response body as JSON')
|
||||
else:
|
||||
body = None
|
||||
|
||||
return resp, body
|
||||
|
||||
def raw_request(self, method, url, **kwargs):
|
||||
kwargs.setdefault('headers', {})
|
||||
kwargs['headers'].setdefault('Content-Type',
|
||||
'application/octet-stream')
|
||||
self._http_request(url, method, **kwargs)
|
||||
|
||||
def credentials_headers(self):
|
||||
credentials = self.session.auth.get_cache_id_elements()
|
||||
username = credentials.get('password_username')
|
||||
password = credentials.get('password_password')
|
||||
creds = {}
|
||||
|
||||
if username:
|
||||
creds['X-Auth-User'] = username
|
||||
if password:
|
||||
creds['X-Auth-Key'] = password
|
||||
|
||||
return creds
|
||||
|
|
|
@ -14,11 +14,15 @@
|
|||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Wrapper around python keystone client to assist in getting a properly scoped token and the registered service
|
||||
endpoint for Monasca.
|
||||
Wrapper around keystoneauth to assist in getting a session, a properly scoped
|
||||
token and the registered service endpoint for Monasca.
|
||||
|
||||
# FIXME(pauloewerton): this is not an appropriate name for this module nor
|
||||
# for the class. Kept for backwards compatibility.
|
||||
"""
|
||||
|
||||
from keystoneclient.v3 import client
|
||||
from keystoneauth1.identity import v3
|
||||
from keystoneauth1 import loading
|
||||
|
||||
from monascaclient import exc
|
||||
|
||||
|
@ -26,60 +30,74 @@ from monascaclient import exc
|
|||
class KSClient(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Get an endpoint and auth token from Keystone.
|
||||
"""Get a session, an endpoint and auth token from Keystone.
|
||||
|
||||
:param username: name of user
|
||||
:param password: user's password
|
||||
:param user_domain_id: unique identifier of domain username resides in (optional)
|
||||
:param user_domain_name: name of domain for username (optional), if user_domain_id not specified
|
||||
:param user_domain_id: unique identifier of domain the username
|
||||
resides in (optional)
|
||||
:param user_domain_name: name of domain for username (optional),
|
||||
if user_domain_id not specified
|
||||
:param project_id: unique identifier of project
|
||||
:param project_name: name of project
|
||||
:param domain_name: name of domain project is in
|
||||
:param domain_id: id of domain project is in
|
||||
:param project_domain_name: name of domain project is in
|
||||
:param project_domain_id: id of domain project is in
|
||||
:param auth_url: endpoint to authenticate against
|
||||
:param token: token to use instead of username/password
|
||||
"""
|
||||
kc_args = {'auth_url': kwargs.get('auth_url'),
|
||||
'insecure': kwargs.get('insecure'),
|
||||
'timeout': kwargs.get('keystone_timeout')}
|
||||
auth_params = {
|
||||
'auth_url': kwargs.get('auth_url'),
|
||||
'project_id': kwargs.get('project_id'),
|
||||
'project_name': kwargs.get('project_name'),
|
||||
'project_domain_id': kwargs.get('project_domain_id'),
|
||||
'project_domain_name': kwargs.get('project_domain_name')
|
||||
}
|
||||
|
||||
if kwargs.get('os_cacert'):
|
||||
kc_args['cacert'] = kwargs.get('os_cacert')
|
||||
if kwargs.get('project_id'):
|
||||
kc_args['project_id'] = kwargs.get('project_id')
|
||||
elif kwargs.get('project_name'):
|
||||
kc_args['project_name'] = kwargs.get('project_name')
|
||||
if kwargs.get('domain_name'):
|
||||
kc_args['project_domain_name'] = kwargs.get('domain_name')
|
||||
if kwargs.get('domain_id'):
|
||||
kc_args['project_domain_id'] = kwargs.get('domain_id')
|
||||
password_params = {
|
||||
'username': kwargs.get('username'),
|
||||
'password': kwargs.get('password'),
|
||||
'user_domain_id': kwargs.get('user_domain_id'),
|
||||
'user_domain_name': kwargs.get('user_domain_name')
|
||||
}
|
||||
|
||||
if kwargs.get('token'):
|
||||
kc_args['token'] = kwargs.get('token')
|
||||
token = kwargs.get('token')
|
||||
|
||||
if token:
|
||||
auth_params['token'] = token
|
||||
auth = v3.Token(**auth_params)
|
||||
else:
|
||||
kc_args['username'] = kwargs.get('username')
|
||||
kc_args['password'] = kwargs.get('password')
|
||||
# when username not in the default domain (id='default'), supply user domain (as namespace)
|
||||
if kwargs.get('user_domain_name'):
|
||||
kc_args['user_domain_name'] = kwargs.get('user_domain_name')
|
||||
if kwargs.get('user_domain_id'):
|
||||
kc_args['user_domain_id'] = kwargs.get('user_domain_id')
|
||||
auth_params.update(password_params)
|
||||
auth = v3.Password(**auth_params)
|
||||
|
||||
session_params = {
|
||||
'insecure': kwargs.get('insecure'),
|
||||
'cacert': kwargs.get('os_cacert'),
|
||||
'cert': kwargs.get('cert_file'),
|
||||
'key': kwargs.get('key_file')
|
||||
}
|
||||
|
||||
self._session = loading.session.Session().load_from_options(
|
||||
auth=auth, **session_params)
|
||||
|
||||
self._kwargs = kwargs
|
||||
self._keystone = client.Client(**kc_args)
|
||||
self._token = None
|
||||
self._monasca_url = None
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
"""Return the keystoneauth session object used for authentication."""
|
||||
return self._session
|
||||
|
||||
@property
|
||||
def token(self):
|
||||
"""Token property
|
||||
|
||||
Validate token is project scoped and return it if it is
|
||||
project_id and auth_token were fetched when keystone client was created
|
||||
Validate token is project scoped and return it if its project_id and
|
||||
token were fetched when keystoneauth session was created
|
||||
"""
|
||||
if self._token is None:
|
||||
if self._keystone.project_id:
|
||||
self._token = self._keystone.auth_token
|
||||
if self._session.get_project_id():
|
||||
self._token = self._session.get_token()
|
||||
else:
|
||||
raise exc.CommandError("No project id or project name.")
|
||||
return self._token
|
||||
|
@ -87,15 +105,13 @@ class KSClient(object):
|
|||
@property
|
||||
def monasca_url(self):
|
||||
"""Return the monasca publicURL registered in keystone."""
|
||||
if self._monasca_url is None:
|
||||
if self._kwargs.get('region_name'):
|
||||
self._monasca_url = self._keystone.service_catalog.url_for(
|
||||
service_type=self._kwargs.get('service_type') or 'monitoring',
|
||||
attr='region',
|
||||
filter_value=self._kwargs.get('region_name'),
|
||||
endpoint_type=self._kwargs.get('endpoint_type') or 'publicURL')
|
||||
else:
|
||||
self._monasca_url = self._keystone.service_catalog.url_for(
|
||||
service_type=self._kwargs.get('service_type') or 'monitoring',
|
||||
endpoint_type=self._kwargs.get('endpoint_type') or 'publicURL')
|
||||
service_type = self._kwargs.get('service_type', 'monitoring')
|
||||
service_name = self._kwargs.get('service_name', 'monasca')
|
||||
interface = self._kwargs.get('endpoint_type', 'public')
|
||||
region_name = self._kwargs.get('region_name')
|
||||
|
||||
if not self._monasca_url:
|
||||
self._monasca_url = self._session.get_endpoint(
|
||||
service_type=service_type, service_name=service_name,
|
||||
interface=interface, region_name=region_name)
|
||||
return self._monasca_url
|
||||
|
|
|
@ -140,18 +140,18 @@ class MonascaShell(object):
|
|||
parser.add_argument('--os_project_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-domain-id',
|
||||
default=utils.env('OS_DOMAIN_ID'),
|
||||
help='Defaults to env[OS_DOMAIN_ID].')
|
||||
parser.add_argument('--os-project-domain-id',
|
||||
default=utils.env('OS_PROJECT_DOMAIN_ID'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
|
||||
|
||||
parser.add_argument('--os_domain_id',
|
||||
parser.add_argument('--os_project_domain_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-domain-name',
|
||||
default=utils.env('OS_DOMAIN_NAME'),
|
||||
help='Defaults to env[OS_DOMAIN_NAME].')
|
||||
parser.add_argument('--os-project-domain-name',
|
||||
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
|
||||
|
||||
parser.add_argument('--os_domain_name',
|
||||
parser.add_argument('--os_project_domain_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-auth-url',
|
||||
|
@ -329,71 +329,50 @@ class MonascaShell(object):
|
|||
'auth_url': args.os_auth_url,
|
||||
'service_type': args.os_service_type,
|
||||
'endpoint_type': args.os_endpoint_type,
|
||||
'os_cacert': args.os_cacert,
|
||||
'user_domain_id': args.os_user_domain_id,
|
||||
'user_domain_name': args.os_user_domain_name,
|
||||
'project_id': args.os_project_id,
|
||||
'project_name': args.os_project_name,
|
||||
'domain_id': args.os_domain_id,
|
||||
'domain_name': args.os_domain_name,
|
||||
'project_domain_id': args.os_project_domain_id,
|
||||
'project_domain_name': args.os_project_domain_name,
|
||||
'insecure': args.insecure,
|
||||
'os_cacert': args.os_cacert,
|
||||
'cert_file': args.cert_file,
|
||||
'key_file': args.key_file,
|
||||
'region_name': args.os_region_name,
|
||||
'keystone_timeout': args.keystone_timeout
|
||||
}
|
||||
|
||||
endpoint = args.monasca_api_url
|
||||
session = None
|
||||
|
||||
if not args.os_no_client_auth:
|
||||
_ksclient = ksclient.KSClient(**kwargs)
|
||||
if args.os_auth_token:
|
||||
token = args.os_auth_token
|
||||
else:
|
||||
try:
|
||||
token = _ksclient.token
|
||||
except exc.CommandError:
|
||||
raise exc.CommandError(
|
||||
"User does not have a default project. "
|
||||
"You must provide a project id using "
|
||||
"--os-project-id or via env[OS_PROJECT_ID], "
|
||||
"or you must provide a project name using "
|
||||
"--os-project-name or via env[OS_PROJECT_NAME] "
|
||||
"and a project domain using --os-domain-name, via "
|
||||
"env[OS_DOMAIN_NAME], using --os-domain-id or "
|
||||
"via env[OS_DOMAIN_ID]")
|
||||
|
||||
kwargs = {
|
||||
'token': token,
|
||||
'insecure': args.insecure,
|
||||
'os_cacert': args.os_cacert,
|
||||
'cert_file': args.cert_file,
|
||||
'key_file': args.key_file,
|
||||
'username': args.os_username,
|
||||
'password': args.os_password,
|
||||
'service_type': args.os_service_type,
|
||||
'endpoint_type': args.os_endpoint_type,
|
||||
'auth_url': args.os_auth_url,
|
||||
'keystone_timeout': args.keystone_timeout
|
||||
}
|
||||
|
||||
if args.os_user_domain_name:
|
||||
kwargs['user_domain_name'] = args.os_user_domain_name
|
||||
if args.os_user_domain_id:
|
||||
kwargs['user_domain_id'] = args.os_user_domain_id
|
||||
if args.os_region_name:
|
||||
kwargs['region_name'] = args.os_region_name
|
||||
if args.os_project_name:
|
||||
kwargs['project_name'] = args.os_project_name
|
||||
if args.os_project_id:
|
||||
kwargs['project_id'] = args.os_project_id
|
||||
if args.os_domain_name:
|
||||
kwargs['domain_name'] = args.os_domain_name
|
||||
if args.os_domain_id:
|
||||
kwargs['domain_id'] = args.os_domain_id
|
||||
# Kept to check whether the token is indeed project scoped
|
||||
try:
|
||||
_ksclient.token
|
||||
except exc.CommandError:
|
||||
raise exc.CommandError(
|
||||
"User does not have a default project. "
|
||||
"You must provide a project id using "
|
||||
"--os-project-id or via env[OS_PROJECT_ID], "
|
||||
"or you must provide a project name using "
|
||||
"--os-project-name or via env[OS_PROJECT_NAME] "
|
||||
"and a project domain using --os-project-domain-name, "
|
||||
"via env[OS_PROJECT_DOMAIN_NAME], using "
|
||||
"--os-project-domain-id or via "
|
||||
"env[OS_PROJECT_DOMAIN_ID]")
|
||||
|
||||
if not endpoint:
|
||||
endpoint = _ksclient.monasca_url
|
||||
|
||||
client = monasca_client.Client(api_version, endpoint, **kwargs)
|
||||
session = _ksclient.session
|
||||
|
||||
if session:
|
||||
client = monasca_client.Client(api_version, session=session)
|
||||
else:
|
||||
client = monasca_client.Client(api_version, endpoint, **kwargs)
|
||||
|
||||
args.func(client, args)
|
||||
|
||||
|
|
|
@ -13,24 +13,34 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from keystoneclient.v3 import client as ksclient
|
||||
from keystoneauth1.identity import v3
|
||||
from keystoneauth1.loading import session
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
|
||||
def script_keystone_client(token=None):
|
||||
auth_params = {'auth_url': 'http://no.where',
|
||||
'project_id': 'project_id',
|
||||
'project_name': 'project_name',
|
||||
'project_domain_id': 'project_domain_id',
|
||||
'project_domain_name': 'project_domain_name'}
|
||||
|
||||
password_params = {'username': 'username',
|
||||
'password': 'password',
|
||||
'user_domain_id': 'user_domain_id',
|
||||
'user_domain_name': 'user_domain_name'}
|
||||
|
||||
if token:
|
||||
ksclient.Client(auth_url='http://no.where',
|
||||
insecure=False,
|
||||
tenant_id='tenant_id',
|
||||
token=token).AndReturn(FakeKeystone(token, None))
|
||||
auth_params['token'] = token
|
||||
auth = v3.Token(**auth_params).AndReturn(FakeKeystoneAuth(token, None))
|
||||
else:
|
||||
ksclient.Client(auth_url='http://no.where',
|
||||
insecure=False,
|
||||
password='password',
|
||||
project_name='project_name',
|
||||
timeout=20,
|
||||
username='username').AndReturn(FakeKeystone(
|
||||
'abcd1234', 'test'))
|
||||
auth_params.update(password_params)
|
||||
auth = v3.Password(**auth_params).AndReturn(
|
||||
FakeKeystoneAuth('abcd1234', 'test'))
|
||||
|
||||
session.Session().load_from_options(
|
||||
auth=auth, insecure=False, cacert=None, cert=None, key=None).AndReturn(
|
||||
FakeSession(auth))
|
||||
|
||||
|
||||
def fake_headers():
|
||||
|
@ -40,19 +50,34 @@ def fake_headers():
|
|||
'User-Agent': 'python-monascaclient'}
|
||||
|
||||
|
||||
class FakeServiceCatalog(object):
|
||||
class FakeSession():
|
||||
|
||||
def url_for(self, endpoint_type, service_type):
|
||||
def __init__(self, auth):
|
||||
self.auth = auth
|
||||
|
||||
def get_token(self):
|
||||
return self.auth.auth_token
|
||||
|
||||
def get_project_id(self):
|
||||
return self.auth.project_id
|
||||
|
||||
def get_endpoint(self, service_type, service_name, interface, region_name):
|
||||
return 'http://192.168.1.5:8004/v1/f14b41234'
|
||||
|
||||
|
||||
class FakeKeystone(object):
|
||||
service_catalog = FakeServiceCatalog()
|
||||
class FakeKeystoneAuth():
|
||||
|
||||
def __init__(self, auth_token, project_id):
|
||||
self.auth_token = auth_token
|
||||
self.project_id = project_id
|
||||
|
||||
def get_cache_id_elements(self):
|
||||
creds = {
|
||||
'password_username': 'username',
|
||||
'password_password': 'password'
|
||||
}
|
||||
return creds
|
||||
|
||||
|
||||
class FakeRaw(object):
|
||||
version = 110
|
||||
|
|
|
@ -17,7 +17,8 @@ import re
|
|||
import sys
|
||||
|
||||
import fixtures
|
||||
from keystoneclient.v3 import client as ksclient
|
||||
from keystoneauth1.identity import v3
|
||||
from keystoneauth1.loading import session
|
||||
from mox3 import mox
|
||||
import six
|
||||
import testtools
|
||||
|
@ -35,7 +36,7 @@ class TestCase(testtools.TestCase):
|
|||
'OS_USER_DOMAIN_NAME', 'OS_PROJECT_ID',
|
||||
'OS_PROJECT_NAME', 'OS_AUTH_URL', 'OS_REGION_NAME',
|
||||
'OS_AUTH_TOKEN', 'OS_NO_CLIENT_AUTH', 'OS_SERVICE_TYPE',
|
||||
'OS_DOMAIN_NAME', 'OS_DOMAIN_ID',
|
||||
'OS_PROJECT_DOMAIN_NAME', 'OS_PROJECT_DOMAIN_ID',
|
||||
'OS_ENDPOINT_TYPE', 'MONASCA_API_URL')
|
||||
|
||||
for key in client_env:
|
||||
|
@ -70,9 +71,11 @@ class ShellBase(TestCase):
|
|||
def setUp(self):
|
||||
super(ShellBase, self).setUp()
|
||||
self.m = mox.Mox()
|
||||
self.m.StubOutWithMock(ksclient, 'Client')
|
||||
self.m.StubOutWithMock(http.HTTPClient, 'json_request')
|
||||
self.m.StubOutWithMock(http.HTTPClient, 'raw_request')
|
||||
self.m.StubOutWithMock(v3, 'Password')
|
||||
self.m.StubOutWithMock(v3, 'Token')
|
||||
self.m.StubOutWithMock(session.Session, 'load_from_options')
|
||||
self.m.StubOutWithMock(http.SessionClient, 'json_request')
|
||||
self.m.StubOutWithMock(http.SessionClient, 'raw_request')
|
||||
self.addCleanup(self.m.VerifyAll)
|
||||
self.addCleanup(self.m.UnsetStubs)
|
||||
|
||||
|
@ -155,7 +158,12 @@ class ShellTestMonascaCommands(ShellBase):
|
|||
'OS_USERNAME': 'username',
|
||||
'OS_PASSWORD': 'password',
|
||||
'OS_PROJECT_NAME': 'project_name',
|
||||
'OS_PROJECT_ID': 'project_id',
|
||||
'OS_AUTH_URL': 'http://no.where',
|
||||
'OS_PROJECT_DOMAIN_ID': 'project_domain_id',
|
||||
'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
|
||||
'OS_USER_DOMAIN_ID': 'user_domain_id',
|
||||
'OS_USER_DOMAIN_NAME': 'user_domain_name',
|
||||
}
|
||||
self.set_fake_env(fake_env)
|
||||
|
||||
|
@ -180,7 +188,7 @@ class ShellTestMonascaCommands(ShellBase):
|
|||
'Created',
|
||||
{'location': 'http://no.where/v2.0/metrics'},
|
||||
None)
|
||||
http.HTTPClient.json_request(
|
||||
http.SessionClient.json_request(
|
||||
'POST',
|
||||
'/metrics',
|
||||
data={'timestamp': 1395691090,
|
||||
|
@ -235,7 +243,7 @@ class ShellTestMonascaCommands(ShellBase):
|
|||
'Created',
|
||||
{'location': 'http://no.where/v2.0/notification-methods'},
|
||||
None)
|
||||
http.HTTPClient.json_request(
|
||||
http.SessionClient.json_request(
|
||||
'POST',
|
||||
'/notification-methods',
|
||||
data={'name': 'email1',
|
||||
|
@ -261,7 +269,7 @@ class ShellTestMonascaCommands(ShellBase):
|
|||
'Created',
|
||||
{'location': 'http://no.where/v2.0/notification-methods'},
|
||||
None)
|
||||
http.HTTPClient.json_request(
|
||||
http.SessionClient.json_request(
|
||||
'POST',
|
||||
'/notification-methods',
|
||||
data={'name': 'mypost',
|
||||
|
@ -296,7 +304,7 @@ class ShellTestMonascaCommands(ShellBase):
|
|||
'Created',
|
||||
{'location': 'http://no.where/v2.0/notification-methods'},
|
||||
None)
|
||||
http.HTTPClient.json_request(
|
||||
http.SessionClient.json_request(
|
||||
'PUT',
|
||||
'/alarm-definitions/' + id,
|
||||
data={'name': name,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import string
|
||||
|
||||
from monascaclient.common import http
|
||||
from monascaclient import exc
|
||||
from monascaclient.v2_0 import alarm_definitions
|
||||
from monascaclient.v2_0 import alarms
|
||||
from monascaclient.v2_0 import metrics
|
||||
|
@ -25,6 +26,7 @@ class Client(object):
|
|||
|
||||
"""Client for the Monasca v2_0 API.
|
||||
|
||||
:param session: a keystoneauth session object
|
||||
:param string endpoint: A user-supplied endpoint URL for the monasca api
|
||||
service.
|
||||
:param string token: Token for authentication.
|
||||
|
@ -37,7 +39,21 @@ class Client(object):
|
|||
if 'auth_url' in kwargs and 'v2.0' in kwargs['auth_url']:
|
||||
kwargs['auth_url'] = string.replace(
|
||||
kwargs['auth_url'], 'v2.0', 'v3')
|
||||
self.http_client = http.HTTPClient(*args, **kwargs)
|
||||
|
||||
session = kwargs.get('session')
|
||||
|
||||
if session:
|
||||
self.http_client = http.SessionClient(
|
||||
session=session,
|
||||
service_type=kwargs.get('service_type', 'monitoring'),
|
||||
service_name=kwargs.get('service_name', 'monasca'),
|
||||
interface=kwargs.get('endpoint_type', 'public'),
|
||||
region_name=kwargs.get('region_name'),
|
||||
endpoint_override=kwargs.get('endpoint'))
|
||||
else:
|
||||
# For backward compatibility in case no session is passed
|
||||
self.http_client = http.HTTPClient(*args, **kwargs)
|
||||
|
||||
self.metrics = metrics.MetricsManager(self.http_client)
|
||||
self.notifications = notifications.NotificationsManager(
|
||||
self.http_client)
|
||||
|
@ -46,4 +62,8 @@ class Client(object):
|
|||
self.http_client)
|
||||
|
||||
def replace_token(self, token):
|
||||
self.http_client.replace_token(token)
|
||||
if isinstance(self.http_client, http.SessionClient):
|
||||
raise exc.CommandError(message='Token replacement is not '
|
||||
'supported for session client.')
|
||||
else:
|
||||
self.http_client.replace_token(token)
|
||||
|
|
|
@ -10,7 +10,7 @@ oslo.serialization>=1.10.0 # Apache-2.0
|
|||
oslo.service>=1.0.0 # Apache-2.0
|
||||
oslo.utils>=3.5.0 # Apache-2.0
|
||||
|
||||
python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0
|
||||
keystoneauth1>=2.1.0 # Apache-2.0
|
||||
|
||||
Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # BSD
|
||||
iso8601>=0.1.11 # MIT
|
||||
|
|
Loading…
Reference in New Issue