summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorekudryashova <ekudryashova@mirantis.com>2014-01-23 19:28:09 +0200
committerEugeniya Kudryashova <ekudryashova@mirantis.com>2014-07-31 18:59:58 +0300
commit47934c777c50897b649793e0960eebdaad322c45 (patch)
treed265370067aa46be001d1656936c916bc418a50a
parent092eb6643161747186ba4d0947a847af45e3d546 (diff)
downloadpython-ceilometerclient-47934c777c50897b649793e0960eebdaad322c45.tar.gz
Use HTTPClient from common Oslo code
In the process of unification of the clients code we should reuse common functionality from Oslo. bp common-client-library-2 Change-Id: I0e027c33ee42b6de032d33269caeea33e7837f40
-rw-r--r--ceilometerclient/client.py158
-rw-r--r--ceilometerclient/common/base.py8
-rw-r--r--ceilometerclient/common/http.py313
-rw-r--r--ceilometerclient/shell.py178
-rw-r--r--ceilometerclient/tests/test_client.py63
-rw-r--r--ceilometerclient/tests/test_http.py70
-rw-r--r--ceilometerclient/tests/test_shell.py12
-rw-r--r--ceilometerclient/tests/utils.py43
-rw-r--r--ceilometerclient/tests/v1/test_meters.py26
-rw-r--r--ceilometerclient/tests/v1/test_projects.py14
-rw-r--r--ceilometerclient/tests/v1/test_resources.py27
-rw-r--r--ceilometerclient/tests/v1/test_samples.py35
-rw-r--r--ceilometerclient/tests/v1/test_users.py14
-rw-r--r--ceilometerclient/tests/v2/test_alarms.py167
-rw-r--r--ceilometerclient/tests/v2/test_event_types.py10
-rw-r--r--ceilometerclient/tests/v2/test_events.py41
-rw-r--r--ceilometerclient/tests/v2/test_options.py1
-rw-r--r--ceilometerclient/tests/v2/test_query_alarm_history.py11
-rw-r--r--ceilometerclient/tests/v2/test_query_alarms.py10
-rw-r--r--ceilometerclient/tests/v2/test_query_samples.py10
-rw-r--r--ceilometerclient/tests/v2/test_resources.py27
-rw-r--r--ceilometerclient/tests/v2/test_samples.py21
-rw-r--r--ceilometerclient/tests/v2/test_statistics.py38
-rw-r--r--ceilometerclient/tests/v2/test_trait_descriptions.py10
-rw-r--r--ceilometerclient/tests/v2/test_traits.py10
-rw-r--r--ceilometerclient/v1/client.py23
-rw-r--r--ceilometerclient/v2/alarms.py11
-rw-r--r--ceilometerclient/v2/client.py24
-rw-r--r--ceilometerclient/v2/query.py6
-rw-r--r--ceilometerclient/v2/samples.py4
-rw-r--r--requirements.txt1
31 files changed, 498 insertions, 888 deletions
diff --git a/ceilometerclient/client.py b/ceilometerclient/client.py
index b66e547..283e24e 100644
--- a/ceilometerclient/client.py
+++ b/ceilometerclient/client.py
@@ -14,10 +14,11 @@ from keystoneclient.auth.identity import v2 as v2_auth
from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import discover
from keystoneclient import session
-import six
from ceilometerclient.common import utils
from ceilometerclient import exc
+from ceilometerclient.openstack.common.apiclient import auth
+from ceilometerclient.openstack.common.apiclient import exceptions
def _get_keystone_session(**kwargs):
@@ -139,12 +140,94 @@ def _get_endpoint(ks_session, **kwargs):
return endpoint
-def get_client(api_version, **kwargs):
+class AuthPlugin(auth.BaseAuthPlugin):
+ opt_names = ['tenant_id', 'region_name', 'auth_token',
+ 'service_type', 'endpoint_type', 'cacert',
+ 'auth_url', 'insecure', 'cert_file', 'key_file',
+ 'cert', 'key', 'tenant_name', 'project_name',
+ 'project_id', 'user_domain_id', 'user_domain_name',
+ 'password', 'username']
+
+ def __init__(self, auth_system=None, **kwargs):
+ self.opt_names.extend(self.common_opt_names)
+ super(AuthPlugin, self).__init__(auth_system, **kwargs)
+
+ def _do_authenticate(self, http_client):
+ if self.opts.get('token') and self.opts.get('endpoint'):
+ token = self.opts.get('token')
+ endpoint = self.opts.get('endpoint')
+ else:
+ project_id = self.opts.get('project_id') \
+ or self.opts.get('tenant_id')
+ project_name = (self.opts.get('project_name') or
+ self.opts.get('tenant_name'))
+ ks_kwargs = {
+ 'username': self.opts.get('username'),
+ 'password': self.opts.get('password'),
+ 'user_id': self.opts.get('user_id'),
+ 'user_domain_id': self.opts.get('user_domain_id'),
+ 'user_domain_name': self.opts.get('user_domain_name'),
+ 'project_id': project_id,
+ 'project_name': project_name,
+ 'project_domain_name': self.opts.get('project_domain_name'),
+ 'project_domain_id': self.opts.get('project_domain_id'),
+ 'auth_url': self.opts.get('auth_url'),
+ 'cacert': self.opts.get('cacert'),
+ 'cert': self.opts.get('cert'),
+ 'key': self.opts.get('key'),
+ 'insecure': self.opts.get('insecure')
+ }
+
+ # retrieve session
+ ks_session = _get_keystone_session(**ks_kwargs)
+ token = lambda: ks_session.get_token()
+ endpoint = self.opts.get('endpoint') or \
+ _get_endpoint(ks_session, **ks_kwargs)
+ self.opts['token'] = token()
+ self.opts['endpoint'] = endpoint
+
+ def token_and_endpoint(self, endpoint_type, service_type):
+ token = self.opts.get('token')
+ if callable(token):
+ token = token()
+ return token, self.opts.get('endpoint')
+
+ def sufficient_options(self):
+ """Check if all required options are present.
+
+ :raises: AuthPluginOptionsMissing
+ """
+ missing = not ((self.opts.get('token') and
+ self.opts.get('endpoint')) or
+ (self.opts.get('username')
+ and self.opts.get('password')
+ and self.opts.get('auth_url') and
+ (self.opts.get('tenant_id')
+ or self.opts.get('tenant_name'))))
+
+ if missing:
+ missing_opts = []
+ opts = ['token', 'endpoint', 'username', 'password', 'auth_url',
+ 'tenant_id', 'tenant_name']
+ for opt in opts:
+ if not self.opts.get(opt):
+ missing_opts.append(opt)
+ raise exceptions.AuthPluginOptionsMissing(missing_opts)
+
+
+def Client(version, *args, **kwargs):
+ module = utils.import_versioned_module(version, 'client')
+ client_class = getattr(module, 'Client')
+ return client_class(*args, **kwargs)
+
+
+def get_client(version, **kwargs):
"""Get an authtenticated client, based on the credentials
- in the keyword args.
+ in the keyword args.
:param api_version: the API version to use ('1' or '2')
:param kwargs: keyword args containing credentials, either:
+
* os_auth_token: pre-existing token to re-use
* ceilometer_url: ceilometer API endpoint
or:
@@ -164,53 +247,38 @@ def get_client(api_version, **kwargs):
* os_key: SSL private key
* insecure: allow insecure SSL (no cert verification)
"""
- token = kwargs.get('os_auth_token')
- if token and not six.callable(token):
- token = lambda: kwargs.get('os_auth_token')
-
- if token and kwargs.get('ceilometer_url'):
- endpoint = kwargs.get('ceilometer_url')
- else:
- project_id = kwargs.get('os_project_id') or kwargs.get('os_tenant_id')
- project_name = (kwargs.get('os_project_name') or
- kwargs.get('os_tenant_name'))
- ks_kwargs = {
- 'username': kwargs.get('os_username'),
- 'password': kwargs.get('os_password'),
- 'user_id': kwargs.get('os_user_id'),
- 'user_domain_id': kwargs.get('os_user_domain_id'),
- 'user_domain_name': kwargs.get('os_user_domain_name'),
- 'project_id': project_id,
- 'project_name': project_name,
- 'project_domain_name': kwargs.get('os_project_domain_name'),
- 'project_domain_id': kwargs.get('os_project_domain_id'),
- 'auth_url': kwargs.get('os_auth_url'),
- 'cacert': kwargs.get('os_cacert'),
- 'cert': kwargs.get('os_cert'),
- 'key': kwargs.get('os_key'),
- 'insecure': kwargs.get('insecure')
- }
-
- # retrieve session
- ks_session = _get_keystone_session(**ks_kwargs)
- token = token or (lambda: ks_session.get_token())
-
- endpoint = kwargs.get('ceilometer_url') or \
- _get_endpoint(ks_session, **ks_kwargs)
+ endpoint = kwargs.get('ceilometer_url')
cli_kwargs = {
- 'token': token,
- 'insecure': kwargs.get('insecure'),
- 'timeout': kwargs.get('timeout'),
+ 'username': kwargs.get('os_username'),
+ 'password': kwargs.get('os_password'),
+ 'tenant_id': kwargs.get('os_tenant_id'),
+ 'tenant_name': kwargs.get('os_tenant_name'),
+ 'auth_url': kwargs.get('os_auth_url'),
+ 'region_name': kwargs.get('os_region_name'),
+ 'service_type': kwargs.get('os_service_type'),
+ 'endpoint_type': kwargs.get('os_endpoint_type'),
'cacert': kwargs.get('os_cacert'),
'cert_file': kwargs.get('os_cert'),
- 'key_file': kwargs.get('os_key')
+ 'key_file': kwargs.get('os_key'),
+ 'token': kwargs.get('os_auth_token'),
}
- return Client(api_version, endpoint, **cli_kwargs)
+ cli_kwargs.update(kwargs)
+ return Client(version, endpoint, **cli_kwargs)
-def Client(version, *args, **kwargs):
- module = utils.import_versioned_module(version, 'client')
- client_class = getattr(module, 'Client')
- return client_class(*args, **kwargs)
+def get_auth_plugin(endpoint, **kwargs):
+ auth_plugin = AuthPlugin(
+ auth_url=kwargs.get('auth_url'),
+ service_type=kwargs.get('service_type'),
+ token=kwargs.get('token'),
+ endpoint_type=kwargs.get('endpoint_type'),
+ cacert=kwargs.get('ca_file'),
+ tenant_id=kwargs.get('project_id') or kwargs.get('tenant_id'),
+ endpoint=endpoint,
+ username=kwargs.get('username'),
+ password=kwargs.get('password'),
+ tenant_name=kwargs.get('tenant_name'),
+ )
+ return auth_plugin
diff --git a/ceilometerclient/common/base.py b/ceilometerclient/common/base.py
index a01adbf..7d4be24 100644
--- a/ceilometerclient/common/base.py
+++ b/ceilometerclient/common/base.py
@@ -49,13 +49,13 @@ class Manager(object):
self.api = api
def _create(self, url, body):
- resp, body = self.api.json_request('POST', url, body=body)
+ body = self.api.post(url, json=body).json()
if body:
return self.resource_class(self, body)
def _list(self, url, response_key=None, obj_class=None, body=None,
expect_single=False):
- resp, body = self.api.json_request('GET', url)
+ body = self.api.get(url).json()
if obj_class is None:
obj_class = self.resource_class
@@ -72,13 +72,13 @@ class Manager(object):
return [obj_class(self, res, loaded=True) for res in data if res]
def _update(self, url, body, response_key=None):
- resp, body = self.api.json_request('PUT', url, body=body)
+ body = self.api.put(url, json=body).json()
# PUT requests may not return a body
if body:
return self.resource_class(self, body)
def _delete(self, url):
- self.api.raw_request('DELETE', url)
+ self.api.delete(url)
class Resource(base.Resource):
diff --git a/ceilometerclient/common/http.py b/ceilometerclient/common/http.py
deleted file mode 100644
index 56373ee..0000000
--- a/ceilometerclient/common/http.py
+++ /dev/null
@@ -1,313 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import copy
-import hashlib
-import logging
-import os
-import socket
-
-try:
- import ssl
-except ImportError:
- # TODO(bcwaldon): Handle this failure more gracefully
- pass
-
-try:
- import json
-except ImportError:
- import simplejson as json
-
-import six
-from six.moves import http_client as httplib # noqa
-from six.moves import urllib
-
-from ceilometerclient import exc
-
-
-LOG = logging.getLogger(__name__)
-USER_AGENT = 'python-ceilometerclient'
-CHUNKSIZE = 1024 * 64 # 64kB
-SENSITIVE_HEADERS = ('X-Auth-Token',)
-
-
-class HTTPClient(object):
-
- def __init__(self, endpoint, **kwargs):
- self.endpoint = endpoint
- self.auth_token = kwargs.get('token')
- self.connection_params = self.get_connection_params(endpoint, **kwargs)
- self.proxy_url = self.get_proxy_url()
-
- @staticmethod
- def get_connection_params(endpoint, **kwargs):
- parts = urllib.parse.urlparse(endpoint)
-
- _args = (parts.hostname, parts.port, parts.path)
- _kwargs = {'timeout': (float(kwargs.get('timeout'))
- if kwargs.get('timeout') else 600)}
-
- if parts.scheme == 'https':
- _class = VerifiedHTTPSConnection
- _kwargs['cacert'] = kwargs.get('cacert', None)
- _kwargs['cert_file'] = kwargs.get('cert_file', None)
- _kwargs['key_file'] = kwargs.get('key_file', None)
- _kwargs['insecure'] = kwargs.get('insecure', False)
- elif parts.scheme == 'http':
- _class = httplib.HTTPConnection
- else:
- msg = 'Unsupported scheme: %s' % parts.scheme
- raise exc.InvalidEndpoint(msg)
-
- return (_class, _args, _kwargs)
-
- def get_connection(self):
- _class = self.connection_params[0]
- try:
- if self.proxy_url:
- proxy_parts = urllib.parse.urlparse(self.proxy_url)
- return _class(proxy_parts.hostname, proxy_parts.port,
- **self.connection_params[2])
- else:
- return _class(*self.connection_params[1][0:2],
- **self.connection_params[2])
- except httplib.InvalidURL:
- raise exc.InvalidEndpoint()
-
- def safe_header(self, name, value):
- if name in SENSITIVE_HEADERS:
- # because in python3 byte string handling is ... ug
- v = value.encode('utf-8')
- h = hashlib.sha1(v)
- d = h.hexdigest()
- return name, "{SHA1}%s" % d
- else:
- return name, value
-
- def log_curl_request(self, method, url, kwargs):
- curl = ['curl -i -X %s' % method]
-
- for (key, value) in kwargs['headers'].items():
- header = '-H \'%s: %s\'' % self.safe_header(key, value)
- curl.append(header)
-
- conn_params_fmt = [
- ('key_file', '--key %s'),
- ('cert_file', '--cert %s'),
- ('cacert', '--cacert %s'),
- ]
- for (key, fmt) in conn_params_fmt:
- value = self.connection_params[2].get(key)
- if value:
- curl.append(fmt % value)
-
- if self.connection_params[2].get('insecure'):
- curl.append('-k')
-
- if 'body' in kwargs:
- curl.append('-d \'%s\'' % kwargs['body'])
-
- curl.append('%s/%s' % (self.endpoint.rstrip('/'), url.lstrip('/')))
- LOG.debug(' '.join(curl))
-
- @staticmethod
- def log_http_response(resp, body=None):
- status = (resp.version / 10.0, resp.status, resp.reason)
- dump = ['\nHTTP/%.1f %s %s' % status]
- dump.extend(['%s: %s' % (k, v) for k, v in resp.getheaders()])
- dump.append('')
- if body:
- dump.extend([body, ''])
- LOG.debug('\n'.join(dump))
-
- def _make_connection_url(self, url):
- (_class, _args, _kwargs) = self.connection_params
- base_url = _args[2]
- return '%s/%s' % (base_url.rstrip('/'), url.lstrip('/'))
-
- def _http_request(self, url, method, **kwargs):
- """Send an http request with the specified characteristics.
-
- Wrapper around httplib.HTTP(S)Connection.request to handle tasks such
- as setting headers and error handling.
- """
- # Copy the kwargs so we can reuse the original in case of redirects
- kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
- kwargs['headers'].setdefault('User-Agent', USER_AGENT)
- auth_token = self.auth_token()
- if auth_token:
- kwargs['headers'].setdefault('X-Auth-Token', auth_token)
-
- self.log_curl_request(method, url, kwargs)
- conn = self.get_connection()
-
- try:
- if self.proxy_url:
- conn_url = (self.endpoint.rstrip('/') +
- self._make_connection_url(url))
- else:
- conn_url = self._make_connection_url(url)
- conn.request(method, conn_url, **kwargs)
- resp = conn.getresponse()
- except socket.gaierror as e:
- message = ("Error finding address for %(url)s: %(e)s"
- % dict(url=url, e=e))
- raise exc.InvalidEndpoint(message=message)
- except (socket.error, socket.timeout) as e:
- endpoint = self.endpoint
- message = ("Error communicating with %(endpoint)s %(e)s"
- % dict(endpoint=endpoint, e=e))
- raise exc.CommunicationError(message=message)
-
- body_iter = ResponseBodyIterator(resp)
-
- # Read body into string if it isn't obviously image data
- if resp.getheader('content-type', None) != 'application/octet-stream':
- body_str = ''.join([chunk for chunk in body_iter])
- self.log_http_response(resp, body_str)
- body_iter = six.StringIO(body_str)
- else:
- self.log_http_response(resp)
-
- if 400 <= resp.status < 600:
- LOG.warn("Request returned failure status.")
- raise exc.from_response(resp, ''.join(body_iter))
- elif resp.status in (301, 302, 305):
- # Redirected. Reissue the request to the new location.
- return self._http_request(resp['location'], method, **kwargs)
- elif resp.status == 300:
- raise exc.from_response(resp)
-
- return resp, body_iter
-
- def json_request(self, method, url, **kwargs):
- kwargs.setdefault('headers', {})
- kwargs['headers'].setdefault('Content-Type', 'application/json')
- kwargs['headers'].setdefault('Accept', 'application/json')
-
- if 'body' in kwargs:
- kwargs['body'] = json.dumps(kwargs['body'])
-
- resp, body_iter = self._http_request(url, method, **kwargs)
- content_type = resp.getheader('content-type', None)
-
- if resp.status == 204 or resp.status == 205 or content_type is None:
- return resp, list()
-
- if 'application/json' in content_type:
- body = ''.join([chunk for chunk in body_iter])
- try:
- body = json.loads(body)
- 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')
- return self._http_request(url, method, **kwargs)
-
- def get_proxy_url(self):
- scheme = urllib.parse.urlparse(self.endpoint).scheme
- if scheme == 'https':
- return os.environ.get('https_proxy')
- elif scheme == 'http':
- return os.environ.get('http_proxy')
- msg = 'Unsupported scheme: %s' % scheme
- raise exc.InvalidEndpoint(msg)
-
-
-class VerifiedHTTPSConnection(httplib.HTTPSConnection):
- """httplib-compatibile connection using client-side SSL authentication
-
- :see http://code.activestate.com/recipes/
- 577548-https-httplib-client-connection-with-certificate-v/
- """
-
- def __init__(self, host, port, key_file=None, cert_file=None,
- cacert=None, timeout=None, insecure=False):
- httplib.HTTPSConnection.__init__(self, host, port, key_file=key_file,
- cert_file=cert_file)
- self.key_file = key_file
- self.cert_file = cert_file
- if cacert is not None:
- self.cacert = cacert
- else:
- self.cacert = self.get_system_ca_file()
- self.timeout = timeout
- self.insecure = insecure
-
- def connect(self):
- """Connect to a host on a given (SSL) port.
- If cacert is pointing somewhere, use it to check Server Certificate.
-
- Redefined/copied and extended from httplib.py:1105 (Python 2.6.x).
- This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to
- ssl.wrap_socket(), which forces SSL to check server certificate against
- our client certificate.
- """
- sock = socket.create_connection((self.host, self.port), self.timeout)
-
- if self._tunnel_host:
- self.sock = sock
- self._tunnel()
-
- if self.insecure is True:
- kwargs = {'cert_reqs': ssl.CERT_NONE}
- else:
- kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.cacert}
-
- if self.cert_file:
- kwargs['certfile'] = self.cert_file
- if self.key_file:
- kwargs['keyfile'] = self.key_file
-
- self.sock = ssl.wrap_socket(sock, **kwargs)
-
- @staticmethod
- def get_system_ca_file():
- """Return path to system default CA file."""
- # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora,
- # Suse, FreeBSD/OpenBSD
- ca_path = ['/etc/ssl/certs/ca-certificates.crt',
- '/etc/pki/tls/certs/ca-bundle.crt',
- '/etc/ssl/ca-bundle.pem',
- '/etc/ssl/cert.pem']
- for ca in ca_path:
- if os.path.exists(ca):
- return ca
- return None
-
-
-class ResponseBodyIterator(object):
- """A class that acts as an iterator over an HTTP response."""
-
- def __init__(self, resp):
- self.resp = resp
-
- def __iter__(self):
- while True:
- yield self.next()
-
- def next(self):
- chunk = self.resp.read(CHUNKSIZE)
- if chunk:
- return chunk
- else:
- raise StopIteration()
diff --git a/ceilometerclient/shell.py b/ceilometerclient/shell.py
index 98f3851..138dd62 100644
--- a/ceilometerclient/shell.py
+++ b/ceilometerclient/shell.py
@@ -32,157 +32,6 @@ from ceilometerclient.openstack.common import strutils
class CeilometerShell(object):
- def _append_identity_args(self, parser):
- # FIXME(fabgia): identity related parameters should be passed by the
- # Keystone client itself to avoid constant update in all the services
- # clients. When this fix is merged this method can be made obsolete.
- # Bug: https://bugs.launchpad.net/python-keystoneclient/+bug/1332337
- parser.add_argument('-k', '--insecure',
- default=False,
- action='store_true',
- help="Explicitly allow ceilometerclient to "
- "perform \"insecure\" SSL (https) requests. "
- "The server's certificate will "
- "not be verified against any certificate "
- "authorities. This option should be used with "
- "caution.")
-
- # User related options
- parser.add_argument('--os-username',
- default=cliutils.env('OS_USERNAME'),
- help='Defaults to env[OS_USERNAME].')
-
- parser.add_argument('--os_username',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-user-id',
- default=cliutils.env('OS_USER_ID'),
- help='Defaults to env[OS_USER_ID].')
-
- parser.add_argument('--os-password',
- default=cliutils.env('OS_PASSWORD'),
- help='Defaults to env[OS_PASSWORD].')
-
- parser.add_argument('--os_password',
- help=argparse.SUPPRESS)
-
- # Domain related options
- parser.add_argument('--os-user-domain-id',
- default=cliutils.env('OS_USER_DOMAIN_ID'),
- help='Defaults to env[OS_USER_DOMAIN_ID].')
-
- parser.add_argument('--os-user-domain-name',
- default=cliutils.env('OS_USER_DOMAIN_NAME'),
- help='Defaults to env[OS_USER_DOMAIN_NAME].')
-
- parser.add_argument('--os-project-domain-id',
- default=cliutils.env('OS_PROJECT_DOMAIN_ID'),
- help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
-
- parser.add_argument('--os-project-domain-name',
- default=cliutils.env('OS_PROJECT_DOMAIN_NAME'),
- help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
-
- # Project V3 or Tenant V2 related options
- parser.add_argument('--os-project-id',
- default=cliutils.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-project-name',
- default=cliutils.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-id',
- default=cliutils.env('OS_TENANT_ID'),
- help='This option is mutually exclusive with '
- ' --os-project-id. '
- 'Defaults to env[OS_PROJECT_ID].')
-
- parser.add_argument('--os_tenant_id',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-tenant-name',
- default=cliutils.env('OS_TENANT_NAME'),
- help='Defaults to env[OS_TENANT_NAME].')
-
- parser.add_argument('--os_tenant_name',
- help=argparse.SUPPRESS)
-
- # Auth related options
- parser.add_argument('--os-auth-url',
- default=cliutils.env('OS_AUTH_URL'),
- help='Defaults to env[OS_AUTH_URL].')
-
- parser.add_argument('--os_auth_url',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-auth-token',
- default=cliutils.env('OS_AUTH_TOKEN'),
- help='Defaults to env[OS_AUTH_TOKEN].')
-
- parser.add_argument('--os_auth_token',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-cacert',
- metavar='<ca-certificate-file>',
- dest='os_cacert',
- default=cliutils.env('OS_CACERT'),
- help='Path of CA TLS certificate(s) used to verify'
- 'the remote server\'s certificate. Without this '
- 'option ceilometer looks for the default system '
- 'CA certificates.')
-
- parser.add_argument('--os-cert',
- help='Path of certificate file to use in SSL '
- 'connection. This file can optionally be '
- 'prepended with the private key.')
-
- parser.add_argument('--os-key',
- help='Path of client key to use in SSL '
- 'connection. This option is not necessary '
- 'if your key is prepended to your cert file.')
-
- # Service Catalog related options
- parser.add_argument('--os-service-type',
- default=cliutils.env('OS_SERVICE_TYPE'),
- help='Defaults to env[OS_SERVICE_TYPE].')
-
- parser.add_argument('--os_service_type',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-endpoint-type',
- default=cliutils.env('OS_ENDPOINT_TYPE'),
- help='Defaults to env[OS_ENDPOINT_TYPE].')
-
- parser.add_argument('--os_endpoint_type',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--os-region-name',
- default=cliutils.env('OS_REGION_NAME'),
- help='Defaults to env[OS_REGION_NAME].')
-
- parser.add_argument('--os_region_name',
- help=argparse.SUPPRESS)
-
- # Deprecated options
- parser.add_argument('--ca-file',
- dest='os_cacert',
- help='DEPRECATED! Use --os-cacert.')
-
- parser.add_argument('--cert-file',
- dest='os_cert',
- help='DEPRECATED! Use --os-cert.')
-
- parser.add_argument('--key-file',
- dest='os_key',
- help='DEPRECATED! Use --os-key.')
-
def get_base_parser(self):
parser = argparse.ArgumentParser(
prog='ceilometer',
@@ -233,9 +82,8 @@ class CeilometerShell(object):
parser.add_argument('--ceilometer_api_version',
help=argparse.SUPPRESS)
- # FIXME(fabgia): identity related parameters should be passed by the
- # Keystone client itself.
- self._append_identity_args(parser)
+ self.auth_plugin.add_opts(parser)
+ self.auth_plugin.add_common_opts(parser)
return parser
@@ -291,8 +139,10 @@ class CeilometerShell(object):
def parse_args(self, argv):
# Parse args once to find version
+ self.auth_plugin = ceiloclient.AuthPlugin(argv)
parser = self.get_base_parser()
(options, args) = parser.parse_known_args(argv)
+ self.auth_plugin.parse_opts(options)
self._setup_logging(options.debug)
# build available subcommands based on version
@@ -331,13 +181,13 @@ class CeilometerShell(object):
self.do_bash_completion(args)
return 0
- if not (args.os_auth_token and args.ceilometer_url):
- if not args.os_username:
+ if not (self.auth_plugin.opts['auth_token'] and args.ceilometer_url):
+ if not self.auth_plugin.opts['username']:
raise exc.CommandError("You must provide a username via "
"either --os-username or via "
"env[OS_USERNAME]")
- if not args.os_password:
+ if not self.auth_plugin.opts['password']:
raise exc.CommandError("You must provide a password via "
"either --os-password or via "
"env[OS_PASSWORD]")
@@ -354,13 +204,21 @@ class CeilometerShell(object):
"--os-user-domain-id or via "
"env[OS_USER_DOMAIN_ID]")
- if not args.os_auth_url:
+ if not (self.auth_plugin.opts['tenant_id']
+ or self.auth_plugin.opts['tenant_name']):
+ raise exc.CommandError("You must provide a tenant_id via "
+ "either --os-tenant-id or via "
+ "env[OS_TENANT_ID]")
+
+ if not self.auth_plugin.opts['auth_url']:
raise exc.CommandError("You must provide an auth url via "
"either --os-auth-url or via "
"env[OS_AUTH_URL]")
- client = ceiloclient.get_client(api_version, **(args.__dict__))
-
+ client_kwargs = vars(args)
+ client_kwargs.update(self.auth_plugin.opts)
+ client_kwargs['auth_plugin'] = self.auth_plugin
+ client = ceiloclient.Client(api_version, **client_kwargs)
# call whatever callback was selected
try:
args.func(client, args)
diff --git a/ceilometerclient/tests/test_client.py b/ceilometerclient/tests/test_client.py
index 14aaca6..faed8ee 100644
--- a/ceilometerclient/tests/test_client.py
+++ b/ceilometerclient/tests/test_client.py
@@ -12,46 +12,63 @@
import types
+import mock
+
from ceilometerclient import client
+from ceilometerclient.tests import fakes
from ceilometerclient.tests import utils
from ceilometerclient.v1 import client as v1client
from ceilometerclient.v2 import client as v2client
-FAKE_ENV = {'os_username': 'username',
- 'os_password': 'password',
- 'os_tenant_name': 'tenant_name',
- 'os_auth_url': 'http://no.where:5000/',
- 'os_auth_token': '1234',
- 'ceilometer_url': 'http://no.where'}
+FAKE_ENV = {'username': 'username',
+ 'password': 'password',
+ 'tenant_name': 'tenant_name',
+ 'auth_url': 'http://no.where',
+ 'ceilometer_url': 'http://no.where',
+ 'auth_plugin': 'fake_auth',
+ 'token': '1234'}
class ClientTest(utils.BaseTestCase):
- def create_client(self, api_version=2, exclude=[]):
- env = dict((k, v) for k, v in FAKE_ENV.items() if k not in exclude)
- return client.get_client(api_version, **env)
+ def create_client(self, env, api_version=2, endpoint=None, exclude=[]):
+ env = dict((k, v) for k, v in env.items()
+ if k not in exclude)
+
+ return client.Client(api_version, endpoint, **env)
def setUp(self):
super(ClientTest, self).setUp()
def test_client_version(self):
- c1 = self.create_client(api_version=1)
+ c1 = self.create_client(env=FAKE_ENV, api_version=1)
self.assertIsInstance(c1, v1client.Client)
- c2 = self.create_client(api_version=2)
+ c2 = self.create_client(env=FAKE_ENV, api_version=2)
self.assertIsInstance(c2, v2client.Client)
- def test_client_auth_token_lambda(self):
- FAKE_ENV['os_auth_token'] = lambda: '1234'
- self._test_client_auth_token()
-
- def test_client_auth_token_non_lambda(self):
- FAKE_ENV['os_auth_token'] = "1234"
- self._test_client_auth_token()
+ def test_client_auth_lambda(self):
+ env = FAKE_ENV.copy()
+ env['token'] = lambda: env['token']
+ self.assertIsInstance(env['token'],
+ types.FunctionType)
+ c2 = self.create_client(env)
+ self.assertIsInstance(c2, v2client.Client)
- def _test_client_auth_token(self):
- c2 = self.create_client()
+ def test_client_auth_non_lambda(self):
+ env = FAKE_ENV.copy()
+ env['token'] = "1234"
+ self.assertIsInstance(env['token'], str)
+ c2 = self.create_client(env)
self.assertIsInstance(c2, v2client.Client)
- self.assertIsInstance(c2.http_client.auth_token,
- types.FunctionType)
- self.assertEqual('1234', c2.http_client.auth_token())
+
+ @mock.patch('keystoneclient.v2_0.client', fakes.FakeKeystone)
+ def test_client_without_auth_plugin(self):
+ env = FAKE_ENV.copy()
+ del env['auth_plugin']
+ c = self.create_client(env, api_version=2, endpoint='fake_endpoint')
+ self.assertIsInstance(c.auth_plugin, client.AuthPlugin)
+
+ def test_client_with_auth_plugin(self):
+ c = self.create_client(FAKE_ENV, api_version=2)
+ self.assertIsInstance(c.auth_plugin, str)
diff --git a/ceilometerclient/tests/test_http.py b/ceilometerclient/tests/test_http.py
deleted file mode 100644
index c7a6404..0000000
--- a/ceilometerclient/tests/test_http.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import mock
-
-from ceilometerclient.common import http
-from ceilometerclient.tests import utils
-
-
-class HttpClientTest(utils.BaseTestCase):
- url = 'http://localhost'
-
- def test_url_generation_trailing_slash_in_base_prefix_in_path(self):
- client = http.HTTPClient("%s/" % self.url)
- url = client._make_connection_url('/v1/resources')
- self.assertEqual(url, '/v1/resources')
-
- def test_url_generation_no_trailing_slash_in_base_prefix_in_path(self):
- client = http.HTTPClient(self.url)
- url = client._make_connection_url('/v1/resources')
- self.assertEqual(url, '/v1/resources')
-
- def test_url_generation_trailing_slash_in_base_no_prefix_in_path(self):
- client = http.HTTPClient("%s/" % self.url)
- url = client._make_connection_url('v1/resources')
- self.assertEqual(url, '/v1/resources')
-
- def test_url_generation_no_trailing_slash_in_base_no_prefix_in_path(self):
- client = http.HTTPClient(self.url)
- url = client._make_connection_url('v1/resources')
- self.assertEqual(url, '/v1/resources')
-
- def test_get_connection(self):
- client = http.HTTPClient(self.url)
- self.assertIsNotNone(client.get_connection())
-
- @mock.patch.object(http.HTTPClient, 'get_connection')
- def test_url_generation_with_proxy(self, get_conn):
- client = http.HTTPClient(self.url, token=lambda: 'token')
- client.proxy_url = "http://localhost:3128/"
- conn = mock.MagicMock()
- conn.request.side_effect = Exception("stop")
- get_conn.return_value = conn
- try:
- client._http_request('/v1/resources', 'GET')
- except Exception:
- pass
- conn.request.assert_called_once_with('GET', (self.url.rstrip('/') +
- '/v1/resources'),
- headers=mock.ANY)
-
-
-class HttpsClientTest(HttpClientTest):
- url = 'https://localhost'
-
-
-class HttpEndingSlashClientTest(HttpClientTest):
- url = 'http://localhost/'
diff --git a/ceilometerclient/tests/test_shell.py b/ceilometerclient/tests/test_shell.py
index 5f0ffba..cadfcc8 100644
--- a/ceilometerclient/tests/test_shell.py
+++ b/ceilometerclient/tests/test_shell.py
@@ -48,10 +48,10 @@ class ShellTest(utils.BaseTestCase):
super(ShellTest, self).setUp()
@mock.patch('sys.stdout', new=six.StringIO())
- @mock.patch.object(ks_session, 'Session')
- @mock.patch.object(v1client.http.HTTPClient, 'json_request')
- @mock.patch.object(v1client.http.HTTPClient, 'raw_request')
- def shell(self, argstr, mock_ksclient, mock_json, mock_raw):
+ @mock.patch.object(ks_session, 'Session', mock.MagicMock())
+ @mock.patch.object(v1client.client.HTTPClient,
+ 'client_request', mock.MagicMock())
+ def shell(self, argstr):
try:
_shell = ceilometer_shell.CeilometerShell()
_shell.main(argstr.split())
@@ -103,7 +103,7 @@ class ShellKeystoneV2Test(ShellTest):
mock_ksclient.side_effect = exc.HTTPUnauthorized
self.make_env(FAKE_V2_ENV)
args = ['--debug', 'event-list']
- self.assertRaises(exc.HTTPUnauthorized, ceilometer_shell.main, args)
+ self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
@mock.patch.object(ks_session, 'Session')
def test_dash_d_switch_raises_error(self, mock_ksclient):
@@ -132,7 +132,7 @@ class ShellKeystoneV3Test(ShellTest):
mock_ksclient.side_effect = exc.HTTPUnauthorized
self.make_env(FAKE_V3_ENV)
args = ['--debug', 'event-list']
- self.assertRaises(exc.HTTPUnauthorized, ceilometer_shell.main, args)
+ self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
@mock.patch.object(ks_session, 'Session')
def test_dash_d_switch_raises_error(self, mock_ksclient):
diff --git a/ceilometerclient/tests/utils.py b/ceilometerclient/tests/utils.py
index a3e6a38..57bc276 100644
--- a/ceilometerclient/tests/utils.py
+++ b/ceilometerclient/tests/utils.py
@@ -13,55 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import copy
-
import fixtures
-import six
import testtools
-from ceilometerclient.common import http
-
class BaseTestCase(testtools.TestCase):
def setUp(self):
super(BaseTestCase, self).setUp()
self.useFixture(fixtures.FakeLogger())
-
-
-class FakeAPI(object):
- def __init__(self, fixtures):
- self.fixtures = fixtures
- self.calls = []
-
- def _request(self, method, url, headers=None, body=None):
- call = (method, url, headers or {}, body)
- self.calls.append(call)
- return self.fixtures[url][method]
-
- def raw_request(self, *args, **kwargs):
- fixture = self._request(*args, **kwargs)
- body_iter = http.ResponseBodyIterator(six.StringIO(fixture[1]))
- return FakeResponse(fixture[0]), body_iter
-
- def json_request(self, *args, **kwargs):
- fixture = self._request(*args, **kwargs)
- return FakeResponse(fixture[0]), fixture[1]
-
-
-class FakeResponse(object):
- def __init__(self, headers, body=None, version=None):
- """:param headers: dict representing HTTP response headers
- :param body: file-like object
- """
- self.headers = headers
- self.body = body
-
- def getheaders(self):
- return copy.deepcopy(self.headers).items()
-
- def getheader(self, key, default):
- return self.headers.get(key, default)
-
- def read(self, amt):
- return self.body.read(amt)
diff --git a/ceilometerclient/tests/v1/test_meters.py b/ceilometerclient/tests/v1/test_meters.py
index f97c18b..1c883b7 100644
--- a/ceilometerclient/tests/v1/test_meters.py
+++ b/ceilometerclient/tests/v1/test_meters.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v1.meters
@@ -109,15 +110,16 @@ class MeterManagerTest(utils.BaseTestCase):
def setUp(self):
super(MeterManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v1.meters.MeterManager(self.api)
def test_list_all(self):
resources = list(self.mgr.list())
expect = [
- ('GET', '/v1/meters', {}, None),
+ 'GET', '/v1/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 2)
self.assertEqual(resources[0].resource_id, 'a')
self.assertEqual(resources[1].resource_id, 'b')
@@ -125,9 +127,9 @@ class MeterManagerTest(utils.BaseTestCase):
def test_list_by_source(self):
resources = list(self.mgr.list(source='openstack'))
expect = [
- ('GET', '/v1/sources/openstack/meters', {}, None),
+ 'GET', '/v1/sources/openstack/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 2)
self.assertEqual(resources[0].resource_id, 'b')
self.assertEqual(resources[1].resource_id, 'q')
@@ -135,26 +137,26 @@ class MeterManagerTest(utils.BaseTestCase):
def test_list_by_user(self):
resources = list(self.mgr.list(user_id='joey'))
expect = [
- ('GET', '/v1/users/joey/meters', {}, None),
+ 'GET', '/v1/users/joey/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
def test_list_by_project(self):
resources = list(self.mgr.list(project_id='dig_the_ditch'))
expect = [
- ('GET', '/v1/projects/dig_the_ditch/meters', {}, None),
+ 'GET', '/v1/projects/dig_the_ditch/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
def test_list_by_metaquery(self):
resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo'))
expect = [
- ('GET', '/v1/meters?metadata.zxc_id=foo', {}, None),
+ 'GET', '/v1/meters?metadata.zxc_id=foo'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
diff --git a/ceilometerclient/tests/v1/test_projects.py b/ceilometerclient/tests/v1/test_projects.py
index a1faaf0..2f34a5c 100644
--- a/ceilometerclient/tests/v1/test_projects.py
+++ b/ceilometerclient/tests/v1/test_projects.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v1.meters
@@ -40,15 +41,16 @@ class ProjectManagerTest(utils.BaseTestCase):
def setUp(self):
super(ProjectManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v1.meters.ProjectManager(self.api)
def test_list_all(self):
projects = list(self.mgr.list())
expect = [
- ('GET', '/v1/projects', {}, None),
+ 'GET', '/v1/projects'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(projects), 2)
self.assertEqual(projects[0].project_id, 'a')
self.assertEqual(projects[1].project_id, 'b')
@@ -56,8 +58,8 @@ class ProjectManagerTest(utils.BaseTestCase):
def test_list_by_source(self):
projects = list(self.mgr.list(source='source_b'))
expect = [
- ('GET', '/v1/sources/source_b/projects', {}, None),
+ 'GET', '/v1/sources/source_b/projects'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(projects), 1)
self.assertEqual(projects[0].project_id, 'b')
diff --git a/ceilometerclient/tests/v1/test_resources.py b/ceilometerclient/tests/v1/test_resources.py
index 00cea8c..4eac3fe 100644
--- a/ceilometerclient/tests/v1/test_resources.py
+++ b/ceilometerclient/tests/v1/test_resources.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v1.meters
@@ -108,15 +109,16 @@ class ResourceManagerTest(utils.BaseTestCase):
def setUp(self):
super(ResourceManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v1.meters.ResourceManager(self.api)
def test_list_all(self):
resources = list(self.mgr.list())
expect = [
- ('GET', '/v1/resources', {}, None),
+ 'GET', '/v1/resources'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 2)
self.assertEqual(resources[0].resource_id, 'a')
self.assertEqual(resources[1].resource_id, 'b')
@@ -124,27 +126,27 @@ class ResourceManagerTest(utils.BaseTestCase):
def test_list_by_user(self):
resources = list(self.mgr.list(user_id='joey'))
expect = [
- ('GET', '/v1/users/joey/resources', {}, None),
+ 'GET', '/v1/users/joey/resources'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
def test_list_by_metaquery(self):
resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo'))
expect = [
- ('GET', '/v1/resources?metadata.zxc_id=foo', {}, None),
+ 'GET', '/v1/resources?metadata.zxc_id=foo'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
def test_list_by_project(self):
resources = list(self.mgr.list(project_id='project_bla'))
expect = [
- ('GET', '/v1/projects/project_bla/resources', {}, None),
+ 'GET', '/v1/projects/project_bla/resources'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'a')
@@ -152,9 +154,8 @@ class ResourceManagerTest(utils.BaseTestCase):
resources = list(self.mgr.list(start_timestamp='now',
end_timestamp='now'))
expect = [
- ('GET', '/v1/resources?start_timestamp=now&end_timestamp=now',
- {}, None),
+ 'GET', '/v1/resources?start_timestamp=now&end_timestamp=now'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'b')
diff --git a/ceilometerclient/tests/v1/test_samples.py b/ceilometerclient/tests/v1/test_samples.py
index 9e59b46..61f064e 100644
--- a/ceilometerclient/tests/v1/test_samples.py
+++ b/ceilometerclient/tests/v1/test_samples.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v1.meters
@@ -122,24 +123,25 @@ class SampleManagerTest(utils.BaseTestCase):
def setUp(self):
super(SampleManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v1.meters.SampleManager(self.api)
def test_list_all(self):
samples = list(self.mgr.list(counter_name=None))
expect = [
- ('GET', '/v1/meters', {}, None),
+ 'GET', '/v1/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 0)
def test_list_by_source(self):
samples = list(self.mgr.list(source='openstack',
counter_name='this'))
expect = [
- ('GET', '/v1/sources/openstack/meters/this', {}, None),
+ 'GET', '/v1/sources/openstack/meters/this'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].resource_id, 'b')
@@ -147,9 +149,9 @@ class SampleManagerTest(utils.BaseTestCase):
samples = list(self.mgr.list(user_id='freddy',
counter_name='balls'))
expect = [
- ('GET', '/v1/users/freddy/meters/balls', {}, None),
+ 'GET', '/v1/users/freddy/meters/balls'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].project_id, 'melbourne_open')
self.assertEqual(samples[0].user_id, 'freddy')
@@ -159,9 +161,9 @@ class SampleManagerTest(utils.BaseTestCase):
samples = list(self.mgr.list(project_id='dig_the_ditch',
counter_name='meters'))
expect = [
- ('GET', '/v1/projects/dig_the_ditch/meters/meters', {}, None),
+ 'GET', '/v1/projects/dig_the_ditch/meters/meters'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].project_id, 'dig_the_ditch')
self.assertEqual(samples[0].volume, 345)
@@ -171,9 +173,9 @@ class SampleManagerTest(utils.BaseTestCase):
samples = list(self.mgr.list(metaquery='metadata.zxc_id=foo',
counter_name='this'))
expect = [
- ('GET', '/v1/meters?metadata.zxc_id=foo', {}, None),
+ 'GET', '/v1/meters?metadata.zxc_id=foo'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].resource_metadata['zxc_id'], 'foo')
@@ -183,12 +185,11 @@ class SampleManagerTest(utils.BaseTestCase):
start_timestamp='now',
end_timestamp='now'))
expect = [
- ('GET',
- '/v1/users/freddy/meters/balls?' +
- 'start_timestamp=now&end_timestamp=now',
- {}, None),
+ 'GET',
+ '/v1/users/freddy/meters/balls?' +
+ 'start_timestamp=now&end_timestamp=now'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].project_id, 'melbourne_open')
self.assertEqual(samples[0].user_id, 'freddy')
diff --git a/ceilometerclient/tests/v1/test_users.py b/ceilometerclient/tests/v1/test_users.py
index df208c5..541139b 100644
--- a/ceilometerclient/tests/v1/test_users.py
+++ b/ceilometerclient/tests/v1/test_users.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v1.meters
@@ -40,15 +41,16 @@ class UserManagerTest(utils.BaseTestCase):
def setUp(self):
super(UserManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v1.meters.UserManager(self.api)
def test_list_all(self):
users = list(self.mgr.list())
expect = [
- ('GET', '/v1/users', {}, None),
+ 'GET', '/v1/users'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(users), 2)
self.assertEqual(users[0].user_id, 'a')
self.assertEqual(users[1].user_id, 'b')
@@ -56,8 +58,8 @@ class UserManagerTest(utils.BaseTestCase):
def test_list_by_source(self):
users = list(self.mgr.list(source='source_b'))
expect = [
- ('GET', '/v1/sources/source_b/users', {}, None),
+ 'GET', '/v1/sources/source_b/users'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(users), 1)
self.assertEqual(users[0].user_id, 'b')
diff --git a/ceilometerclient/tests/v2/test_alarms.py b/ceilometerclient/tests/v2/test_alarms.py
index a0e13ac..f963bce 100644
--- a/ceilometerclient/tests/v2/test_alarms.py
+++ b/ceilometerclient/tests/v2/test_alarms.py
@@ -21,7 +21,8 @@ import six
from six.moves import xrange # noqa
import testtools
-from ceilometerclient.tests import utils
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.v2 import alarms
AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
@@ -210,11 +211,11 @@ fixtures = {
{
'PUT': (
{},
- 'alarm'
+ {'alarm': 'alarm'}
),
'GET': (
{},
- 'alarm'
+ {'alarm': 'alarm'}
),
},
@@ -254,15 +255,16 @@ class AlarmManagerTest(testtools.TestCase):
def setUp(self):
super(AlarmManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = alarms.AlarmManager(self.api)
def test_list_all(self):
alarms = list(self.mgr.list())
expect = [
- ('GET', '/v2/alarms', {}, None),
+ 'GET', '/v2/alarms'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(alarms), 1)
self.assertEqual(alarms[0].alarm_id, 'alarm-id')
@@ -272,21 +274,20 @@ class AlarmManagerTest(testtools.TestCase):
{"field": "name",
"value": "SwiftObjectAlarm"}]))
expect = [
- ('GET',
- '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op='
- '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm',
- {}, None),
+ 'GET',
+ '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op='
+ '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm',
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(alarms), 1)
self.assertEqual(alarms[0].alarm_id, 'alarm-id')
def test_get(self):
alarm = self.mgr.get(alarm_id='alarm-id')
expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
+ 'GET', '/v2/alarms/alarm-id'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertTrue(alarm)
self.assertEqual(alarm.alarm_id, 'alarm-id')
self.assertEqual(alarm.rule, alarm.threshold_rule)
@@ -294,18 +295,21 @@ class AlarmManagerTest(testtools.TestCase):
def test_create(self):
alarm = self.mgr.create(**CREATE_ALARM)
expect = [
- ('POST', '/v2/alarms', {}, CREATE_ALARM),
+ 'POST', '/v2/alarms'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect, body=CREATE_ALARM)
self.assertTrue(alarm)
def test_update(self):
alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_ALARM)
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('PUT', '/v2/alarms/alarm-id', {}, UPDATED_ALARM),
+ expect_get = [
+ 'GET', '/v2/alarms/alarm-id'
+ ]
+ expect_put = [
+ 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect_get, pos=0)
+ self.http_client.assert_called(*expect_put, pos=1)
self.assertTrue(alarm)
self.assertEqual(alarm.alarm_id, 'alarm-id')
for (key, value) in six.iteritems(UPDATED_ALARM):
@@ -313,11 +317,14 @@ class AlarmManagerTest(testtools.TestCase):
def test_update_delta(self):
alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_ALARM)
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('PUT', '/v2/alarms/alarm-id', {}, UPDATED_ALARM),
+ expect_get = [
+ 'GET', '/v2/alarms/alarm-id'
]
- self.assertEqual(self.api.calls, expect)
+ expect_put = [
+ 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
+ ]
+ self.http_client.assert_called(*expect_get, pos=0)
+ self.http_client.assert_called(*expect_put, pos=1)
self.assertTrue(alarm)
self.assertEqual(alarm.alarm_id, 'alarm-id')
for (key, value) in six.iteritems(UPDATED_ALARM):
@@ -326,25 +333,25 @@ class AlarmManagerTest(testtools.TestCase):
def test_set_state(self):
state = self.mgr.set_state(alarm_id='alarm-id', state='alarm')
expect = [
- ('PUT', '/v2/alarms/alarm-id/state', {}, 'alarm'),
+ 'PUT', '/v2/alarms/alarm-id/state'
]
- self.assertEqual(self.api.calls, expect)
- self.assertEqual(state, 'alarm')
+ self.http_client.assert_called(*expect, body='alarm')
+ self.assertEqual(state, {'alarm': 'alarm'})
def test_get_state(self):
state = self.mgr.get_state(alarm_id='alarm-id')
expect = [
- ('GET', '/v2/alarms/alarm-id/state', {}, None),
+ 'GET', '/v2/alarms/alarm-id/state'
]
- self.assertEqual(self.api.calls, expect)
- self.assertEqual(state, 'alarm')
+ self.http_client.assert_called(*expect)
+ self.assertEqual(state, {'alarm': 'alarm'})
def test_delete(self):
deleted = self.mgr.delete(alarm_id='victim-id')
expect = [
- ('DELETE', '/v2/alarms/victim-id', {}, None),
+ 'DELETE', '/v2/alarms/victim-id'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertIsNone(deleted)
def test_get_from_alarm_class(self):
@@ -352,10 +359,10 @@ class AlarmManagerTest(testtools.TestCase):
self.assertTrue(alarm)
alarm.get()
expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('GET', '/v2/alarms/alarm-id', {}, None)
+ 'GET', '/v2/alarms/alarm-id'
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect, pos=0)
+ self.http_client.assert_called(*expect, pos=1)
self.assertEqual('alarm-id', alarm.alarm_id)
self.assertEqual(alarm.threshold_rule, alarm.rule)
@@ -363,28 +370,34 @@ class AlarmManagerTest(testtools.TestCase):
alarm = self.mgr.get(alarm_id='alarm-id')
self.assertTrue(alarm)
state = alarm.get_state()
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('GET', '/v2/alarms/alarm-id/state', {}, None)
+ expect_get_1 = [
+ 'GET', '/v2/alarms/alarm-id'
]
- self.assertEqual(expect, self.api.calls)
+ expect_get_2 = [
+ 'GET', '/v2/alarms/alarm-id/state'
+ ]
+ self.http_client.assert_called(*expect_get_1, pos=0)
+ self.http_client.assert_called(*expect_get_2, pos=1)
self.assertEqual('alarm', state)
def test_delete_from_alarm_class(self):
alarm = self.mgr.get(alarm_id='alarm-id')
self.assertTrue(alarm)
deleted = alarm.delete()
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('DELETE', '/v2/alarms/alarm-id', {}, None)
+ expect_get = [
+ 'GET', '/v2/alarms/alarm-id'
]
- self.assertEqual(expect, self.api.calls)
+ expect_delete = [
+ 'DELETE', '/v2/alarms/alarm-id'
+ ]
+ self.http_client.assert_called(*expect_get, pos=0)
+ self.http_client.assert_called(*expect_delete, pos=1)
self.assertIsNone(deleted)
def _do_test_get_history(self, q, url):
history = self.mgr.get_history(q=q, alarm_id='alarm-id')
- expect = [('GET', url, {}, None)]
- self.assertEqual(self.api.calls, expect)
+ expect = ['GET', url]
+ self.http_client.assert_called(*expect)
for i in xrange(len(history)):
change = history[i]
self.assertIsInstance(change, alarms.AlarmChange)
@@ -406,15 +419,17 @@ class AlarmLegacyManagerTest(testtools.TestCase):
def setUp(self):
super(AlarmLegacyManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = alarms.AlarmManager(self.api)
def test_create(self):
alarm = self.mgr.create(**CREATE_LEGACY_ALARM)
expect = [
- ('POST', '/v2/alarms', {}, CREATE_ALARM_WITHOUT_TC),
+ 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC,
]
- self.assertEqual(self.api.calls, expect)
+
+ self.http_client.assert_called(*expect)
self.assertTrue(alarm)
def test_create_counter_name(self):
@@ -424,18 +439,17 @@ class AlarmLegacyManagerTest(testtools.TestCase):
del create['meter_name']
alarm = self.mgr.create(**create)
expect = [
- ('POST', '/v2/alarms', {}, CREATE_ALARM_WITHOUT_TC),
+ 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC,
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertTrue(alarm)
def test_update(self):
alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_LEGACY_ALARM)
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('PUT', '/v2/alarms/alarm-id', {}, UPDATED_ALARM),
+ expect_put = [
+ 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect_put)
self.assertTrue(alarm)
self.assertEqual(alarm.alarm_id, 'alarm-id')
for (key, value) in six.iteritems(UPDATED_ALARM):
@@ -447,11 +461,10 @@ class AlarmLegacyManagerTest(testtools.TestCase):
updated['counter_name'] = UPDATED_LEGACY_ALARM['meter_name']
del updated['meter_name']
alarm = self.mgr.update(alarm_id='alarm-id', **updated)
- expect = [
- ('GET', '/v2/alarms/alarm-id', {}, None),
- ('PUT', '/v2/alarms/alarm-id', {}, UPDATED_ALARM),
+ expect_put = [
+ 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect_put)
self.assertTrue(alarm)
self.assertEqual(alarm.alarm_id, 'alarm-id')
for (key, value) in six.iteritems(UPDATED_ALARM):
@@ -462,7 +475,8 @@ class AlarmTimeConstraintTest(testtools.TestCase):
def setUp(self):
super(AlarmTimeConstraintTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = alarms.AlarmManager(self.api)
def test_add_new(self):
@@ -471,26 +485,37 @@ class AlarmTimeConstraintTest(testtools.TestCase):
duration=500)
kwargs = dict(time_constraints=[new_constraint])
self.mgr.update(alarm_id='alarm-id', **kwargs)
- actual = self.api.calls[1][3]['time_constraints']
- expected = AN_ALARM[u'time_constraints'] + [new_constraint]
- self.assertEqual(expected, actual)
+ body = copy.deepcopy(AN_ALARM)
+ body[u'time_constraints'] = \
+ AN_ALARM[u'time_constraints'] + [new_constraint]
+ expect = [
+ 'PUT', '/v2/alarms/alarm-id', body
+ ]
+ self.http_client.assert_called(*expect)
def test_update_existing(self):
updated_constraint = dict(name='cons2',
duration=500)
kwargs = dict(time_constraints=[updated_constraint])
self.mgr.update(alarm_id='alarm-id', **kwargs)
- actual = self.api.calls[1][3]['time_constraints']
- expected = [AN_ALARM[u'time_constraints'][0], dict(name='cons2',
- description='desc2',
- start='0 23 * * *',
- duration=500,
- timezone='')]
- self.assertEqual(expected, actual)
+ body = copy.deepcopy(AN_ALARM)
+ body[u'time_constraints'][1] = dict(name='cons2',
+ description='desc2',
+ start='0 23 * * *',
+ duration=500,
+ timezone='')
+
+ expect = [
+ 'PUT', '/v2/alarms/alarm-id', body
+ ]
+ self.http_client.assert_called(*expect)
def test_remove(self):
kwargs = dict(remove_time_constraints=['cons2'])
self.mgr.update(alarm_id='alarm-id', **kwargs)
- actual = self.api.calls[1][3]['time_constraints']
- expected = [AN_ALARM[u'time_constraints'][0]]
- self.assertEqual(expected, actual)
+ body = copy.deepcopy(AN_ALARM)
+ body[u'time_constraints'] = AN_ALARM[u'time_constraints'][:1]
+ expect = [
+ 'PUT', '/v2/alarms/alarm-id', body
+ ]
+ self.http_client.assert_called(*expect)
diff --git a/ceilometerclient/tests/v2/test_event_types.py b/ceilometerclient/tests/v2/test_event_types.py
index 08a25a4..8d5e4a0 100644
--- a/ceilometerclient/tests/v2/test_event_types.py
+++ b/ceilometerclient/tests/v2/test_event_types.py
@@ -12,6 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.event_types
@@ -30,15 +33,16 @@ class EventTypesManagerTest(utils.BaseTestCase):
def setUp(self):
super(EventTypesManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.event_types.EventTypeManager(self.api)
def test_list(self):
event_types = list(self.mgr.list())
expect = [
- ('GET', '/v2/event_types/', {}, None),
+ 'GET', '/v2/event_types/'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(event_types), 4)
self.assertEqual(event_types[0].event_type, "Foo")
self.assertEqual(event_types[1].event_type, "Bar")
diff --git a/ceilometerclient/tests/v2/test_events.py b/ceilometerclient/tests/v2/test_events.py
index 4935d8b..acf27d4 100644
--- a/ceilometerclient/tests/v2/test_events.py
+++ b/ceilometerclient/tests/v2/test_events.py
@@ -11,7 +11,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.events
@@ -124,15 +125,16 @@ class EventManagerTest(utils.BaseTestCase):
def setUp(self):
super(EventManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.events.EventManager(self.api)
def test_list_all(self):
events = list(self.mgr.list())
expect = [
- ('GET', '/v2/events', {}, None),
+ 'GET', '/v2/events'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(events), 3)
self.assertEqual(events[0].event_type, 'Foo')
self.assertEqual(events[1].event_type, 'Foo')
@@ -141,9 +143,9 @@ class EventManagerTest(utils.BaseTestCase):
def test_list_one(self):
event = self.mgr.get(2)
expect = [
- ('GET', '/v2/events/2', {}, None),
+ 'GET', '/v2/events/2'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertTrue(event)
self.assertEqual(event.event_type, 'Foo')
@@ -152,11 +154,10 @@ class EventManagerTest(utils.BaseTestCase):
"value": "localhost",
"type": "string"}]))
expect = [
- ('GET', '/v2/events?q.field=hostname&q.op=&q.type=string'
- '&q.value=localhost',
- {}, None),
+ 'GET', '/v2/events?q.field=hostname&q.op=&q.type=string'
+ '&q.value=localhost'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(events), 2)
self.assertEqual(events[0].event_type, 'Foo')
@@ -164,11 +165,10 @@ class EventManagerTest(utils.BaseTestCase):
events = list(self.mgr.list(q=[{"field": "hostname",
"value": "foreignhost"}]))
expect = [
- ('GET', '/v2/events?q.field=hostname&q.op='
- '&q.type=&q.value=foreignhost',
- {}, None),
+ 'GET', '/v2/events?q.field=hostname&q.op='
+ '&q.type=&q.value=foreignhost'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(events), 2)
self.assertEqual(events[0].event_type, 'Foo')
@@ -180,11 +180,10 @@ class EventManagerTest(utils.BaseTestCase):
"type": "integer"}]))
expect = [
- ('GET', '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op='
- '&q.type=&q.type=integer&q.value=localhost&q.value=5',
- {}, None),
+ 'GET', '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op='
+ '&q.type=&q.type=integer&q.value=localhost&q.value=5'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(events), 1)
def test_get_from_event_class(self):
@@ -192,8 +191,8 @@ class EventManagerTest(utils.BaseTestCase):
self.assertTrue(event)
event.get()
expect = [
- ('GET', '/v2/events/2', {}, None),
- ('GET', '/v2/events/2', {}, None),
+ 'GET', '/v2/events/2'
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect, pos=0)
+ self.http_client.assert_called(*expect, pos=1)
self.assertEqual('Foo', event.event_type)
diff --git a/ceilometerclient/tests/v2/test_options.py b/ceilometerclient/tests/v2/test_options.py
index e9dee54..6318d5c 100644
--- a/ceilometerclient/tests/v2/test_options.py
+++ b/ceilometerclient/tests/v2/test_options.py
@@ -10,7 +10,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
from ceilometerclient.tests import utils
from ceilometerclient.v2 import options
diff --git a/ceilometerclient/tests/v2/test_query_alarm_history.py b/ceilometerclient/tests/v2/test_query_alarm_history.py
index 2a6cfb4..60d437d 100644
--- a/ceilometerclient/tests/v2/test_query_alarm_history.py
+++ b/ceilometerclient/tests/v2/test_query_alarm_history.py
@@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
from ceilometerclient.v2 import query
@@ -49,13 +51,16 @@ class QueryAlarmsManagerTest(utils.BaseTestCase):
def setUp(self):
super(QueryAlarmsManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = query.QueryAlarmHistoryManager(self.api)
def test_query(self):
alarm_history = self.mgr.query(**QUERY)
expect = [
- ('POST', '/v2/query/alarms/history', {}, QUERY),
+
+ 'POST', '/v2/query/alarms/history', QUERY,
+
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect)
self.assertEqual(1, len(alarm_history))
diff --git a/ceilometerclient/tests/v2/test_query_alarms.py b/ceilometerclient/tests/v2/test_query_alarms.py
index 199caa7..7e7a108 100644
--- a/ceilometerclient/tests/v2/test_query_alarms.py
+++ b/ceilometerclient/tests/v2/test_query_alarms.py
@@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
from ceilometerclient.v2 import query
@@ -60,13 +62,15 @@ class QueryAlarmsManagerTest(utils.BaseTestCase):
def setUp(self):
super(QueryAlarmsManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = query.QueryAlarmsManager(self.api)
def test_query(self):
alarms = self.mgr.query(**QUERY)
expect = [
- ('POST', '/v2/query/alarms', {}, QUERY),
+ 'POST', '/v2/query/alarms', QUERY,
]
- self.assertEqual(expect, self.api.calls)
+
+ self.http_client.assert_called(*expect)
self.assertEqual(1, len(alarms))
diff --git a/ceilometerclient/tests/v2/test_query_samples.py b/ceilometerclient/tests/v2/test_query_samples.py
index b12a508..7f6e7d9 100644
--- a/ceilometerclient/tests/v2/test_query_samples.py
+++ b/ceilometerclient/tests/v2/test_query_samples.py
@@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
from ceilometerclient.v2 import query
@@ -53,13 +55,15 @@ class QuerySamplesManagerTest(utils.BaseTestCase):
def setUp(self):
super(QuerySamplesManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = query.QuerySamplesManager(self.api)
def test_query(self):
samples = self.mgr.query(**QUERY)
expect = [
- ('POST', '/v2/query/samples', {}, QUERY),
+
+ 'POST', '/v2/query/samples', QUERY,
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect)
self.assertEqual(1, len(samples))
diff --git a/ceilometerclient/tests/v2/test_resources.py b/ceilometerclient/tests/v2/test_resources.py
index d62ce40..5d53737 100644
--- a/ceilometerclient/tests/v2/test_resources.py
+++ b/ceilometerclient/tests/v2/test_resources.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.resources
@@ -70,15 +71,16 @@ class ResourceManagerTest(utils.BaseTestCase):
def setUp(self):
super(ResourceManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.resources.ResourceManager(self.api)
def test_list_all(self):
resources = list(self.mgr.list())
expect = [
- ('GET', '/v2/resources', {}, None),
+ 'GET', '/v2/resources'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 2)
self.assertEqual(resources[0].resource_id, 'a')
self.assertEqual(resources[1].resource_id, 'b')
@@ -86,9 +88,9 @@ class ResourceManagerTest(utils.BaseTestCase):
def test_list_one(self):
resource = self.mgr.get(resource_id='a')
expect = [
- ('GET', '/v2/resources/a', {}, None),
+ 'GET', '/v2/resources/a'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertTrue(resource)
self.assertEqual(resource.resource_id, 'a')
@@ -97,11 +99,10 @@ class ResourceManagerTest(utils.BaseTestCase):
"value": "a"},
]))
expect = [
- ('GET', '/v2/resources?q.field=resource_id&q.op='
- '&q.type=&q.value=a',
- {}, None),
+ 'GET', '/v2/resources?q.field=resource_id&q.op='
+ '&q.type=&q.value=a'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(resources), 1)
self.assertEqual(resources[0].resource_id, 'a')
@@ -110,8 +111,8 @@ class ResourceManagerTest(utils.BaseTestCase):
self.assertTrue(resource)
resource.get()
expect = [
- ('GET', '/v2/resources/a', {}, None),
- ('GET', '/v2/resources/a', {}, None),
+ 'GET', '/v2/resources/a'
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect, pos=0)
+ self.http_client.assert_called(*expect, pos=1)
self.assertEqual('a', resource.resource_id)
diff --git a/ceilometerclient/tests/v2/test_samples.py b/ceilometerclient/tests/v2/test_samples.py
index 7b0b878..46b4cff 100644
--- a/ceilometerclient/tests/v2/test_samples.py
+++ b/ceilometerclient/tests/v2/test_samples.py
@@ -15,6 +15,8 @@
import copy
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.samples
@@ -71,15 +73,16 @@ class SampleManagerTest(utils.BaseTestCase):
def setUp(self):
super(SampleManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.samples.SampleManager(self.api)
def test_list_by_meter_name(self):
samples = list(self.mgr.list(meter_name='instance'))
expect = [
- ('GET', '/v2/meters/instance', {}, None),
+ 'GET', '/v2/meters/instance'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
self.assertEqual(samples[0].resource_id, 'resource-id')
@@ -91,20 +94,20 @@ class SampleManagerTest(utils.BaseTestCase):
{"field": "source",
"value": "bar"},
]))
- expect = [('GET', '%s?%s' % (base_url, args), {}, None)]
- self.assertEqual(self.api.calls, expect)
+ expect = ['GET', '%s?%s' % (base_url, args)]
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 0)
def test_create(self):
sample = self.mgr.create(**CREATE_SAMPLE)
expect = [
- ('POST', '/v2/meters/instance', {}, [CREATE_SAMPLE]),
+ 'POST', '/v2/meters/instance'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect, body=CREATE_SAMPLE)
self.assertTrue(sample)
def test_limit(self):
samples = list(self.mgr.list(meter_name='instance', limit=1))
- expect = [('GET', '/v2/meters/instance?limit=1', {}, None)]
- self.assertEqual(self.api.calls, expect)
+ expect = ['GET', '/v2/meters/instance?limit=1']
+ self.http_client.assert_called(*expect)
self.assertEqual(len(samples), 1)
diff --git a/ceilometerclient/tests/v2/test_statistics.py b/ceilometerclient/tests/v2/test_statistics.py
index ed3465c..65f633e 100644
--- a/ceilometerclient/tests/v2/test_statistics.py
+++ b/ceilometerclient/tests/v2/test_statistics.py
@@ -12,7 +12,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.statistics
@@ -114,15 +115,16 @@ class StatisticsManagerTest(utils.BaseTestCase):
def setUp(self):
super(StatisticsManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.statistics.StatisticsManager(self.api)
def test_list_by_meter_name(self):
stats = list(self.mgr.list(meter_name='instance'))
expect = [
- ('GET', '/v2/meters/instance/statistics', {}, None),
+ 'GET', '/v2/meters/instance/statistics'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(stats), 1)
self.assertEqual(stats[0].count, 135)
@@ -135,10 +137,9 @@ class StatisticsManagerTest(utils.BaseTestCase):
"value": "bar"},
]))
expect = [
- ('GET',
- '%s?%s' % (base_url, qry), {}, None),
+ 'GET', '%s?%s' % (base_url, qry)
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(stats), 1)
self.assertEqual(stats[0].count, 135)
@@ -152,10 +153,9 @@ class StatisticsManagerTest(utils.BaseTestCase):
],
period=60))
expect = [
- ('GET',
- '%s?%s%s' % (base_url, qry, period), {}, None),
+ 'GET', '%s?%s%s' % (base_url, qry, period)
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(stats), 1)
self.assertEqual(stats[0].count, 135)
@@ -169,10 +169,10 @@ class StatisticsManagerTest(utils.BaseTestCase):
],
groupby=['resource_id']))
expect = [
- ('GET',
- '%s?%s%s' % (base_url, qry, groupby), {}, None),
+ 'GET',
+ '%s?%s%s' % (base_url, qry, groupby)
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(stats), 2)
self.assertEqual(stats[0].count, 135)
self.assertEqual(stats[1].count, 12)
@@ -189,10 +189,10 @@ class StatisticsManagerTest(utils.BaseTestCase):
],
groupby='resource_id'))
expect = [
- ('GET',
- '%s?%s%s' % (base_url, qry, groupby), {}, None),
+ 'GET',
+ '%s?%s%s' % (base_url, qry, groupby)
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect)
self.assertEqual(2, len(stats))
self.assertEqual(135, stats[0].count)
self.assertEqual(12, stats[1].count)
@@ -212,10 +212,10 @@ class StatisticsManagerTest(utils.BaseTestCase):
stats = list(self.mgr.list(meter_name='instance',
aggregates=aggregates))
expect = [
- ('GET',
- '%s?%s' % (base_url, aggregate_query), {}, None),
+ 'GET',
+ '%s?%s' % (base_url, aggregate_query)
]
- self.assertEqual(expect, self.api.calls)
+ self.http_client.assert_called(*expect)
self.assertEqual(1, len(stats))
self.assertEqual(2, stats[0].count)
self.assertEqual(2.0, stats[0].aggregate.get('count'))
diff --git a/ceilometerclient/tests/v2/test_trait_descriptions.py b/ceilometerclient/tests/v2/test_trait_descriptions.py
index 0b273f0..7913124 100644
--- a/ceilometerclient/tests/v2/test_trait_descriptions.py
+++ b/ceilometerclient/tests/v2/test_trait_descriptions.py
@@ -11,7 +11,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.trait_descriptions
@@ -34,16 +35,17 @@ class TraitDescriptionManagerTest(utils.BaseTestCase):
def setUp(self):
super(TraitDescriptionManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = (ceilometerclient.v2.trait_descriptions.
TraitDescriptionManager(self.api))
def test_list(self):
trait_descriptions = list(self.mgr.list('Foo'))
expect = [
- ('GET', '/v2/event_types/Foo/traits', {}, None),
+ 'GET', '/v2/event_types/Foo/traits'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(trait_descriptions), 3)
for i, vals in enumerate([('trait_1', 'string'),
('trait_2', 'integer'),
diff --git a/ceilometerclient/tests/v2/test_traits.py b/ceilometerclient/tests/v2/test_traits.py
index f8239a0..1d7dde0 100644
--- a/ceilometerclient/tests/v2/test_traits.py
+++ b/ceilometerclient/tests/v2/test_traits.py
@@ -11,7 +11,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+from ceilometerclient.openstack.common.apiclient import client
+from ceilometerclient.openstack.common.apiclient import fake_client
from ceilometerclient.tests import utils
import ceilometerclient.v2.traits
@@ -37,15 +38,16 @@ class TraitManagerTest(utils.BaseTestCase):
def setUp(self):
super(TraitManagerTest, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
+ self.api = client.BaseClient(self.http_client)
self.mgr = ceilometerclient.v2.traits.TraitManager(self.api)
def test_list(self):
traits = list(self.mgr.list('Foo', 'trait_1'))
expect = [
- ('GET', '/v2/event_types/Foo/traits/trait_1', {}, None),
+ 'GET', '/v2/event_types/Foo/traits/trait_1'
]
- self.assertEqual(self.api.calls, expect)
+ self.http_client.assert_called(*expect)
self.assertEqual(len(traits), 2)
for i, vals in enumerate([('trait_1',
'datetime',
diff --git a/ceilometerclient/v1/client.py b/ceilometerclient/v1/client.py
index 89a5b44..e8827e2 100644
--- a/ceilometerclient/v1/client.py
+++ b/ceilometerclient/v1/client.py
@@ -13,7 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from ceilometerclient.common import http
+
+from ceilometerclient import client as ceiloclient
+from ceilometerclient.openstack.common.apiclient import client
from ceilometerclient.v1 import meters
@@ -29,7 +31,24 @@ class Client(object):
def __init__(self, *args, **kwargs):
"""Initialize a new client for the Ceilometer v1 API."""
- self.http_client = http.HTTPClient(*args, **kwargs)
+ self.auth_plugin = kwargs.get('auth_plugin') \
+ or ceiloclient.get_auth_plugin(*args, **kwargs)
+ self.client = client.HTTPClient(
+ auth_plugin=self.auth_plugin,
+ region_name=kwargs.get('region_name'),
+ endpoint_type=kwargs.get('endpoint_type'),
+ original_ip=kwargs.get('original_ip'),
+ verify=kwargs.get('verify'),
+ cert=kwargs.get('cacert'),
+ timeout=kwargs.get('timeout'),
+ timings=kwargs.get('timings'),
+ keyring_saver=kwargs.get('keyring_saver'),
+ debug=kwargs.get('debug'),
+ user_agent=kwargs.get('user_agent'),
+ http=kwargs.get('http')
+ )
+
+ self.http_client = client.BaseClient(self.client)
self.meters = meters.MeterManager(self.http_client)
self.samples = meters.SampleManager(self.http_client)
self.users = meters.UserManager(self.http_client)
diff --git a/ceilometerclient/v2/alarms.py b/ceilometerclient/v2/alarms.py
index 7c46fb2..341cbb7 100644
--- a/ceilometerclient/v2/alarms.py
+++ b/ceilometerclient/v2/alarms.py
@@ -57,7 +57,8 @@ class Alarm(base.Resource):
return self.manager.delete(self.alarm_id)
def get_state(self):
- return self.manager.get_state(self.alarm_id)
+ state = self.manager.get_state(self.alarm_id)
+ return state.get('alarm')
class AlarmChange(base.Resource):
@@ -167,14 +168,12 @@ class AlarmManager(base.Manager):
return self._delete(self._path(alarm_id))
def set_state(self, alarm_id, state):
- resp, body = self.api.json_request('PUT',
- "%s/state" % self._path(alarm_id),
- body=state)
+ body = self.api.put("%s/state" % self._path(alarm_id),
+ json=state).json()
return body
def get_state(self, alarm_id):
- resp, body = self.api.json_request('GET',
- "%s/state" % self._path(alarm_id))
+ body = self.api.get("%s/state" % self._path(alarm_id)).json()
return body
def get_history(self, alarm_id, q=None):
diff --git a/ceilometerclient/v2/client.py b/ceilometerclient/v2/client.py
index ba5ca43..95be8f5 100644
--- a/ceilometerclient/v2/client.py
+++ b/ceilometerclient/v2/client.py
@@ -15,7 +15,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-from ceilometerclient.common import http
+from ceilometerclient import client as ceiloclient
+from ceilometerclient.openstack.common.apiclient import client
from ceilometerclient.v2 import alarms
from ceilometerclient.v2 import event_types
from ceilometerclient.v2 import events
@@ -39,8 +40,26 @@ class Client(object):
"""
def __init__(self, *args, **kwargs):
+
"""Initialize a new client for the Ceilometer v2 API."""
- self.http_client = http.HTTPClient(*args, **kwargs)
+ self.auth_plugin = kwargs.get('auth_plugin') \
+ or ceiloclient.get_auth_plugin(*args, **kwargs)
+ self.client = client.HTTPClient(
+ auth_plugin=self.auth_plugin,
+ region_name=kwargs.get('region_name'),
+ endpoint_type=kwargs.get('endpoint_type'),
+ original_ip=kwargs.get('original_ip'),
+ verify=kwargs.get('verify'),
+ cert=kwargs.get('cacert'),
+ timeout=kwargs.get('timeout'),
+ timings=kwargs.get('timings'),
+ keyring_saver=kwargs.get('keyring_saver'),
+ debug=kwargs.get('debug'),
+ user_agent=kwargs.get('user_agent'),
+ http=kwargs.get('http')
+ )
+
+ self.http_client = client.BaseClient(self.client)
self.meters = meters.MeterManager(self.http_client)
self.samples = samples.SampleManager(self.http_client)
self.statistics = statistics.StatisticsManager(self.http_client)
@@ -51,6 +70,7 @@ class Client(object):
self.traits = traits.TraitManager(self.http_client)
self.trait_descriptions = trait_descriptions.\
TraitDescriptionManager(self.http_client)
+
self.query_samples = query.QuerySamplesManager(
self.http_client)
self.query_alarms = query.QueryAlarmsManager(
diff --git a/ceilometerclient/v2/query.py b/ceilometerclient/v2/query.py
index 85d2f6c..a11a56d 100644
--- a/ceilometerclient/v2/query.py
+++ b/ceilometerclient/v2/query.py
@@ -33,9 +33,9 @@ class QueryManager(base.Manager):
query["limit"] = limit
url = '/v2/query%s' % self.path_suffix
- resp, body = self.api.json_request('POST',
- url,
- body=query)
+
+ body = self.api.post(url, json=query).json()
+
if body:
return [self.resource_class(self, b) for b in body]
else:
diff --git a/ceilometerclient/v2/samples.py b/ceilometerclient/v2/samples.py
index cd0c3c2..b0ff3b5 100644
--- a/ceilometerclient/v2/samples.py
+++ b/ceilometerclient/v2/samples.py
@@ -47,8 +47,6 @@ class SampleManager(base.Manager):
new = dict((key, value) for (key, value) in kwargs.items()
if key in CREATION_ATTRIBUTES)
url = self._path(counter_name=kwargs['counter_name'])
- resp, body = self.api.json_request('POST',
- url,
- body=[new])
+ body = self.api.post(url, json=new).json()
if body:
return [Sample(self, b) for b in body]
diff --git a/requirements.txt b/requirements.txt
index 6123791..1c2e9bb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ iso8601>=0.1.9
PrettyTable>=0.7,<0.8
python-keystoneclient>=0.9.0
six>=1.7.0
+stevedore>=0.14