Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf2b4f31c7 | ||
|
|
2fe71f729a | ||
|
|
c6b90fc6e6 | ||
|
|
d9aa46de34 | ||
|
|
56e6f689bb | ||
|
|
75755b2af3 | ||
|
|
40ddf6a470 | ||
|
|
287dd57185 | ||
|
|
416a717ebc | ||
|
|
efb2b0949a | ||
|
|
a567600b77 | ||
|
|
d04e5ac776 | ||
|
|
a1f45a0206 | ||
|
|
2211d48f72 | ||
|
|
e402ce676c | ||
|
|
c423ca4470 | ||
|
|
f750d31169 | ||
|
|
cdbcafd142 | ||
|
|
cffa8b8936 | ||
|
|
10f80c7d02 | ||
|
|
87cdbb1340 | ||
|
|
cede66dde6 | ||
|
|
addb3a8b33 | ||
|
|
04bf3504ee | ||
|
|
b6f7a7831f | ||
|
|
70cef21224 | ||
|
|
8fa848fb51 | ||
|
|
d70f9c778c | ||
|
|
ddf93becc1 | ||
|
|
0024760bef | ||
|
|
5d43074cc4 | ||
|
|
d82273fcd4 | ||
|
|
241d90f541 | ||
|
|
708aeff9b7 | ||
|
|
9a9399f284 | ||
|
|
a070f5b16c | ||
|
|
9a1f531155 | ||
|
|
d0f0aaf346 | ||
|
|
a93f8b04b1 | ||
|
|
e6daa3df81 | ||
|
|
7a199820d0 | ||
|
|
b24e261143 | ||
|
|
9acc36b4ca | ||
|
|
a6093c5a36 | ||
|
|
9554c9e440 | ||
|
|
8318891835 | ||
|
|
b2a42f71fe | ||
|
|
d4ae928048 | ||
|
|
1d8378cc6c | ||
|
|
44a2bb0b26 | ||
|
|
0417e30f76 | ||
|
|
a4dd6e1a61 | ||
|
|
d503c98cbe | ||
|
|
0efe6a0606 | ||
|
|
69399b5e5d | ||
|
|
df5087a344 | ||
|
|
70771bf2d7 | ||
|
|
367608ceeb | ||
|
|
92981a7bb4 | ||
|
|
5faa8b0de6 | ||
|
|
55f3a3fa75 | ||
|
|
336f1466e0 | ||
|
|
5b6fd6c529 | ||
|
|
778782c3c9 | ||
|
|
985e3c2304 | ||
|
|
0cad4b0e99 | ||
|
|
1703d5538b | ||
|
|
c6e23ab770 | ||
|
|
450aa61358 | ||
|
|
066c9564fb | ||
|
|
6abecf6348 | ||
|
|
a63b75c555 | ||
|
|
f8c4caba43 | ||
|
|
c6f2cb4643 | ||
|
|
5c188a2306 | ||
|
|
9dd1a6fbea | ||
|
|
0de831021d | ||
|
|
4dc3e65e44 | ||
|
|
8b69ecf237 | ||
|
|
ea21f9761b | ||
|
|
df4e8360e2 | ||
|
|
236bf8b307 | ||
|
|
6dbfc4502e | ||
|
|
def167f77a | ||
|
|
4fe0255682 | ||
|
|
e4623d6663 | ||
|
|
382a2d9565 | ||
|
|
9428ab38aa | ||
|
|
1e095e6da9 | ||
|
|
621c06f8af | ||
|
|
e4df2e2105 | ||
|
|
50f6cb3e54 | ||
|
|
d9d61d7727 | ||
|
|
bf03f8fae6 | ||
|
|
b17283d585 |
@@ -3,10 +3,7 @@ branch = True
|
||||
source = cloudkittyclient
|
||||
omit =
|
||||
cloudkittyclient/tests/*,
|
||||
cloudkittyclient/openstack/*,
|
||||
cloudkittyclient/i18n.py,
|
||||
cloudkittyclient/common/client.py,
|
||||
cloudkittyclient/common/exceptions.py
|
||||
cloudkittyclient/i18n.py
|
||||
|
||||
[report]
|
||||
ignore-errors = True
|
||||
ignore_errors = True
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,3 +11,6 @@ cover
|
||||
dist
|
||||
*.egg
|
||||
*.sw?
|
||||
.eggs
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=stackforge/python-cloudkittyclient.git
|
||||
project=openstack/python-cloudkittyclient.git
|
||||
|
||||
19
.pylintrc
19
.pylintrc
@@ -1,19 +0,0 @@
|
||||
[MASTER]
|
||||
ignore=openstack,test
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
# C0111: Don't require docstrings on every method
|
||||
# W0511: TODOs in code comments are fine.
|
||||
# W0142: *args and **kwargs are fine.
|
||||
# W0622: Redefining id is fine.
|
||||
disable=C0111,W0511,W0142,W0622
|
||||
|
||||
[BASIC]
|
||||
# Don't require docstrings on tests.
|
||||
no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
|
||||
|
||||
[Variables]
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
# _ is used by our localization
|
||||
additional-builtins=_
|
||||
@@ -1,6 +0,0 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
||||
@@ -1,3 +1,12 @@
|
||||
========================
|
||||
Team and repository tags
|
||||
========================
|
||||
|
||||
.. image:: http://governance.openstack.org/badges/python-cloudkittyclient.svg
|
||||
:target: http://governance.openstack.org/reference/tags/index.html
|
||||
|
||||
.. Change things from this point on
|
||||
|
||||
Python bindings to the CloudKitty API
|
||||
=====================================
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2015 Objectif Libre
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
||||
@@ -37,7 +37,7 @@ import os
|
||||
import six
|
||||
from stevedore import extension
|
||||
|
||||
from cloudkittyclient.openstack.common.apiclient import exceptions
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
|
||||
|
||||
_discovered_plugins = {}
|
||||
@@ -54,7 +54,7 @@ def discover_auth_systems():
|
||||
def add_plugin(ext):
|
||||
_discovered_plugins[ext.name] = ext.plugin
|
||||
|
||||
ep_namespace = "cloudkittyclient.openstack.common.apiclient.auth"
|
||||
ep_namespace = "cloudkittyclient.apiclient.auth"
|
||||
mgr = extension.ExtensionManager(ep_namespace)
|
||||
mgr.map(add_plugin)
|
||||
|
||||
@@ -156,8 +156,7 @@ class BaseAuthPlugin(object):
|
||||
|
||||
@classmethod
|
||||
def add_opts(cls, parser):
|
||||
"""Populate the parser with the options for this plugin.
|
||||
"""
|
||||
"""Populate the parser with the options for this plugin."""
|
||||
for opt in cls.opt_names:
|
||||
# use `BaseAuthPlugin.common_opt_names` since it is never
|
||||
# changed in child classes
|
||||
@@ -166,8 +165,7 @@ class BaseAuthPlugin(object):
|
||||
|
||||
@classmethod
|
||||
def add_common_opts(cls, parser):
|
||||
"""Add options that are common for several plugins.
|
||||
"""
|
||||
"""Add options that are common for several plugins."""
|
||||
for opt in cls.common_opt_names:
|
||||
cls._parser_add_opt(parser, opt)
|
||||
|
||||
@@ -204,8 +202,7 @@ class BaseAuthPlugin(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def _do_authenticate(self, http_client):
|
||||
"""Protected method for authentication.
|
||||
"""
|
||||
"""Protected method for authentication."""
|
||||
|
||||
def sufficient_options(self):
|
||||
"""Check if all required options are present.
|
||||
@@ -44,8 +44,8 @@ from oslo_utils import strutils
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from cloudkittyclient.openstack.common._i18n import _
|
||||
from cloudkittyclient.openstack.common.apiclient import exceptions
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
def getid(obj):
|
||||
@@ -467,8 +467,7 @@ class Resource(object):
|
||||
|
||||
@property
|
||||
def human_id(self):
|
||||
"""Human-readable ID which can be used for bash completion.
|
||||
"""
|
||||
"""Human-readable ID which can be used for bash completion."""
|
||||
if self.HUMAN_ID:
|
||||
name = getattr(self, self.NAME_ATTR, None)
|
||||
if name is not None:
|
||||
@@ -523,6 +522,9 @@ class Resource(object):
|
||||
return self.id == other.id
|
||||
return self._info == other._info
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def is_loaded(self):
|
||||
return self._loaded
|
||||
|
||||
@@ -38,8 +38,9 @@ from oslo_utils import encodeutils
|
||||
from oslo_utils import importutils
|
||||
import requests
|
||||
|
||||
from cloudkittyclient.openstack.common._i18n import _
|
||||
from cloudkittyclient.openstack.common.apiclient import exceptions
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
|
||||
@@ -64,7 +65,7 @@ class HTTPClient(object):
|
||||
into terminal and send the same request with curl.
|
||||
"""
|
||||
|
||||
user_agent = "cloudkittyclient.openstack.common.apiclient"
|
||||
user_agent = "cloudkittyclient.apiclient"
|
||||
|
||||
def __init__(self,
|
||||
auth_plugin,
|
||||
@@ -38,12 +38,11 @@ import sys
|
||||
|
||||
import six
|
||||
|
||||
from cloudkittyclient.openstack.common._i18n import _
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
"""The base exception class for all exceptions this library raises.
|
||||
"""
|
||||
"""The base exception class for all exceptions this library raises."""
|
||||
pass
|
||||
|
||||
|
||||
@@ -118,8 +117,7 @@ class AmbiguousEndpoints(EndpointException):
|
||||
|
||||
|
||||
class HttpError(ClientException):
|
||||
"""The base exception class for all HTTP exceptions.
|
||||
"""
|
||||
"""The base exception class for all HTTP exceptions."""
|
||||
http_status = 0
|
||||
message = _("HTTP Error")
|
||||
|
||||
@@ -43,7 +43,7 @@ import requests
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from cloudkittyclient.openstack.common.apiclient import client
|
||||
from cloudkittyclient.apiclient import client
|
||||
|
||||
|
||||
def assert_has_keys(dct, required=None, optional=None):
|
||||
@@ -59,8 +59,7 @@ def assert_has_keys(dct, required=None, optional=None):
|
||||
|
||||
|
||||
class TestResponse(requests.Response):
|
||||
"""Wrap requests.Response and provide a convenient initialization.
|
||||
"""
|
||||
"""Wrap requests.Response and provide a convenient initialization."""
|
||||
|
||||
def __init__(self, data):
|
||||
super(TestResponse, self).__init__()
|
||||
@@ -88,6 +87,9 @@ class TestResponse(requests.Response):
|
||||
self.headers == other.headers and
|
||||
self._content == other._content)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class FakeHTTPClient(client.HTTPClient):
|
||||
|
||||
@@ -99,15 +101,14 @@ class FakeHTTPClient(client.HTTPClient):
|
||||
super(FakeHTTPClient, self).__init__(*args, **kwargs)
|
||||
|
||||
def assert_called(self, method, url, body=None, pos=-1):
|
||||
"""Assert than an API method was just called.
|
||||
"""
|
||||
"""Assert than an API method was just called."""
|
||||
expected = (method, url)
|
||||
called = self.callstack[pos][0:2]
|
||||
assert self.callstack, \
|
||||
"Expected %s %s but no calls were made." % expected
|
||||
msg = "Expected %s %s but no calls were made." % expected
|
||||
assert self.callstack, msg
|
||||
|
||||
assert expected == called, 'Expected %s %s; got %s %s' % \
|
||||
(expected + called)
|
||||
msg = 'Expected %s %s; got %s %s' % (expected + called)
|
||||
assert expected == called, msg
|
||||
|
||||
if body is not None:
|
||||
if self.callstack[pos][3] != body:
|
||||
@@ -115,12 +116,11 @@ class FakeHTTPClient(client.HTTPClient):
|
||||
(self.callstack[pos][3], body))
|
||||
|
||||
def assert_called_anytime(self, method, url, body=None):
|
||||
"""Assert than an API method was called anytime in the test.
|
||||
"""
|
||||
"""Assert than an API method was called anytime in the test."""
|
||||
expected = (method, url)
|
||||
|
||||
assert self.callstack, \
|
||||
"Expected %s %s but no calls were made." % expected
|
||||
msg = "Expected %s %s but no calls were made." % expected
|
||||
assert self.callstack, msg
|
||||
|
||||
found = False
|
||||
entry = None
|
||||
@@ -129,8 +129,8 @@ class FakeHTTPClient(client.HTTPClient):
|
||||
found = True
|
||||
break
|
||||
|
||||
assert found, 'Expected %s %s; got %s' % \
|
||||
(method, url, self.callstack)
|
||||
msg = 'Expected %s %s; got %s' % (method, url, self.callstack)
|
||||
assert found, msg
|
||||
if body is not None:
|
||||
assert entry[3] == body, "%s != %s" % (entry[3], body)
|
||||
|
||||
@@ -28,8 +28,8 @@ from oslo_utils import encodeutils
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from cloudkittyclient.openstack.common._i18n import _
|
||||
from cloudkittyclient.openstack.common.apiclient import exceptions
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
def find_resource(manager, name_or_id, **find_args):
|
||||
@@ -84,17 +84,13 @@ def find_resource(manager, name_or_id, **find_args):
|
||||
return manager.find(**kwargs)
|
||||
except exceptions.NotFound:
|
||||
msg = _("No %(name)s with a name or "
|
||||
"ID of '%(name_or_id)s' exists.") % \
|
||||
{
|
||||
"name": manager.resource_class.__name__.lower(),
|
||||
"name_or_id": name_or_id
|
||||
}
|
||||
"ID of '%(name_or_id)s' exists.") % {
|
||||
"name": manager.resource_class.__name__.lower(),
|
||||
"name_or_id": name_or_id}
|
||||
raise exceptions.CommandError(msg)
|
||||
except exceptions.NoUniqueMatch:
|
||||
msg = _("Multiple %(name)s matches found for "
|
||||
"'%(name_or_id)s', use an ID to be more specific.") % \
|
||||
{
|
||||
"name": manager.resource_class.__name__.lower(),
|
||||
"name_or_id": name_or_id
|
||||
}
|
||||
"'%(name_or_id)s', use an ID to be more specific.") % {
|
||||
"name": manager.resource_class.__name__.lower(),
|
||||
"name_or_id": name_or_id}
|
||||
raise exceptions.CommandError(msg)
|
||||
@@ -10,6 +10,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import time
|
||||
|
||||
from keystoneclient import adapter
|
||||
from keystoneclient.auth.identity import v2 as v2_auth
|
||||
from keystoneclient.auth.identity import v3 as v3_auth
|
||||
from keystoneclient import discover
|
||||
@@ -18,10 +22,11 @@ from keystoneclient import session
|
||||
from oslo_utils import strutils
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from cloudkittyclient.apiclient import auth
|
||||
from cloudkittyclient.apiclient import client
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.common import utils
|
||||
from cloudkittyclient import exc
|
||||
from cloudkittyclient.openstack.common.apiclient import auth
|
||||
from cloudkittyclient.openstack.common.apiclient import exceptions
|
||||
|
||||
|
||||
def _discover_auth_versions(session, auth_url):
|
||||
@@ -105,6 +110,8 @@ def _get_keystone_session(**kwargs):
|
||||
user_id=user_id,
|
||||
user_domain_name=user_domain_name,
|
||||
user_domain_id=user_domain_id,
|
||||
project_name=project_name,
|
||||
project_id=project_id,
|
||||
project_domain_name=project_domain_name,
|
||||
project_domain_id=project_domain_id)
|
||||
elif use_v2:
|
||||
@@ -145,7 +152,8 @@ class AuthPlugin(auth.BaseAuthPlugin):
|
||||
'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',
|
||||
'project_id', 'project_domain_id', 'project_domain_name',
|
||||
'user_id', 'user_domain_id', 'user_domain_name',
|
||||
'password', 'username', 'endpoint']
|
||||
|
||||
def __init__(self, auth_system=None, **kwargs):
|
||||
@@ -200,8 +208,13 @@ class AuthPlugin(auth.BaseAuthPlugin):
|
||||
"""
|
||||
has_token = self.opts.get('token') or self.opts.get('auth_token')
|
||||
no_auth = has_token and self.opts.get('endpoint')
|
||||
has_project = (self.opts.get('project_id')
|
||||
or (self.opts.get('project_name')
|
||||
and (self.opts.get('user_domain_name')
|
||||
or self.opts.get('user_domain_id'))))
|
||||
has_tenant = self.opts.get('tenant_id') or self.opts.get('tenant_name')
|
||||
has_credential = (self.opts.get('username') and has_tenant
|
||||
has_credential = (self.opts.get('username')
|
||||
and (has_project or has_tenant)
|
||||
and self.opts.get('password')
|
||||
and self.opts.get('auth_url'))
|
||||
missing = not (no_auth or has_credential)
|
||||
@@ -250,9 +263,28 @@ def get_client(version, **kwargs):
|
||||
:param api_version: the API version to use ('1')
|
||||
:param kwargs: keyword args containing credentials, either:
|
||||
|
||||
* session: a keystoneauth/keystoneclient session object
|
||||
* service_type: The default service_type for URL discovery
|
||||
* service_name: The default service_name for URL discovery
|
||||
* interface: The default interface for URL discovery
|
||||
(Default: public)
|
||||
* region_name: The default region_name for URL discovery
|
||||
* endpoint_override: Always use this endpoint URL for requests
|
||||
for this cloudkittyclient
|
||||
* auth: An auth plugin to use instead of the session one
|
||||
* user_agent: The User-Agent string to set
|
||||
(Default is python-cloudkittyclient)
|
||||
* connect_retries: the maximum number of retries that should be
|
||||
attempted for connection errors
|
||||
* logger: A logging object
|
||||
|
||||
or (DEPRECATED):
|
||||
|
||||
* os_token: pre-existing token to re-use
|
||||
* os_endpoint: Cloudkitty API endpoint
|
||||
or:
|
||||
|
||||
or (DEPRECATED):
|
||||
|
||||
* os_username: name of user
|
||||
* os_password: user's password
|
||||
* os_user_id: user's id
|
||||
@@ -274,8 +306,10 @@ def get_client(version, **kwargs):
|
||||
cli_kwargs = {
|
||||
'username': kwargs.get('os_username'),
|
||||
'password': kwargs.get('os_password'),
|
||||
'tenant_id': kwargs.get('os_tenant_id'),
|
||||
'tenant_name': kwargs.get('os_tenant_name'),
|
||||
'tenant_id': (kwargs.get('os_tenant_id')
|
||||
or kwargs.get('os_project_id')),
|
||||
'tenant_name': (kwargs.get('os_tenant_name')
|
||||
or kwargs.get('os_project_name')),
|
||||
'auth_url': kwargs.get('os_auth_url'),
|
||||
'region_name': kwargs.get('os_region_name'),
|
||||
'service_type': kwargs.get('os_service_type'),
|
||||
@@ -307,10 +341,94 @@ def get_auth_plugin(endpoint, **kwargs):
|
||||
endpoint=endpoint,
|
||||
username=kwargs.get('username'),
|
||||
password=kwargs.get('password'),
|
||||
tenant_name=kwargs.get('tenant_name'),
|
||||
tenant_name=kwargs.get('tenant_name') or kwargs.get('project_name'),
|
||||
user_domain_name=kwargs.get('user_domain_name'),
|
||||
user_domain_id=kwargs.get('user_domain_id'),
|
||||
project_domain_name=kwargs.get('project_domain_name'),
|
||||
project_domain_id=kwargs.get('project_domain_id')
|
||||
)
|
||||
return auth_plugin
|
||||
|
||||
|
||||
LEGACY_OPTS = ('auth_plugin', 'auth_url', 'token', 'insecure', 'cacert',
|
||||
'tenant_id', 'project_id', 'username', 'password',
|
||||
'project_name', 'tenant_name',
|
||||
'user_domain_name', 'user_domain_id',
|
||||
'project_domain_name', 'project_domain_id',
|
||||
'key_file', 'cert_file', 'verify', 'timeout', 'cert')
|
||||
|
||||
|
||||
def construct_http_client(**kwargs):
|
||||
kwargs = kwargs.copy()
|
||||
if kwargs.get('session') is not None:
|
||||
# Drop legacy options
|
||||
for opt in LEGACY_OPTS:
|
||||
kwargs.pop(opt, None)
|
||||
|
||||
return SessionClient(
|
||||
session=kwargs.pop('session'),
|
||||
service_type=kwargs.pop('service_type', 'rating') or 'rating',
|
||||
interface=kwargs.pop('interface', kwargs.pop('endpoint_type',
|
||||
'publicURL')),
|
||||
region_name=kwargs.pop('region_name', None),
|
||||
user_agent=kwargs.pop('user_agent', 'python-cloudkittyclient'),
|
||||
auth=kwargs.get('auth', None),
|
||||
timings=kwargs.pop('timings', None),
|
||||
**kwargs)
|
||||
else:
|
||||
return client.BaseClient(client.HTTPClient(
|
||||
auth_plugin=kwargs.get('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('cert'),
|
||||
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')
|
||||
))
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def record_time(times, enabled, *args):
|
||||
"""Record the time of a specific action.
|
||||
|
||||
:param times: A list of tuples holds time data.
|
||||
:type times: list
|
||||
:param enabled: Whether timing is enabled.
|
||||
:type enabled: bool
|
||||
:param args: Other data to be stored besides time data, these args
|
||||
will be joined to a string.
|
||||
"""
|
||||
if not enabled:
|
||||
yield
|
||||
else:
|
||||
start = time.time()
|
||||
yield
|
||||
end = time.time()
|
||||
times.append((' '.join(args), start, end))
|
||||
|
||||
|
||||
class SessionClient(adapter.LegacyJsonAdapter):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.times = []
|
||||
self.timings = kwargs.pop('timings', False)
|
||||
super(SessionClient, self).__init__(*args, **kwargs)
|
||||
|
||||
def request(self, url, method, **kwargs):
|
||||
kwargs.setdefault('headers', kwargs.get('headers', {}))
|
||||
# NOTE(sileht): The standard call raises errors from
|
||||
# keystoneauth, where we need to raise the cloudkittyclient errors.
|
||||
raise_exc = kwargs.pop('raise_exc', True)
|
||||
with record_time(self.times, self.timings, method, url):
|
||||
resp, body = super(SessionClient, self).request(url,
|
||||
method,
|
||||
raise_exc=False,
|
||||
**kwargs)
|
||||
|
||||
if raise_exc and resp.status_code >= 400:
|
||||
raise exc.from_response(resp, body)
|
||||
return resp
|
||||
|
||||
@@ -22,8 +22,9 @@ import copy
|
||||
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from cloudkittyclient.apiclient import base
|
||||
from cloudkittyclient import exc
|
||||
from cloudkittyclient.openstack.common.apiclient import base
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
def getid(obj):
|
||||
@@ -138,7 +139,7 @@ class CrudManager(base.CrudManager):
|
||||
'name': self.resource_class.__name__,
|
||||
'args': kwargs
|
||||
}
|
||||
raise exc.NotFound(404, msg)
|
||||
raise exc.HTTPNotFound(msg)
|
||||
return rl
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import prettytable
|
||||
import six
|
||||
from six import moves
|
||||
|
||||
from cloudkittyclient.openstack.common._i18n import _
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
class MissingArgs(Exception):
|
||||
@@ -267,5 +267,5 @@ def pretty_choice_list(l):
|
||||
|
||||
def exit(msg=''):
|
||||
if msg:
|
||||
print (msg, file=sys.stderr)
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@@ -23,11 +23,20 @@ import uuid
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import timeutils
|
||||
import prettytable
|
||||
import six
|
||||
|
||||
from cloudkittyclient.common import cliutils
|
||||
from cloudkittyclient import exc
|
||||
from cloudkittyclient.openstack.common import cliutils
|
||||
from cloudkittyclient.i18n import _
|
||||
|
||||
|
||||
def iso2dt(iso_date):
|
||||
"""iso8601 format to datetime."""
|
||||
iso_dt = timeutils.parse_isotime(iso_date)
|
||||
trans_dt = timeutils.normalize_time(iso_dt)
|
||||
return trans_dt
|
||||
|
||||
|
||||
def import_versioned_module(version, submodule=None):
|
||||
@@ -45,7 +54,9 @@ def arg(*args, **kwargs):
|
||||
kwargs['help'] += " Defaults to %s." % kwargs['default']
|
||||
required = kwargs.get('required', False)
|
||||
if required:
|
||||
kwargs['help'] += " Required."
|
||||
kwargs['help'] += " required."
|
||||
elif 'default' not in kwargs:
|
||||
kwargs['help'] += "."
|
||||
|
||||
# Because of the sematics of decorator composition if we just append
|
||||
# to the options list positional options will appear to be backwards.
|
||||
@@ -140,8 +151,10 @@ def find_resource(manager, name_or_id):
|
||||
try:
|
||||
return manager.find(name=name_or_id)
|
||||
except exc.HTTPNotFound:
|
||||
msg = ("No %s with a name or ID of '%s' exists." %
|
||||
(manager.resource_class.__name__.lower(), name_or_id))
|
||||
msg = _("No %(name)s with a name or ID of '%(id)s' exists.") % {
|
||||
"name": manager.resource_class.__name__.lower(),
|
||||
"id": name_or_id
|
||||
}
|
||||
raise exc.CommandError(msg)
|
||||
|
||||
|
||||
@@ -152,9 +165,12 @@ def args_array_to_dict(kwargs, key_to_convert):
|
||||
kwargs[key_to_convert] = dict(v.split("=", 1)
|
||||
for v in values_to_convert)
|
||||
except ValueError:
|
||||
raise exc.CommandError(
|
||||
'%s must be a list of key=value not "%s"' % (
|
||||
key_to_convert, values_to_convert))
|
||||
msg = _("%(key)s must be a list of key=value "
|
||||
"not '%(value)s'") % {
|
||||
"key": key_to_convert,
|
||||
"value": values_to_convert
|
||||
}
|
||||
raise exc.CommandError(msg)
|
||||
return kwargs
|
||||
|
||||
|
||||
@@ -172,9 +188,12 @@ def args_array_to_list_of_dicts(kwargs, key_to_convert):
|
||||
dct[kv[0]] = kv[1].strip(" \"'") # strip spaces and quotes
|
||||
kwargs[key_to_convert].append(dct)
|
||||
except Exception:
|
||||
raise exc.CommandError(
|
||||
'%s must be a list of key1=value1;key2=value2;... not "%s"' % (
|
||||
key_to_convert, values_to_convert))
|
||||
msg = _("%(key)s must be a list of "
|
||||
"key1=value1;key2=value2;... not '%(value)s'") % {
|
||||
"key": key_to_convert,
|
||||
"value": values_to_convert
|
||||
}
|
||||
raise exc.CommandError(msg)
|
||||
return kwargs
|
||||
|
||||
|
||||
|
||||
28
cloudkittyclient/i18n.py
Normal file
28
cloudkittyclient/i18n.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html
|
||||
|
||||
"""
|
||||
|
||||
import oslo_i18n as i18n
|
||||
|
||||
_translators = i18n.TranslatorFactory(domain='cloudkittyclient')
|
||||
i18n.enable_lazy()
|
||||
|
||||
_ = _translators.primary
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
@@ -1,45 +0,0 @@
|
||||
# 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.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
import oslo_i18n
|
||||
|
||||
# NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
|
||||
# application name when this module is synced into the separate
|
||||
# repository. It is OK to have more than one translation function
|
||||
# using the same domain, since there will still only be one message
|
||||
# catalog.
|
||||
_translators = oslo_i18n.TranslatorFactory(domain='cloudkittyclient')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
except ImportError:
|
||||
# NOTE(dims): Support for cases where a project wants to use
|
||||
# code from oslo-incubator, but is not ready to be internationalized
|
||||
# (like tempest)
|
||||
_ = _LI = _LW = _LE = _LC = lambda x: x
|
||||
35
cloudkittyclient/osc.py
Normal file
35
cloudkittyclient/osc.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
from cloudkittyclient import client as ckclient
|
||||
|
||||
DEFAULT_API_VERSION = '1'
|
||||
API_VERSION_OPTION = 'os_rating_api_version'
|
||||
API_NAME = "rating"
|
||||
API_VERSIONS = {
|
||||
"1": "cloudkittyclient.v1.client.Client",
|
||||
}
|
||||
|
||||
|
||||
def make_client(instance):
|
||||
"""Returns a rating service client."""
|
||||
version = instance._api_version[API_NAME]
|
||||
version = int(version)
|
||||
auth_config = instance.get_configuration()['auth']
|
||||
return ckclient.get_client(version, **auth_config)
|
||||
|
||||
|
||||
def build_option_parser(parser):
|
||||
"""Hook to add global options."""
|
||||
return parser
|
||||
@@ -28,9 +28,9 @@ from stevedore import extension
|
||||
|
||||
import cloudkittyclient
|
||||
from cloudkittyclient import client as ckclient
|
||||
from cloudkittyclient.common import cliutils
|
||||
from cloudkittyclient.common import utils
|
||||
from cloudkittyclient import exc
|
||||
from cloudkittyclient.openstack.common import cliutils
|
||||
from cloudkittyclient.v1.collector import shell as collector_shell
|
||||
from cloudkittyclient.v1.report import shell as report_shell
|
||||
from cloudkittyclient.v1.storage import shell as storage_shell
|
||||
@@ -54,6 +54,9 @@ def _positive_non_zero_int(argument_value):
|
||||
|
||||
class CloudkittyShell(object):
|
||||
|
||||
def __init__(self):
|
||||
self.auth_plugin = ckclient.AuthPlugin()
|
||||
|
||||
def get_base_parser(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='cloudkitty',
|
||||
@@ -174,7 +177,6 @@ class CloudkittyShell(object):
|
||||
|
||||
def parse_args(self, argv):
|
||||
# Parse args once to find version
|
||||
self.auth_plugin = ckclient.AuthPlugin()
|
||||
parser = self.get_base_parser()
|
||||
(options, args) = parser.parse_known_args(argv)
|
||||
self.auth_plugin.parse_opts(options)
|
||||
@@ -196,12 +198,11 @@ class CloudkittyShell(object):
|
||||
|
||||
@staticmethod
|
||||
def no_project_and_domain_set(args):
|
||||
if not (args.os_project_id or (args.os_project_name and
|
||||
(args.os_user_domain_name or args.os_user_domain_id)) or
|
||||
(args.os_tenant_id or args.os_tenant_name)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return not (((args.os_project_id or (args.os_project_name and
|
||||
(args.os_project_domain_name or
|
||||
args.os_project_domain_id)))
|
||||
and (args.os_user_domain_name or args.os_user_domain_id))
|
||||
or (args.os_tenant_id or args.os_tenant_name))
|
||||
|
||||
def main(self, argv):
|
||||
parsed = self.parse_args(argv)
|
||||
@@ -240,20 +241,24 @@ class CloudkittyShell(object):
|
||||
"env[OS_USER_DOMAIN_NAME] or "
|
||||
"a domain_id via either "
|
||||
"--os-user-domain-id or via "
|
||||
"env[OS_USER_DOMAIN_ID]")
|
||||
|
||||
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]")
|
||||
"env[OS_USER_DOMAIN_ID]\n\n"
|
||||
"As an alternative to project_id, "
|
||||
"you can provide a project_name via "
|
||||
"either --os-project-name or via "
|
||||
"env[OS_PROJECT_NAME] and "
|
||||
"a project_domain_name via either "
|
||||
"--os-project-domain-name or via "
|
||||
"env[OS_PROJECT_DOMAIN_NAME] or "
|
||||
"a project_domain_id via either "
|
||||
"--os-project-domain-id or via "
|
||||
"env[OS_PROJECT_DOMAIN_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_kwargs = vars(args)
|
||||
client_kwargs = {}
|
||||
client_kwargs.update(self.auth_plugin.opts)
|
||||
client_kwargs['auth_plugin'] = self.auth_plugin
|
||||
client = ckclient.get_client(api_version, **client_kwargs)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
|
||||
@@ -45,6 +45,16 @@ class ClientTest(utils.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(ClientTest, self).setUp()
|
||||
|
||||
def test_client_v1_with_session(self):
|
||||
resp = mock.Mock(status_code=200, text=b'')
|
||||
resp.json.return_value = {"modules": []}
|
||||
session = mock.Mock()
|
||||
session.request.return_value = resp
|
||||
c = client.get_client(1, session=session)
|
||||
c.modules.list()
|
||||
self.assertTrue(session.request.called)
|
||||
self.assertTrue(resp.json.called)
|
||||
|
||||
def test_client_version(self):
|
||||
c1 = self.create_client(env=FAKE_ENV, api_version=1)
|
||||
self.assertIsInstance(c1, v1client.Client)
|
||||
@@ -122,7 +132,7 @@ class ClientTest(utils.BaseTestCase):
|
||||
'user_agent': None,
|
||||
'debug': None,
|
||||
}
|
||||
cls = 'cloudkittyclient.openstack.common.apiclient.client.HTTPClient'
|
||||
cls = 'cloudkittyclient.apiclient.client.HTTPClient'
|
||||
with mock.patch(cls) as mocked:
|
||||
self.create_client(env)
|
||||
mocked.assert_called_with(**expected)
|
||||
@@ -137,7 +147,8 @@ class ClientTest(utils.BaseTestCase):
|
||||
env = FAKE_ENV.copy()
|
||||
env['cacert'] = '/path/to/cacert'
|
||||
client = self.create_client(env)
|
||||
self.assertEqual('/path/to/cacert', client.client.verify)
|
||||
self.assertEqual('/path/to/cacert',
|
||||
client.http_client.http_client.verify)
|
||||
|
||||
def test_v1_client_certfile_and_keyfile(self):
|
||||
env = FAKE_ENV.copy()
|
||||
@@ -145,4 +156,4 @@ class ClientTest(utils.BaseTestCase):
|
||||
env['key_file'] = '/path/to/keycert'
|
||||
client = self.create_client(env)
|
||||
self.assertEqual(('/path/to/cert', '/path/to/keycert'),
|
||||
client.client.cert)
|
||||
client.http_client.http_client.cert)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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
|
||||
|
||||
@@ -12,8 +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 cloudkittyclient.openstack.common.apiclient import client
|
||||
from cloudkittyclient.openstack.common.apiclient import fake_client
|
||||
from cloudkittyclient.apiclient import client
|
||||
from cloudkittyclient.apiclient import fake_client
|
||||
from cloudkittyclient.tests import utils
|
||||
import cloudkittyclient.v1.core
|
||||
|
||||
@@ -26,10 +26,12 @@ fixtures = {
|
||||
{
|
||||
'module_id': 'hashmap',
|
||||
'enabled': True,
|
||||
'priority': 1,
|
||||
},
|
||||
{
|
||||
'module_id': 'noop',
|
||||
'enabled': False,
|
||||
'priority': 1,
|
||||
},
|
||||
]},
|
||||
),
|
||||
@@ -40,6 +42,7 @@ fixtures = {
|
||||
{
|
||||
'module_id': 'hashmap',
|
||||
'enabled': True,
|
||||
'priority': 1,
|
||||
}
|
||||
),
|
||||
'PUT': (
|
||||
@@ -47,6 +50,7 @@ fixtures = {
|
||||
{
|
||||
'module_id': 'hashmap',
|
||||
'enabled': False,
|
||||
'priority': 1,
|
||||
}
|
||||
),
|
||||
},
|
||||
@@ -56,6 +60,7 @@ fixtures = {
|
||||
{
|
||||
'module_id': 'noop',
|
||||
'enabled': False,
|
||||
'priority': 1,
|
||||
}
|
||||
),
|
||||
'PUT': (
|
||||
@@ -63,6 +68,7 @@ fixtures = {
|
||||
{
|
||||
'module_id': 'noop',
|
||||
'enabled': True,
|
||||
'priority': 1,
|
||||
}
|
||||
),
|
||||
},
|
||||
@@ -94,9 +100,9 @@ class CloudkittyModuleManagerTest(utils.BaseTestCase):
|
||||
'GET', '/v1/rating/modules'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
self.assertEqual(len(resources), 2)
|
||||
self.assertEqual(resources[0].module_id, 'hashmap')
|
||||
self.assertEqual(resources[1].module_id, 'noop')
|
||||
self.assertEqual(2, len(resources))
|
||||
self.assertEqual('hashmap', resources[0].module_id)
|
||||
self.assertEqual('noop', resources[1].module_id)
|
||||
|
||||
def test_get_module_status(self):
|
||||
resource = self.mgr.get(module_id='hashmap')
|
||||
@@ -104,8 +110,8 @@ class CloudkittyModuleManagerTest(utils.BaseTestCase):
|
||||
'GET', '/v1/rating/modules/hashmap'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
self.assertEqual(resource.module_id, 'hashmap')
|
||||
self.assertEqual(resource.enabled, True)
|
||||
self.assertEqual('hashmap', resource.module_id)
|
||||
self.assertTrue(resource.enabled)
|
||||
|
||||
|
||||
class CloudkittyModuleTest(utils.BaseTestCase):
|
||||
@@ -123,7 +129,8 @@ class CloudkittyModuleTest(utils.BaseTestCase):
|
||||
# body : {'enabled': True}
|
||||
expect = [
|
||||
'PUT', '/v1/rating/modules/noop', {'module_id': 'noop',
|
||||
'enabled': True},
|
||||
'enabled': True,
|
||||
'priority': 1},
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
@@ -134,6 +141,19 @@ class CloudkittyModuleTest(utils.BaseTestCase):
|
||||
# body : {'enabled': False}
|
||||
expect = [
|
||||
'PUT', '/v1/rating/modules/hashmap', {'module_id': 'hashmap',
|
||||
'enabled': False},
|
||||
'enabled': False,
|
||||
'priority': 1},
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
def test_set_priority(self):
|
||||
self.ck_module = self.mgr.get(module_id='hashmap')
|
||||
self.ck_module.set_priority(100)
|
||||
# PUT /v1/rating/modules/hashmap
|
||||
# body : {'priority': 100}
|
||||
expect = [
|
||||
'PUT', '/v1/rating/modules/hashmap', {'module_id': 'hashmap',
|
||||
'enabled': True,
|
||||
'priority': 100},
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
139
cloudkittyclient/tests/v1/test_report.py
Normal file
139
cloudkittyclient/tests/v1/test_report.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# Copyright 2015 Objectif Libre
|
||||
# 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.
|
||||
from cloudkittyclient.apiclient import client
|
||||
from cloudkittyclient.apiclient import fake_client
|
||||
from cloudkittyclient.tests import utils
|
||||
import cloudkittyclient.v1.report
|
||||
|
||||
|
||||
fixtures = {
|
||||
'/v1/report/summary': {
|
||||
'GET': (
|
||||
{},
|
||||
{'summary': [
|
||||
{
|
||||
'tenant_id': 'ALL',
|
||||
'res_type': 'ALL',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '2325.29992'
|
||||
},
|
||||
]},
|
||||
),
|
||||
},
|
||||
'/v1/report/summary?tenant_id=649de47ad78a44bd8562b0aa84389b2b': {
|
||||
'GET': (
|
||||
{},
|
||||
{'summary': [
|
||||
{
|
||||
'tenant_id': '649de47ad78a44bd8562b0aa84389b2b',
|
||||
'res_type': 'ALL',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '990.14996'
|
||||
},
|
||||
]},
|
||||
),
|
||||
},
|
||||
'/v1/report/summary?service=compute': {
|
||||
'GET': (
|
||||
{},
|
||||
{'summary': [
|
||||
{
|
||||
'tenant_id': 'ALL',
|
||||
'res_type': 'compute',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '690.0'
|
||||
},
|
||||
]},
|
||||
),
|
||||
},
|
||||
'/v1/report/summary?groupby=res_type%2Ctenant_id': {
|
||||
'GET': (
|
||||
{},
|
||||
{'summary': [
|
||||
{
|
||||
'tenant_id': '3747afc360b64702a53bdd64dc1b8976',
|
||||
'res_type': 'compute',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '517.5'
|
||||
},
|
||||
{
|
||||
'tenant_id': '3747afc360b64702a53bdd64dc1b8976',
|
||||
'res_type': 'volume',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '817.64996'
|
||||
},
|
||||
{
|
||||
'tenant_id': '649de47ad78a44bd8562b0aa84389b2b',
|
||||
'res_type': 'compute',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '172.5'
|
||||
},
|
||||
{
|
||||
'tenant_id': '649de47ad78a44bd8562b0aa84389b2b',
|
||||
'res_type': 'volume',
|
||||
'begin': '2017-01-01T00:00:00',
|
||||
'end': '2017-02-01T00:00:00',
|
||||
'rate': '817.64996'
|
||||
},
|
||||
]},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class ReportSummaryManagerTest(utils.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ReportSummaryManagerTest, self).setUp()
|
||||
self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
|
||||
self.api = client.BaseClient(self.http_client)
|
||||
self.mgr = cloudkittyclient.v1.report.ReportSummaryManager(self.api)
|
||||
|
||||
def test_get_summary(self):
|
||||
self.mgr.get_summary()
|
||||
expect = [
|
||||
'GET', '/v1/report/summary'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
def test_get_summary_with_tenant(self):
|
||||
self.mgr.get_summary(tenant_id='649de47ad78a44bd8562b0aa84389b2b')
|
||||
expect = [
|
||||
'GET',
|
||||
'/v1/report/summary?tenant_id=649de47ad78a44bd8562b0aa84389b2b'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
def test_get_summary_with_service(self):
|
||||
self.mgr.get_summary(service='compute')
|
||||
expect = [
|
||||
'GET',
|
||||
'/v1/report/summary?service=compute'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
|
||||
def test_get_summary_with_groupby(self):
|
||||
self.mgr.get_summary(groupby='res_type,tenant_id')
|
||||
expect = [
|
||||
'GET',
|
||||
'/v1/report/summary?groupby=res_type%2Ctenant_id'
|
||||
]
|
||||
self.http_client.assert_called(*expect)
|
||||
@@ -16,7 +16,6 @@
|
||||
from stevedore import extension
|
||||
|
||||
from cloudkittyclient import client as ckclient
|
||||
from cloudkittyclient.openstack.common.apiclient import client
|
||||
from cloudkittyclient.v1 import collector
|
||||
from cloudkittyclient.v1 import core
|
||||
from cloudkittyclient.v1 import report
|
||||
@@ -28,38 +27,41 @@ SUBMODULES_NAMESPACE = 'cloudkitty.client.modules'
|
||||
class Client(object):
|
||||
"""Client for the Cloudkitty v1 API.
|
||||
|
||||
:param string endpoint: A user-supplied endpoint URL for the cloudkitty
|
||||
service.
|
||||
:param function token: Provides token for authentication.
|
||||
:param integer timeout: Allows customization of the timeout for client
|
||||
http requests. (optional)
|
||||
:param session: a keystoneauth/keystoneclient session object
|
||||
:type session: keystoneclient.session.Session
|
||||
:param str service_type: The default service_type for URL discovery
|
||||
:param str service_name: The default service_name for URL discovery
|
||||
:param str interface: The default interface for URL discovery
|
||||
(Default: public)
|
||||
:param str region_name: The default region_name for URL discovery
|
||||
:param str endpoint_override: Always use this endpoint URL for requests
|
||||
for this cloudkittyclient
|
||||
:param auth: An auth plugin to use instead of the session one
|
||||
:type auth: keystoneclient.auth.base.BaseAuthPlugin
|
||||
:param str user_agent: The User-Agent string to set
|
||||
(Default is python-cloudkittyclient)
|
||||
:param int connect_retries: the maximum number of retries that should be
|
||||
attempted for connection errors
|
||||
:param logger: A logging object
|
||||
:type logger: logging.Logger
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize a new client for the Cloudkitty v1 API."""
|
||||
self.auth_plugin = (kwargs.get('auth_plugin')
|
||||
or ckclient.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('cert'),
|
||||
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)
|
||||
if not kwargs.get('auth_plugin'):
|
||||
kwargs['auth_plugin'] = ckclient.get_auth_plugin(*args, **kwargs)
|
||||
self.auth_plugin = kwargs.get('auth_plugin')
|
||||
|
||||
self.http_client = ckclient.construct_http_client(**kwargs)
|
||||
self.modules = core.CloudkittyModuleManager(self.http_client)
|
||||
self.collector = collector.CollectorManager(self.http_client)
|
||||
self.reports = report.ReportManager(self.http_client)
|
||||
self.reportsummary = report.ReportSummaryManager(self.http_client)
|
||||
self.quotations = core.QuotationManager(self.http_client)
|
||||
self.storage = storage.StorageManager(self.http_client)
|
||||
self.config = core.ConfigInfoManager(self.http_client)
|
||||
self.service_info = core.ServiceInfoManager(self.http_client)
|
||||
self._expose_submodules()
|
||||
|
||||
def _expose_submodules(self):
|
||||
|
||||
@@ -17,64 +17,71 @@
|
||||
from cloudkittyclient.common import utils
|
||||
|
||||
|
||||
@utils.arg('--collector',
|
||||
@utils.arg('-c', '--collector',
|
||||
help='Collector name to filter on.',
|
||||
required=False,
|
||||
default=None)
|
||||
def do_collector_mapping_list(cc, args):
|
||||
"""List collector mapping."""
|
||||
data = cc.collector.mappings.list(collector=args.collector)
|
||||
fields = ['service', 'collector']
|
||||
fields_labels = ['Service', 'Collector']
|
||||
utils.print_list(data, fields, fields_labels, sortby=0)
|
||||
|
||||
|
||||
@utils.arg('--service',
|
||||
@utils.arg('-s', '--service',
|
||||
help='Which service to get the mapping for.',
|
||||
required=True)
|
||||
def do_collector_mapping_get(cc, args):
|
||||
"""Show collector mapping detail."""
|
||||
data = cc.collector.mappings.get(mapping_id=args.service)
|
||||
utils.print_dict(data.to_dict())
|
||||
|
||||
|
||||
@utils.arg('--collector',
|
||||
@utils.arg('-c', '--collector',
|
||||
help='Map a service to this collector.',
|
||||
required=True)
|
||||
@utils.arg('--service',
|
||||
@utils.arg('-s', '--service',
|
||||
help='Map a collector to this service.',
|
||||
required=True)
|
||||
def do_collector_mapping_create(cc, args):
|
||||
"""Create collector mapping."""
|
||||
out = cc.collector.mappings.create(service=args.service,
|
||||
collector=args.collector)
|
||||
utils.print_dict(out.to_dict())
|
||||
|
||||
|
||||
@utils.arg('--service',
|
||||
@utils.arg('-s', '--service',
|
||||
help='Filter on this service.',
|
||||
required=True)
|
||||
def do_collector_mapping_delete(cc, args):
|
||||
"""Delete collector mapping."""
|
||||
# TODO(sheeprine): Use a less hacky way to do this
|
||||
cc.collector.mappings.delete(mapping_id=args.service)
|
||||
|
||||
|
||||
@utils.arg('--name',
|
||||
@utils.arg('-n', '--name',
|
||||
help='Name of the collector.',
|
||||
required=True)
|
||||
def do_collector_state_get(cc, args):
|
||||
"""Show collector state."""
|
||||
data = cc.collector.states.get(state_id=args.name)
|
||||
utils.print_dict(data.to_dict())
|
||||
|
||||
|
||||
@utils.arg('--name',
|
||||
@utils.arg('-n', '--name',
|
||||
help='Name of the collector.',
|
||||
required=True)
|
||||
def do_collector_state_enable(cc, args):
|
||||
"""Enable collector state."""
|
||||
new_state = cc.collector.states.update(name=args.name, enabled=True)
|
||||
utils.print_dict(new_state.to_dict())
|
||||
|
||||
|
||||
@utils.arg('--name',
|
||||
@utils.arg('-n', '--name',
|
||||
help='Name of the collector.',
|
||||
required=True)
|
||||
def do_collector_state_disable(cc, args):
|
||||
"""Disable collector state."""
|
||||
new_state = cc.collector.states.update(name=args.name, enabled=False)
|
||||
utils.print_dict(new_state.to_dict())
|
||||
|
||||
109
cloudkittyclient/v1/collector/shell_cli.py
Normal file
109
cloudkittyclient/v1/collector/shell_cli.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
#
|
||||
# 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.
|
||||
|
||||
from osc_lib.command import command
|
||||
|
||||
from cloudkittyclient.v1.collector import shell
|
||||
|
||||
|
||||
class CliCollectorMappingList(command.Command):
|
||||
"""List collector mappings."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliCollectorMappingList, self).get_parser(prog_name)
|
||||
parser.add_argument('-c', '--collector',
|
||||
help='Collector name to filter on.',
|
||||
required=False,
|
||||
default=None)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_mapping_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliCollectorMappingGet(command.Command):
|
||||
"""Show collector mapping detail."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliCollectorMappingGet, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service',
|
||||
help='Which service to get the mapping for.',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_mapping_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliCollectorMappingCreate(command.Command):
|
||||
"""Create collector mappings."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliCollectorMappingCreate, self).get_parser(prog_name)
|
||||
parser.add_argument('-c', '--collector',
|
||||
help='Map a service to this collector.',
|
||||
required=True)
|
||||
parser.add_argument('-s', '--service',
|
||||
help='Map a collector to this service.',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_mapping_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliCollectorMappingDelete(command.Command):
|
||||
"""Delete collector mappings."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliCollectorMappingDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service',
|
||||
help='Filter on this service',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_mapping_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class BaseCliCollectorState(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(BaseCliCollectorState, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Name of the collector',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
|
||||
class CliCollectorStateGet(BaseCliCollectorState):
|
||||
"""Show collector state."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_state_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliCollectorStateEnable(BaseCliCollectorState):
|
||||
"""Enable collector state."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_state_enable(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliCollectorStateDisable(BaseCliCollectorState):
|
||||
"""Disable collector state."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_collector_state_disable(ckclient, parsed_args)
|
||||
@@ -30,6 +30,10 @@ class CloudkittyModule(base.Resource):
|
||||
self.enabled = False
|
||||
self.update()
|
||||
|
||||
def set_priority(self, value):
|
||||
self.priority = value
|
||||
self.update()
|
||||
|
||||
|
||||
class CloudkittyModuleManager(base.CrudManager):
|
||||
resource_class = CloudkittyModule
|
||||
@@ -60,3 +64,26 @@ class QuotationManager(base.Manager):
|
||||
out = self.api.post(self.base_url,
|
||||
json={'resources': resources}).json()
|
||||
return out
|
||||
|
||||
|
||||
class ServiceInfo(base.Resource):
|
||||
|
||||
key = "service"
|
||||
|
||||
def __repr__(self):
|
||||
return "<Service %s>" % self._info
|
||||
|
||||
|
||||
class ServiceInfoManager(base.CrudManager):
|
||||
resource_class = ServiceInfo
|
||||
base_url = "/v1/info"
|
||||
key = "service"
|
||||
collection_key = "services"
|
||||
|
||||
|
||||
class ConfigInfoManager(base.Manager):
|
||||
base_url = "/v1/info/config"
|
||||
|
||||
def get_config(self):
|
||||
out = self.api.get(self.base_url).json()
|
||||
return out
|
||||
|
||||
@@ -15,23 +15,76 @@
|
||||
from cloudkittyclient.common import base
|
||||
|
||||
|
||||
class Service(base.Resource):
|
||||
key = 'service'
|
||||
class BaseAttributeMixin(object):
|
||||
def _validate_attribute(self, attribute):
|
||||
attr = getattr(self, attribute)
|
||||
if attr:
|
||||
kwargs = {attribute: attr}
|
||||
return kwargs
|
||||
|
||||
def __repr__(self):
|
||||
return "<hashmap.Service %s>" % self._info
|
||||
def _get_resource(self, mgr, attribute):
|
||||
kwargs = self._validate_attribute(attribute)
|
||||
if kwargs:
|
||||
return mgr(client=self.manager.client).get(**kwargs)
|
||||
|
||||
def _get_resources(self, mgr, attribute):
|
||||
kwargs = self._validate_attribute(attribute)
|
||||
if kwargs:
|
||||
try:
|
||||
return mgr(client=self.manager.client).findall(**kwargs)
|
||||
except Exception:
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
class ServiceMixin(BaseAttributeMixin):
|
||||
@property
|
||||
def service(self):
|
||||
return self._get_resource(ServiceManager, 'service_id')
|
||||
|
||||
|
||||
class FieldMixin(BaseAttributeMixin):
|
||||
@property
|
||||
def field(self):
|
||||
return self._get_resource(FieldManager, 'field_id')
|
||||
|
||||
|
||||
class GroupMixin(BaseAttributeMixin):
|
||||
@property
|
||||
def group(self):
|
||||
return self._get_resource(GroupManager, 'group_id')
|
||||
|
||||
|
||||
class FieldsMixin(BaseAttributeMixin):
|
||||
attribute = ''
|
||||
|
||||
@property
|
||||
def fields(self):
|
||||
return FieldManager(client=self.manager.client).findall(
|
||||
service_id=self.service_id
|
||||
)
|
||||
return self._get_resources(FieldManager, self.attribute)
|
||||
|
||||
|
||||
class MappingsMixin(BaseAttributeMixin):
|
||||
attribute = ''
|
||||
|
||||
@property
|
||||
def mappings(self):
|
||||
return MappingManager(client=self.manager.client).findall(
|
||||
service_id=self.service_id
|
||||
)
|
||||
return self._get_resources(MappingManager, self.attribute)
|
||||
|
||||
|
||||
class ThresholdsMixin(BaseAttributeMixin):
|
||||
attribute = ''
|
||||
|
||||
@property
|
||||
def thresholds(self):
|
||||
return self._get_resources(ThresholdManager, self.attribute)
|
||||
|
||||
|
||||
class Service(base.Resource, FieldsMixin, MappingsMixin, ThresholdsMixin):
|
||||
key = 'service'
|
||||
attribute = 'service_id'
|
||||
|
||||
def __repr__(self):
|
||||
return "<hashmap.Service %s>" % self._info
|
||||
|
||||
|
||||
class ServiceManager(base.CrudManager):
|
||||
@@ -41,18 +94,13 @@ class ServiceManager(base.CrudManager):
|
||||
collection_key = 'services'
|
||||
|
||||
|
||||
class Field(base.Resource):
|
||||
class Field(base.Resource, ServiceMixin, MappingsMixin, ThresholdsMixin):
|
||||
key = 'field'
|
||||
attribute = 'field_id'
|
||||
|
||||
def __repr__(self):
|
||||
return "<hashmap.Field %s>" % self._info
|
||||
|
||||
@property
|
||||
def service(self):
|
||||
return ServiceManager(client=self.manager.client).get(
|
||||
service_id=self.service_id
|
||||
)
|
||||
|
||||
|
||||
class FieldManager(base.CrudManager):
|
||||
resource_class = Field
|
||||
@@ -61,26 +109,12 @@ class FieldManager(base.CrudManager):
|
||||
collection_key = 'fields'
|
||||
|
||||
|
||||
class Mapping(base.Resource):
|
||||
class Mapping(base.Resource, ServiceMixin, FieldMixin, GroupMixin):
|
||||
key = 'mapping'
|
||||
|
||||
def __repr__(self):
|
||||
return "<hashmap.Mapping %s>" % self._info
|
||||
|
||||
@property
|
||||
def service(self):
|
||||
return ServiceManager(client=self.manager.client).get(
|
||||
service_id=self.service_id
|
||||
)
|
||||
|
||||
@property
|
||||
def field(self):
|
||||
if self.field_id is None:
|
||||
return None
|
||||
return FieldManager(client=self.manager.client).get(
|
||||
service_id=self.service_id
|
||||
)
|
||||
|
||||
|
||||
class MappingManager(base.CrudManager):
|
||||
resource_class = Mapping
|
||||
@@ -89,8 +123,9 @@ class MappingManager(base.CrudManager):
|
||||
collection_key = 'mappings'
|
||||
|
||||
|
||||
class Group(base.Resource):
|
||||
class Group(base.Resource, MappingsMixin, ThresholdsMixin):
|
||||
key = 'group'
|
||||
attribute = 'group_id'
|
||||
|
||||
def __repr__(self):
|
||||
return "<hashmap.Group %s>" % self._info
|
||||
@@ -112,7 +147,7 @@ class GroupManager(base.CrudManager):
|
||||
return self._delete(url)
|
||||
|
||||
|
||||
class Threshold(base.Resource):
|
||||
class Threshold(base.Resource, ServiceMixin, FieldMixin, GroupMixin):
|
||||
key = 'threshold'
|
||||
|
||||
def __repr__(self):
|
||||
@@ -124,9 +159,3 @@ class ThresholdManager(base.CrudManager):
|
||||
base_url = '/v1/rating/module_config/hashmap'
|
||||
key = 'threshold'
|
||||
collection_key = 'thresholds'
|
||||
|
||||
def group(self, threshold_id):
|
||||
url = ('%(base_url)s/thresholds/%(threshold_id)s/group' %
|
||||
{'base_url': self.base_url, 'threshold_id': threshold_id})
|
||||
out = self._get(url)
|
||||
return out
|
||||
|
||||
@@ -17,6 +17,7 @@ import functools
|
||||
|
||||
from oslo_utils import strutils
|
||||
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.common import utils
|
||||
from cloudkittyclient import exc
|
||||
|
||||
@@ -44,8 +45,8 @@ def do_hashmap_service_list(cc, args={}):
|
||||
"""List services."""
|
||||
try:
|
||||
services = cc.hashmap.services.list()
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Services not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Services not found.')
|
||||
else:
|
||||
field_labels = ['Name', 'Service id']
|
||||
fields = ['name', 'service_id']
|
||||
@@ -60,8 +61,8 @@ def do_hashmap_service_delete(cc, args={}):
|
||||
"""Delete a service."""
|
||||
try:
|
||||
cc.hashmap.services.delete(service_id=args.service_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Service not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Service not found: %s' % args.service_id)
|
||||
|
||||
|
||||
@utils.arg('-n', '--name',
|
||||
@@ -89,11 +90,12 @@ def do_hashmap_field_create(cc, args={}):
|
||||
help='Service id',
|
||||
required=True)
|
||||
def do_hashmap_field_list(cc, args={}):
|
||||
"""Create a field."""
|
||||
"""List fields."""
|
||||
try:
|
||||
created_field = cc.hashmap.fields.list(service_id=args.service_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Fields not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Fields not found in service: %s'
|
||||
% args.service_id)
|
||||
else:
|
||||
field_labels = ['Name', 'Field id']
|
||||
fields = ['name', 'field_id']
|
||||
@@ -108,28 +110,41 @@ def do_hashmap_field_delete(cc, args={}):
|
||||
"""Delete a field."""
|
||||
try:
|
||||
cc.hashmap.fields.delete(field_id=args.field_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Field not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Field not found: %s' % args.field_id)
|
||||
|
||||
|
||||
def common_hashmap_mapping_arguments(create=False):
|
||||
def _wrapper(func):
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Mapping cost',
|
||||
required=create)
|
||||
@utils.arg('-v', '--value',
|
||||
help='Mapping value',
|
||||
required=False)
|
||||
@utils.arg('-t', '--type',
|
||||
help='Mapping type (flat, rate)',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@utils.arg('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
@functools.wraps(func)
|
||||
def _wrapped(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
return _wrapped
|
||||
return _wrapper
|
||||
|
||||
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Mapping cost',
|
||||
required=True)
|
||||
@utils.arg('-v', '--value',
|
||||
help='Mapping value',
|
||||
required=False)
|
||||
@utils.arg('-t', '--type',
|
||||
help='Mapping type (flat, rate)',
|
||||
required=False)
|
||||
@utils.arg('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
@utils.arg('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@common_hashmap_mapping_arguments(create=True)
|
||||
def do_hashmap_mapping_create(cc, args={}):
|
||||
"""Create a mapping."""
|
||||
arg_to_field_mapping = {
|
||||
@@ -139,6 +154,7 @@ def do_hashmap_mapping_create(cc, args={}):
|
||||
'service_id': 'service_id',
|
||||
'field_id': 'field_id',
|
||||
'group_id': 'group_id',
|
||||
'project_id': 'tenant_id',
|
||||
}
|
||||
fields = {}
|
||||
for k, v in vars(args).items():
|
||||
@@ -152,18 +168,7 @@ def do_hashmap_mapping_create(cc, args={}):
|
||||
@utils.arg('-m', '--mapping-id',
|
||||
help='Mapping id',
|
||||
required=True)
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Mapping cost',
|
||||
required=False)
|
||||
@utils.arg('-v', '--value',
|
||||
help='Mapping value',
|
||||
required=False)
|
||||
@utils.arg('-t', '--type',
|
||||
help='Mapping type (flat, rate)',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@common_hashmap_mapping_arguments()
|
||||
def do_hashmap_mapping_update(cc, args={}):
|
||||
"""Update a mapping."""
|
||||
arg_to_field_mapping = {
|
||||
@@ -172,11 +177,12 @@ def do_hashmap_mapping_update(cc, args={}):
|
||||
'value': 'value',
|
||||
'type': 'type',
|
||||
'group_id': 'group_id',
|
||||
'project_id': 'tenant_id',
|
||||
}
|
||||
try:
|
||||
mapping = cc.hashmap.mappings.get(mapping_id=args.mapping_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Modules not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Mapping not found: %s' % args.mapping_id)
|
||||
for k, v in vars(args).items():
|
||||
if k in arg_to_field_mapping:
|
||||
if v is not None:
|
||||
@@ -193,23 +199,29 @@ def do_hashmap_mapping_update(cc, args={}):
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@utils.arg('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
def do_hashmap_mapping_list(cc, args={}):
|
||||
"""List mappings."""
|
||||
if args.service_id is None and args.field_id is None:
|
||||
raise exc.CommandError("Provide either service-id or field-id")
|
||||
if (args.group_id is None and
|
||||
args.service_id is None and args.field_id is None):
|
||||
raise exc.CommandError("Provide either group-id, service-id or "
|
||||
"field-id")
|
||||
try:
|
||||
mappings = cc.hashmap.mappings.list(service_id=args.service_id,
|
||||
field_id=args.field_id,
|
||||
group_id=args.group_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Mapping not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Mappings not found for field: %s'
|
||||
% args.field_id)
|
||||
else:
|
||||
field_labels = ['Mapping id', 'Value', 'Cost',
|
||||
'Type', 'Field id',
|
||||
'Service id', 'Group id']
|
||||
'Service id', 'Group id', 'Tenant id']
|
||||
fields = ['mapping_id', 'value', 'cost',
|
||||
'type', 'field_id',
|
||||
'service_id', 'group_id']
|
||||
'service_id', 'group_id', 'tenant_id']
|
||||
utils.print_list(mappings, fields, field_labels,
|
||||
sortby=0)
|
||||
|
||||
@@ -221,7 +233,7 @@ def do_hashmap_mapping_delete(cc, args={}):
|
||||
"""Delete a mapping."""
|
||||
try:
|
||||
cc.hashmap.mappings.delete(mapping_id=args.mapping_id)
|
||||
except exc.HTTPNotFound:
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Mapping not found: %s' % args.mapping_id)
|
||||
|
||||
|
||||
@@ -246,8 +258,8 @@ def do_hashmap_group_list(cc, args={}):
|
||||
"""List groups."""
|
||||
try:
|
||||
groups = cc.hashmap.groups.list()
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Mapping not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Groups not found.')
|
||||
else:
|
||||
field_labels = ['Name',
|
||||
'Group id']
|
||||
@@ -268,37 +280,51 @@ def do_hashmap_group_delete(cc, args={}):
|
||||
try:
|
||||
cc.hashmap.groups.delete(group_id=args.group_id,
|
||||
recursive=args.recursive)
|
||||
except exc.HTTPNotFound:
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Group not found: %s' % args.group_id)
|
||||
|
||||
|
||||
@utils.arg('-l', '--level',
|
||||
help='Threshold level',
|
||||
required=True)
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Threshold cost',
|
||||
required=True)
|
||||
@utils.arg('-m', '--map-type',
|
||||
help='Threshold type (flat, rate)',
|
||||
required=False)
|
||||
def common_hashmap_threshold_arguments(create=False):
|
||||
def _wrapper(func):
|
||||
@utils.arg('-l', '--level',
|
||||
help='Threshold level',
|
||||
required=create)
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Threshold cost',
|
||||
required=create)
|
||||
@utils.arg('-t', '--type',
|
||||
help='Threshold type (flat, rate)',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@utils.arg('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
@functools.wraps(func)
|
||||
def _wrapped(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
return _wrapped
|
||||
return _wrapper
|
||||
|
||||
|
||||
@utils.arg('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
@utils.arg('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@common_hashmap_threshold_arguments(create=True)
|
||||
def do_hashmap_threshold_create(cc, args={}):
|
||||
"""Create a mapping."""
|
||||
arg_to_field_mapping = {
|
||||
'level': 'level',
|
||||
'cost': 'cost',
|
||||
'map_type': 'map_type',
|
||||
'type': 'type',
|
||||
'service_id': 'service_id',
|
||||
'field_id': 'field_id',
|
||||
'group_id': 'group_id',
|
||||
'project_id': 'tenant_id',
|
||||
}
|
||||
fields = {}
|
||||
for k, v in vars(args).items():
|
||||
@@ -309,34 +335,24 @@ def do_hashmap_threshold_create(cc, args={}):
|
||||
utils.print_dict(out.to_dict())
|
||||
|
||||
|
||||
@utils.arg('-t', '--threshold-id',
|
||||
@utils.arg('-i', '--threshold-id',
|
||||
help='Threshold id',
|
||||
required=True)
|
||||
@utils.arg('-l', '--level',
|
||||
help='Threshold level',
|
||||
required=False)
|
||||
@utils.arg('-c', '--cost',
|
||||
help='Threshold cost',
|
||||
required=False)
|
||||
@utils.arg('-m', '--map-type',
|
||||
help='Threshold type (flat, rate)',
|
||||
required=False)
|
||||
@utils.arg('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
@common_hashmap_threshold_arguments()
|
||||
def do_hashmap_threshold_update(cc, args={}):
|
||||
"""Update a threshold."""
|
||||
arg_to_field_mapping = {
|
||||
'threshold_id': 'threshold_id',
|
||||
'cost': 'cost',
|
||||
'level': 'level',
|
||||
'map_type': 'map_type',
|
||||
'type': 'type',
|
||||
'group_id': 'group_id',
|
||||
'project_id': 'tenant_id',
|
||||
}
|
||||
try:
|
||||
threshold = cc.hashmap.thresholds.get(threshold_id=args.threshold_id)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Modules not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Threshold not found: %s' % args.threshold_id)
|
||||
for k, v in vars(args).items():
|
||||
if k in arg_to_field_mapping:
|
||||
if v is not None:
|
||||
@@ -357,6 +373,9 @@ def do_hashmap_threshold_update(cc, args={}):
|
||||
type=_bool_strict, metavar='{True,False}',
|
||||
help='If True, list only orhpaned thresholds',
|
||||
required=False)
|
||||
@utils.arg('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
def do_hashmap_threshold_list(cc, args={}):
|
||||
"""List thresholds."""
|
||||
if (args.group_id is None and
|
||||
@@ -368,48 +387,48 @@ def do_hashmap_threshold_list(cc, args={}):
|
||||
field_id=args.field_id,
|
||||
group_id=args.group_id,
|
||||
no_group=args.no_group)
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Threshold not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Thresholds not found')
|
||||
else:
|
||||
field_labels = ['Threshold id', 'Level', 'Cost',
|
||||
'Type', 'Field id',
|
||||
'Service id', 'Group id']
|
||||
'Service id', 'Group id', 'Tenant id']
|
||||
fields = ['threshold_id', 'level', 'cost',
|
||||
'map_type', 'field_id',
|
||||
'service_id', 'group_id']
|
||||
'type', 'field_id',
|
||||
'service_id', 'group_id', 'tenant_id']
|
||||
utils.print_list(thresholds, fields, field_labels, sortby=0)
|
||||
|
||||
|
||||
@utils.arg('-t', '--threshold-id',
|
||||
@utils.arg('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
def do_hashmap_threshold_delete(cc, args={}):
|
||||
"""Delete a threshold."""
|
||||
try:
|
||||
cc.hashmap.thresholds.delete(threshold_id=args.threshold_id)
|
||||
except exc.HTTPNotFound:
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Threshold not found: %s' % args.threshold_id)
|
||||
|
||||
|
||||
@utils.arg('-t', '--threshold-id',
|
||||
@utils.arg('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
def do_hashmap_threshold_get(cc, args={}):
|
||||
"""Get a threshold."""
|
||||
try:
|
||||
threshold = cc.hashmap.thresholds.get(threshold_id=args.threshold_id)
|
||||
except exc.HTTPNotFound:
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Threshold not found: %s' % args.threshold_id)
|
||||
utils.print_dict(threshold.to_dict())
|
||||
|
||||
|
||||
@utils.arg('-t', '--threshold-id',
|
||||
@utils.arg('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
def do_hashmap_threshold_group(cc, args={}):
|
||||
"""Get a threshold group."""
|
||||
try:
|
||||
threshold = cc.hashmap.thresholds.group(threshold_id=args.threshold_id)
|
||||
except exc.HTTPNotFound:
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Threshold not found: %s' % args.threshold_id)
|
||||
utils.print_dict(threshold.to_dict())
|
||||
|
||||
355
cloudkittyclient/v1/rating/hashmap/shell_cli.py
Normal file
355
cloudkittyclient/v1/rating/hashmap/shell_cli.py
Normal file
@@ -0,0 +1,355 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
# 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 functools
|
||||
|
||||
from osc_lib.command import command
|
||||
from oslo_utils import strutils
|
||||
|
||||
from cloudkittyclient.v1.rating.hashmap import shell
|
||||
|
||||
|
||||
_bool_strict = functools.partial(strutils.bool_from_string, strict=True)
|
||||
|
||||
|
||||
class CliHashmapServiceCreate(command.Command):
|
||||
"""Create a service."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapServiceCreate, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Service name',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_service_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapServiceList(command.Command):
|
||||
"""List services."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_service_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapServiceDelete(command.Command):
|
||||
"""Delete a service."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapServiceDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_service_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapFieldCreate(command.Command):
|
||||
"""Create a field."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapFieldCreate, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=True)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Field name',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_field_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapFieldList(command.Command):
|
||||
"""List fields."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapFieldList, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_field_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapFieldDelete(command.Command):
|
||||
"""Delete a field."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapFieldDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_field_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapMappingCommon(command.Command):
|
||||
def get_parser(self, prog_name, cost=False):
|
||||
parser = super(CliHashmapMappingCommon, self).get_parser(prog_name)
|
||||
parser.add_argument('-c', '--cost',
|
||||
help='Mapping Cost',
|
||||
required=cost)
|
||||
parser.add_argument('-v', '--value',
|
||||
help='Mapping Value',
|
||||
required=False)
|
||||
parser.add_argument('-t', '--type',
|
||||
help='Mapping type (flat, rate)',
|
||||
required=False)
|
||||
parser.add_argument('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
parser.add_argument('-p', '--project-id',
|
||||
help='Project/Tenant id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
|
||||
class CliHashmapMappingCreate(CliHashmapMappingCommon):
|
||||
"""Create a mapping."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapMappingCreate, self).get_parser(prog_name,
|
||||
cost=True)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
parser.add_argument('-f', '--field-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_mapping_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapMappingUpdate(CliHashmapMappingCommon):
|
||||
"""Update a mapping."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapMappingUpdate, self).get_parser(prog_name)
|
||||
parser.add_argument('-m', '--mapping-id',
|
||||
help='Mapping id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_mapping_update(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapMappingList(command.Command):
|
||||
"""List mappings."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapMappingList, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
parser.add_argument('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=False)
|
||||
parser.add_argument('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
parser.add_argument('-p', '--project-id',
|
||||
help='Project id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_mapping_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapMappingDelete(command.Command):
|
||||
"""Delete a mapping."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapMappingDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-m', '--mapping-id',
|
||||
help='Mapping id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_mapping_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapGroupCreate(command.Command):
|
||||
"""Create a group."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapGroupCreate, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Group name.',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_group_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapGroupList(command.Command):
|
||||
"""List groups."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_group_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapGroupDelete(command.Command):
|
||||
"""Delete a group."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapGroupDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-g', '--group-id',
|
||||
help='Group uuid',
|
||||
required=True)
|
||||
parser.add_argument('-r', '--recursive',
|
||||
help="""Delete the group's mappings.""",
|
||||
required=False,
|
||||
default=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_group_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdCommon(command.Command):
|
||||
def get_parser(self, prog_name, create=False):
|
||||
parser = super(CliHashmapThresholdCommon, self).get_parser(prog_name)
|
||||
parser.add_argument('-l', '--level',
|
||||
help='Threshold level',
|
||||
required=create)
|
||||
parser.add_argument('-c', '--cost',
|
||||
help='Threshold cost',
|
||||
required=create)
|
||||
parser.add_argument('-t', '--type',
|
||||
help='Threshold type',
|
||||
required=False)
|
||||
parser.add_argument('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
parser.add_argument('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
|
||||
class CliHashmapThresholdCreate(CliHashmapThresholdCommon):
|
||||
"""Create a threshold."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdCreate, self).get_parser(prog_name,
|
||||
create=True)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
parser.add_argument('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdUpdate(CliHashmapThresholdCommon):
|
||||
"""Update a threshold."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdUpdate, self).get_parser(prog_name)
|
||||
parser.add_argument('-i', '--threshold-id',
|
||||
help='Threshold id',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_update(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdList(command.Command):
|
||||
"""List thresholds."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdList, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-id',
|
||||
help='Service id',
|
||||
required=False)
|
||||
parser.add_argument('-f', '--field-id',
|
||||
help='Field id',
|
||||
required=False)
|
||||
parser.add_argument('-g', '--group-id',
|
||||
help='Group id',
|
||||
required=False)
|
||||
parser.add_argument('--no-group',
|
||||
type=_bool_strict, metavar='{True,False}',
|
||||
help='If True, list only orphaned thresholds',
|
||||
required=False)
|
||||
parser.add_argument('-p', '--project-id',
|
||||
help='Project/tenant id',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdDelete(command.Command):
|
||||
"""Delete a threshold."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdGet(command.Command):
|
||||
"""Get a threshold."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdGet, self).get_parser(prog_name)
|
||||
parser.add_argument('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliHashmapThresholdGroup(command.Command):
|
||||
"""Get a threshold group."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliHashmapThresholdGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('-i', '--threshold-id',
|
||||
help='Threshold uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_hashmap_threshold_group(ckclient, parsed_args)
|
||||
30
cloudkittyclient/v1/rating/pyscripts/__init__.py
Normal file
30
cloudkittyclient/v1/rating/pyscripts/__init__.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# Copyright 2015 Objectif Libre
|
||||
# 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.
|
||||
|
||||
from cloudkittyclient.common import base
|
||||
|
||||
|
||||
class Script(base.Resource):
|
||||
key = 'script'
|
||||
|
||||
def __repr__(self):
|
||||
return "<pyscripts.Script %s>" % self._info
|
||||
|
||||
|
||||
class ScriptManager(base.CrudManager):
|
||||
resource_class = Script
|
||||
base_url = '/v1/rating/module_config/pyscripts'
|
||||
key = 'script'
|
||||
collection_key = 'scripts'
|
||||
28
cloudkittyclient/v1/rating/pyscripts/client.py
Normal file
28
cloudkittyclient/v1/rating/pyscripts/client.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright 2015 Objectif Libre
|
||||
# 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.
|
||||
|
||||
from cloudkittyclient.v1.rating import pyscripts
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Client for the PyScripts v1 API.
|
||||
|
||||
:param http_client: A http client.
|
||||
"""
|
||||
|
||||
def __init__(self, http_client):
|
||||
"""Initialize a new client for the PyScripts v1 API."""
|
||||
self.http_client = http_client
|
||||
self.scripts = pyscripts.ScriptManager(self.http_client)
|
||||
31
cloudkittyclient/v1/rating/pyscripts/extension.py
Normal file
31
cloudkittyclient/v1/rating/pyscripts/extension.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copyright 2015 Objectif Libre
|
||||
# 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.
|
||||
|
||||
from cloudkittyclient.v1.rating.pyscripts import client
|
||||
from cloudkittyclient.v1.rating.pyscripts import shell
|
||||
|
||||
|
||||
class Extension(object):
|
||||
"""PyScripts extension.
|
||||
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_client(http_client):
|
||||
return client.Client(http_client)
|
||||
|
||||
@staticmethod
|
||||
def get_shell():
|
||||
return shell
|
||||
117
cloudkittyclient/v1/rating/pyscripts/shell.py
Normal file
117
cloudkittyclient/v1/rating/pyscripts/shell.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# Copyright 2015 Objectif Libre
|
||||
# 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 functools
|
||||
|
||||
from oslo_utils import strutils
|
||||
import six
|
||||
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.common import utils
|
||||
from cloudkittyclient import exc
|
||||
|
||||
_bool_strict = functools.partial(strutils.bool_from_string, strict=True)
|
||||
|
||||
|
||||
@utils.arg('-n', '--name',
|
||||
help='Script name',
|
||||
required=True)
|
||||
@utils.arg('-f', '--file',
|
||||
help='Script file',
|
||||
required=False)
|
||||
def do_pyscripts_script_create(cc, args={}):
|
||||
"""Create a script."""
|
||||
script_args = {'name': args.name}
|
||||
if args.file:
|
||||
with open(args.file) as fp:
|
||||
script_args['data'] = fp.read()
|
||||
out = cc.pyscripts.scripts.create(**script_args)
|
||||
utils.print_dict(out.to_dict())
|
||||
|
||||
|
||||
@utils.arg('-d', '--show-data',
|
||||
help='Show data in the listing',
|
||||
required=False,
|
||||
default=False)
|
||||
def do_pyscripts_script_list(cc, args={}):
|
||||
"""List scripts."""
|
||||
request_args = {}
|
||||
if not args.show_data:
|
||||
request_args['no_data'] = True
|
||||
scripts = cc.pyscripts.scripts.list(**request_args)
|
||||
field_labels = ['Name', 'Script id', 'Data', 'Checksum']
|
||||
fields = ['name', 'script_id', 'data', 'checksum']
|
||||
utils.print_list(scripts,
|
||||
fields,
|
||||
field_labels,
|
||||
sortby=0)
|
||||
|
||||
|
||||
@utils.arg('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
def do_pyscripts_script_get(cc, args={}):
|
||||
"""Get script."""
|
||||
try:
|
||||
script = cc.pyscripts.scripts.get(script_id=args.script_id)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Script not found: %s' % args.script_id)
|
||||
utils.print_dict(script.to_dict())
|
||||
|
||||
|
||||
@utils.arg('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
def do_pyscripts_script_get_data(cc, args={}):
|
||||
"""Get script data."""
|
||||
try:
|
||||
script = cc.pyscripts.scripts.get(script_id=args.script_id)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Script not found: %s' % args.script_id)
|
||||
six.print_(script.data)
|
||||
|
||||
|
||||
@utils.arg('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
def do_pyscripts_script_delete(cc, args={}):
|
||||
"""Delete a script."""
|
||||
try:
|
||||
cc.pyscripts.scripts.delete(script_id=args.script_id)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Script not found: %s' % args.script_id)
|
||||
|
||||
|
||||
@utils.arg('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
@utils.arg('-f', '--file',
|
||||
help='Script file',
|
||||
required=True)
|
||||
def do_pyscripts_script_update(cc, args={}):
|
||||
"""Update a mapping."""
|
||||
excluded_fields = [
|
||||
'checksum',
|
||||
]
|
||||
with open(args.file) as fp:
|
||||
content = fp.read()
|
||||
try:
|
||||
script = cc.pyscripts.scripts.get(script_id=args.script_id)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Script not found: %s' % args.script_id)
|
||||
script_dict = script.to_dict()
|
||||
for field in excluded_fields:
|
||||
del script_dict[field]
|
||||
script_dict['data'] = content
|
||||
cc.pyscripts.scripts.update(**script_dict)
|
||||
115
cloudkittyclient/v1/rating/pyscripts/shell_cli.py
Normal file
115
cloudkittyclient/v1/rating/pyscripts/shell_cli.py
Normal file
@@ -0,0 +1,115 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
# 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 functools
|
||||
|
||||
from osc_lib.command import command
|
||||
from oslo_utils import strutils
|
||||
|
||||
from cloudkittyclient.v1.rating.pyscripts import shell
|
||||
|
||||
|
||||
_bool_strict = functools.partial(strutils.bool_from_string, strict=True)
|
||||
|
||||
|
||||
class CliPyScriptCreate(command.Command):
|
||||
"""Create a script."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptCreate, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Script name',
|
||||
required=True)
|
||||
parser.add_argument('-f', '--file',
|
||||
help='Script file',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_create(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliPyScriptList(command.Command):
|
||||
"""List scripts."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptList, self).get_parser(prog_name)
|
||||
parser.add_argument('-d', '--show-data',
|
||||
help='Show data in the listing',
|
||||
required=False,
|
||||
default=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliPyScriptGet(command.Command):
|
||||
"""Get script."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptGet, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliPyScriptGetData(command.Command):
|
||||
"""Get script data."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptGetData, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_get_data(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliPyScriptDelete(command.Command):
|
||||
"""Get script data."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptDelete, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_delete(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliPyScriptUpdate(command.Command):
|
||||
"""Update a script."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliPyScriptUpdate, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--script-id',
|
||||
help='Script uuid',
|
||||
required=True)
|
||||
parser.add_argument('-f', '--file',
|
||||
help='Script file',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_pyscripts_script_update(ckclient, parsed_args)
|
||||
@@ -15,26 +15,67 @@
|
||||
from cloudkittyclient.common import base
|
||||
|
||||
|
||||
class ReportResult(base.Resource):
|
||||
class ReportSummary(base.Resource):
|
||||
|
||||
key = 'report'
|
||||
key = 'summary'
|
||||
|
||||
def __init(self, tenant_id=None, res_type=None, begin=None,
|
||||
end=None, rate=None):
|
||||
self.tenant_id = tenant_id
|
||||
self.res_type = res_type
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
self.rate = rate
|
||||
|
||||
def __repr__(self):
|
||||
return "<Report %s>" % self._info
|
||||
return "<Summary %s" % self._info
|
||||
|
||||
|
||||
class ReportManager(base.Manager):
|
||||
class ReportManager(base.CrudManager):
|
||||
|
||||
base_url = "/v1/report"
|
||||
|
||||
def list_tenants(self):
|
||||
return self.client.get(self.base_url + "/tenants").json()
|
||||
|
||||
def get_total(self, tenant_id, begin=None, end=None):
|
||||
url = self.base_url + "/total?tenant_id=%s" % tenant_id
|
||||
filter = [url]
|
||||
def get_total(self, tenant_id=None, begin=None, end=None,
|
||||
service=None, all_tenants=False):
|
||||
url = self.base_url + "/total"
|
||||
filters = list()
|
||||
if tenant_id:
|
||||
filters.append("tenant_id=%s" % tenant_id)
|
||||
if begin:
|
||||
filter.append("begin=%s" % begin.isoformat())
|
||||
filters.append("begin=%s" % begin.isoformat())
|
||||
if end:
|
||||
filter.append("end=%s" % end.isoformat())
|
||||
return self.client.get("&".join(filter)).json()
|
||||
filters.append("end=%s" % end.isoformat())
|
||||
if service:
|
||||
filters.append("service=%s" % service)
|
||||
if all_tenants:
|
||||
filters.append("all_tenants=%s" % all_tenants)
|
||||
if filters:
|
||||
url += "?%s" % ('&'.join(filters))
|
||||
return self.client.get(url).json()
|
||||
|
||||
|
||||
class ReportSummaryManager(ReportManager):
|
||||
|
||||
resource_class = ReportSummary
|
||||
key = 'summary'
|
||||
collection_key = "summary"
|
||||
|
||||
def get_summary(self, tenant_id=None, begin=None, end=None,
|
||||
service=None, groupby=None, all_tenants=False):
|
||||
kwargs = {}
|
||||
if tenant_id:
|
||||
kwargs['tenant_id'] = tenant_id
|
||||
if begin:
|
||||
kwargs['begin'] = begin.isoformat()
|
||||
if end:
|
||||
kwargs['end'] = end.isoformat()
|
||||
if service:
|
||||
kwargs['service'] = service
|
||||
if groupby:
|
||||
kwargs['groupby'] = groupby
|
||||
if all_tenants:
|
||||
kwargs['all_tenants'] = all_tenants
|
||||
return super(ReportManager, self).list(**kwargs)
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
# 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 __future__ import print_function
|
||||
|
||||
from cloudkittyclient.common import utils
|
||||
|
||||
|
||||
def do_report_tenant_list(cc, args):
|
||||
"""List tenant report."""
|
||||
tenants = cc.reports.list_tenants()
|
||||
out_table = utils.prettytable.PrettyTable()
|
||||
out_table.add_column("Tenant UUID", tenants)
|
||||
@@ -26,17 +28,69 @@ def do_report_tenant_list(cc, args):
|
||||
|
||||
@utils.arg('-t', '--tenant-id',
|
||||
help='Tenant id',
|
||||
required=False, dest='total_tenant_id')
|
||||
required=False,
|
||||
dest='total_tenant_id')
|
||||
@utils.arg('-b', '--begin',
|
||||
help='Starting date/time (YYYY-MM-DDTHH:MM:SS)',
|
||||
required=False)
|
||||
@utils.arg('-e', '--end',
|
||||
help='Ending date/time (YYYY-MM-DDTHH:MM:SS)',
|
||||
required=False)
|
||||
@utils.arg('-s', '--service',
|
||||
help='Service Type',
|
||||
required=False)
|
||||
@utils.arg('-a', '--all-tenants',
|
||||
default=False,
|
||||
action="store_true",
|
||||
dest='all_tenants',
|
||||
help='Allows to get total from all tenants'
|
||||
' (admin only).')
|
||||
def do_total_get(cc, args):
|
||||
"""Get total reports."""
|
||||
begin = utils.iso2dt(args.begin) if args.begin else None
|
||||
end = utils.iso2dt(args.end) if args.end else None
|
||||
total = cc.reports.get_total(tenant_id=args.total_tenant_id,
|
||||
begin=begin,
|
||||
end=end,
|
||||
service=args.service,
|
||||
all_tenants=args.all_tenants)
|
||||
utils.print_dict({'Total': total or 0.0})
|
||||
|
||||
|
||||
@utils.arg('-t', '--tenant-id',
|
||||
help='Tenant id',
|
||||
required=False,
|
||||
dest='summary_tenant_id')
|
||||
@utils.arg('-b', '--begin',
|
||||
help='Begin timestamp',
|
||||
required=False)
|
||||
@utils.arg('-e', '--end',
|
||||
help='End timestamp',
|
||||
required=False)
|
||||
def do_total_get(cc, args):
|
||||
@utils.arg('-s', '--service',
|
||||
help='Service Type',
|
||||
required=False)
|
||||
@utils.arg('-g', '--groupby',
|
||||
help=('Fields to groupby, separated by commas '
|
||||
'if multiple, now support res_type,tenant_id'),
|
||||
required=False)
|
||||
@utils.arg('-a', '--all-tenants',
|
||||
default=False,
|
||||
action="store_true",
|
||||
dest='all_tenants',
|
||||
help='Allows to get summary from all tenants'
|
||||
' (admin only).')
|
||||
def do_summary_get(cc, args):
|
||||
"""Get summary report."""
|
||||
begin = utils.ts2dt(args.begin) if args.begin else None
|
||||
end = utils.ts2dt(args.end) if args.end else None
|
||||
total = cc.reports.get_total(args.total_tenant_id,
|
||||
begin=begin,
|
||||
end=end)
|
||||
utils.print_dict({'Total': total or 0.0})
|
||||
summarys = cc.reportsummary.get_summary(tenant_id=args.summary_tenant_id,
|
||||
begin=begin,
|
||||
end=end,
|
||||
service=args.service,
|
||||
groupby=args.groupby,
|
||||
all_tenants=args.all_tenants)
|
||||
field_labels = ['Tenant ID', 'Resource Type', 'Rate',
|
||||
'Begin Time', 'End Time']
|
||||
fields = ['tenant_id', 'res_type', 'rate', 'begin', 'end']
|
||||
utils.print_list(summarys, fields, field_labels, sortby=0)
|
||||
|
||||
88
cloudkittyclient/v1/report/shell_cli.py
Normal file
88
cloudkittyclient/v1/report/shell_cli.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
#
|
||||
# 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.
|
||||
|
||||
from osc_lib.command import command
|
||||
|
||||
from cloudkittyclient.v1.report import shell
|
||||
|
||||
|
||||
class CliTotalGet(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliTotalGet, self).get_parser(prog_name)
|
||||
parser.add_argument('-t', '--tenant-id',
|
||||
help='Tenant id',
|
||||
required=False,
|
||||
dest='total_tenant_id')
|
||||
parser.add_argument('-b', '--begin',
|
||||
help='Begin timestamp',
|
||||
required=False)
|
||||
parser.add_argument('-e', '--end',
|
||||
help='End timestamp',
|
||||
required=False)
|
||||
parser.add_argument('-s', '--service',
|
||||
help='Service Type',
|
||||
required=False)
|
||||
parser.add_argument('-a', '--all-tenants',
|
||||
default=False,
|
||||
action="store_true",
|
||||
dest='all_tenants',
|
||||
help='Allows to get total from all tenants'
|
||||
' (admin only).')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_total_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliReportTenantList(command.Command):
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_report_tenant_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliSummaryGet(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliSummaryGet, self).get_parser(prog_name)
|
||||
parser.add_argument('-t', '--tenant-id',
|
||||
help='Tenant id',
|
||||
required=False,
|
||||
dest='summary_tenant_id')
|
||||
parser.add_argument('-b', '--begin',
|
||||
help='Begin timestamp',
|
||||
required=False)
|
||||
parser.add_argument('-e', '--end',
|
||||
help='End timestamp',
|
||||
required=False)
|
||||
parser.add_argument('-s', '--service',
|
||||
help='Service Type',
|
||||
required=False)
|
||||
parser.add_argument('-g', '--groupby',
|
||||
help=('Fields to groupby, separated by '
|
||||
'commas if multiple, now support '
|
||||
'res_type,tenant_id'),
|
||||
required=False)
|
||||
parser.add_argument('-a', '--all-tenants',
|
||||
default=False,
|
||||
action="store_true",
|
||||
dest='all_tenants',
|
||||
help='Allows to get summary from all tenants'
|
||||
' (admin only).')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_summary_get(ckclient, parsed_args)
|
||||
@@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from cloudkittyclient.apiclient import exceptions
|
||||
from cloudkittyclient.common import utils
|
||||
from cloudkittyclient import exc
|
||||
|
||||
@@ -21,11 +22,11 @@ def do_module_list(cc, args):
|
||||
'''List the samples for this meters.'''
|
||||
try:
|
||||
modules = cc.modules.list()
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Modules not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Modules not found')
|
||||
else:
|
||||
field_labels = ['Module', 'Enabled']
|
||||
fields = ['module_id', 'enabled']
|
||||
field_labels = ['Module', 'Enabled', 'Priority']
|
||||
fields = ['module_id', 'enabled', 'priority']
|
||||
utils.print_list(modules, fields, field_labels,
|
||||
sortby=0)
|
||||
|
||||
@@ -38,11 +39,11 @@ def do_module_enable(cc, args):
|
||||
try:
|
||||
module = cc.modules.get(module_id=args.name)
|
||||
module.enable()
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Modules not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Module not found: %s' % args.name)
|
||||
else:
|
||||
field_labels = ['Module', 'Enabled']
|
||||
fields = ['module_id', 'enabled']
|
||||
field_labels = ['Module', 'Enabled', 'Priority']
|
||||
fields = ['module_id', 'enabled', 'priority']
|
||||
modules = [cc.modules.get(module_id=args.name)]
|
||||
utils.print_list(modules, fields, field_labels,
|
||||
sortby=0)
|
||||
@@ -56,11 +57,58 @@ def do_module_disable(cc, args):
|
||||
try:
|
||||
module = cc.modules.get(module_id=args.name)
|
||||
module.disable()
|
||||
except exc.HTTPNotFound:
|
||||
raise exc.CommandError('Modules not found: %s' % args.counter_name)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Module not found: %s' % args.name)
|
||||
else:
|
||||
field_labels = ['Module', 'Enabled']
|
||||
fields = ['module_id', 'enabled']
|
||||
field_labels = ['Module', 'Enabled', 'Priority']
|
||||
fields = ['module_id', 'enabled', 'priority']
|
||||
modules = [cc.modules.get(module_id=args.name)]
|
||||
utils.print_list(modules, fields, field_labels,
|
||||
sortby=0)
|
||||
|
||||
|
||||
@utils.arg('-n', '--name',
|
||||
help='Module name',
|
||||
required=True)
|
||||
@utils.arg('-p', '--priority',
|
||||
help='Module priority',
|
||||
required=True)
|
||||
def do_module_set_priority(cc, args):
|
||||
'''Set module priority.'''
|
||||
try:
|
||||
module = cc.modules.get(module_id=args.name)
|
||||
module.set_priority(args.priority)
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Module not found: %s' % args.name)
|
||||
else:
|
||||
field_labels = ['Module', 'Enabled', 'Priority']
|
||||
fields = ['module_id', 'enabled', 'priority']
|
||||
modules = [cc.modules.get(module_id=args.name)]
|
||||
utils.print_list(modules, fields, field_labels,
|
||||
sortby=0)
|
||||
|
||||
|
||||
def do_info_config_get(cc, args):
|
||||
'''Get cloudkitty configuration.'''
|
||||
utils.print_dict(cc.config.get_config(), dict_property="Section")
|
||||
|
||||
|
||||
@utils.arg('-n', '--name',
|
||||
help='Service name',
|
||||
required=False)
|
||||
def do_info_service_get(cc, args):
|
||||
'''Get service info.'''
|
||||
if args.name:
|
||||
try:
|
||||
services_info = [cc.service_info.get(service_id=args.name)]
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('Service not found: %s' % args.name)
|
||||
else:
|
||||
try:
|
||||
services_info = cc.service_info.list()
|
||||
except exceptions.NotFound:
|
||||
raise exc.CommandError('ServiceInfo not found')
|
||||
|
||||
field_labels = ['Service', 'Metadata', 'Unit']
|
||||
fields = ['service_id', 'metadata', 'unit']
|
||||
utils.print_list(services_info, fields, field_labels, sortby=0)
|
||||
|
||||
91
cloudkittyclient/v1/shell_cli.py
Normal file
91
cloudkittyclient/v1/shell_cli.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
|
||||
# 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.
|
||||
|
||||
from osc_lib.command import command
|
||||
|
||||
from cloudkittyclient.v1 import shell
|
||||
|
||||
|
||||
class CliModuleList(command.Command):
|
||||
"""List modules."""
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_module_list(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliModuleEnable(command.Command):
|
||||
"""Enable a module."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliModuleEnable, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Module name',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_module_enable(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliModuleDisable(command.Command):
|
||||
"""Disable a module."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliModuleDisable, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Module name',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_module_disable(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliModuleSetPriority(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliModuleSetPriority, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Module name',
|
||||
required=True)
|
||||
parser.add_argument('-p', '--priority',
|
||||
help='Module priority',
|
||||
required=True)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_module_set_priority(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliInfoGetConfig(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliInfoGetConfig, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_info_config_get(ckclient, parsed_args)
|
||||
|
||||
|
||||
class CliInfoGetService(command.Command):
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliInfoGetService, self).get_parser(prog_name)
|
||||
parser.add_argument('-n', '--name',
|
||||
help='Service name',
|
||||
required=False)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_info_service_get(ckclient, parsed_args)
|
||||
@@ -17,21 +17,22 @@
|
||||
from cloudkittyclient.common import utils
|
||||
|
||||
|
||||
@utils.arg('--begin',
|
||||
help='Starting date/time (YYYY-MM-ddThh:mm:ss)',
|
||||
required=True)
|
||||
@utils.arg('--end',
|
||||
help='Ending date/time (YYYY-MM-ddThh:mm:ss)',
|
||||
required=True)
|
||||
@utils.arg('--tenant',
|
||||
@utils.arg('-b', '--begin',
|
||||
help='Starting date/time (YYYY-MM-DDTHH:MM:SS)',
|
||||
required=False)
|
||||
@utils.arg('-e', '--end',
|
||||
help='Ending date/time (YYYY-MM-DDTHH:MM:SS)',
|
||||
required=False)
|
||||
@utils.arg('-t', '--tenant',
|
||||
help='Tenant ID',
|
||||
required=False,
|
||||
default=None)
|
||||
@utils.arg('--resource-type',
|
||||
@utils.arg('-r', '--resource-type',
|
||||
help='Resource type (compute, image, ...)',
|
||||
required=False,
|
||||
default=None)
|
||||
def do_storage_dataframe_list(cc, args):
|
||||
"""List dataframes."""
|
||||
data = cc.storage.dataframes.list(begin=args.begin, end=args.end,
|
||||
tenant_id=args.tenant,
|
||||
resource_type=args.resource_type)
|
||||
|
||||
44
cloudkittyclient/v1/storage/shell_cli.py
Normal file
44
cloudkittyclient/v1/storage/shell_cli.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# Copyright 2016 Objectif Libre
|
||||
#
|
||||
# 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.
|
||||
|
||||
from osc_lib.command import command
|
||||
|
||||
from cloudkittyclient.v1.storage import shell
|
||||
|
||||
|
||||
class CliStorageDataframeList(command.Command):
|
||||
"""List dataframes."""
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CliStorageDataframeList, self).get_parser(prog_name)
|
||||
parser.add_argument('-b', '--begin',
|
||||
help='Starting date/time (YYYY-MM-ddThh:mm:ss)',
|
||||
required=False)
|
||||
parser.add_argument('-e', '--end',
|
||||
help='Ending date/time (YYYY-MM-ddThh:mm:ss)',
|
||||
required=False)
|
||||
parser.add_argument('-t', '--tenant',
|
||||
help='Tenant ID',
|
||||
required=False,
|
||||
default=None)
|
||||
parser.add_argument('-r', '--resource-type',
|
||||
help='Resource type (compute, image...)',
|
||||
required=False,
|
||||
default=None)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ckclient = self.app.client_manager.rating
|
||||
shell.do_storage_dataframe_list(ckclient, parsed_args)
|
||||
@@ -1,42 +0,0 @@
|
||||
Name: python-cloudkittyclient
|
||||
Version: @VERSION@
|
||||
Release: 1%{?dist}
|
||||
Summary: Client library for CloudKitty
|
||||
License: ASL 2.0
|
||||
Source: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: python-setuptools
|
||||
BuildRequires: python-pbr
|
||||
BuildRequires: python-keystoneclient
|
||||
BuildRequires: python-stevedore
|
||||
BuildRequires: python-babel
|
||||
|
||||
Requires: python-keystoneclient
|
||||
Requires: python-stevedore
|
||||
Requires: python-babel
|
||||
|
||||
%description
|
||||
Client library for CloudKitty
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%{__python} setup.py build
|
||||
|
||||
%install
|
||||
%{__python} setup.py install -O1 --skip-build --root %{buildroot}
|
||||
|
||||
#export PYTHONPATH="$( pwd ):$PYTHONPATH"
|
||||
#sphinx-build -b html doc/source html
|
||||
|
||||
%files
|
||||
%{_bindir}/*
|
||||
%{python_sitelib}/*
|
||||
#%doc html
|
||||
|
||||
%changelog
|
||||
* Sun Apr 19 2015 Gauvain Pocentek <gauvain.pocentek@objectif-libre.com> @VERSION@-1
|
||||
- Initial release
|
||||
1
doc/source/conf.py
Executable file → Normal file
1
doc/source/conf.py
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from oslo-incubator.git
|
||||
module=apiclient
|
||||
module=cliutils
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=cloudkittyclient
|
||||
@@ -2,10 +2,12 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr!=0.7,<1.0,>=0.6
|
||||
Babel>=1.3
|
||||
python-keystoneclient<1.4.0,>=1.2.0
|
||||
stevedore<1.4.0,>=1.3.0 # Apache-2.0
|
||||
oslo.i18n<1.6.0,>=1.5.0 # Apache-2.0
|
||||
oslo.serialization<1.5.0,>=1.4.0 # Apache-2.0
|
||||
oslo.utils<1.5.0,>=1.4.0 # Apache-2.0
|
||||
pbr>=1.6 # Apache-2.0
|
||||
Babel>=2.3.4 # BSD
|
||||
python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0
|
||||
python-openstackclient>=3.0.0 # Apache-2.0
|
||||
stevedore>=1.10.0 # Apache-2.0
|
||||
oslo.i18n>=2.1.0 # Apache-2.0
|
||||
oslo.serialization>=1.10.0 # Apache-2.0
|
||||
oslo.utils>=3.11.0 # Apache-2.0
|
||||
PrettyTable<0.8,>=0.7 # BSD
|
||||
|
||||
56
setup.cfg
56
setup.cfg
@@ -1,6 +1,5 @@
|
||||
[metadata]
|
||||
name = python-cloudkittyclient
|
||||
version = 0.4.1
|
||||
summary = API client of cloudkitty, Rating as a Service project.
|
||||
description-file =
|
||||
README.rst
|
||||
@@ -17,7 +16,6 @@ classifier =
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
@@ -30,6 +28,60 @@ console_scripts =
|
||||
|
||||
cloudkitty.client.modules =
|
||||
hashmap = cloudkittyclient.v1.rating.hashmap.extension:Extension
|
||||
pyscripts = cloudkittyclient.v1.rating.pyscripts.extension:Extension
|
||||
|
||||
openstack.cli.extension =
|
||||
rating = cloudkittyclient.osc
|
||||
|
||||
openstack.rating.v1 =
|
||||
rating_module-list = cloudkittyclient.v1.shell_cli:CliModuleList
|
||||
rating_module-enable = cloudkittyclient.v1.shell_cli:CliModuleEnable
|
||||
rating_module-disable = cloudkittyclient.v1.shell_cli:CliModuleDisable
|
||||
rating_module-set-priority = cloudkittyclient.v1.shell_cli:CliModuleSetPriority
|
||||
|
||||
rating_info-config-get = cloudkittyclient.v1.shell_cli:CliInfoGetConfig
|
||||
rating_info-service-get = cloudkittyclient.v1.shell_cli:CliInfoGetService
|
||||
|
||||
rating_total-get = cloudkittyclient.v1.report.shell_cli:CliTotalGet
|
||||
rating_summary-get = cloudkittyclient.v1.report.shell_cli:CliSummaryGet
|
||||
rating_report-tenant-list = cloudkittyclient.v1.report.shell_cli:CliReportTenantList
|
||||
|
||||
rating_collector-mapping-list = cloudkittyclient.v1.collector.shell_cli:CliCollectorMappingList
|
||||
rating_collector-mapping-get = cloudkittyclient.v1.collector.shell_cli:CliCollectorMappingGet
|
||||
rating_collector-mapping-create = cloudkittyclient.v1.collector.shell_cli:CliCollectorMappingCreate
|
||||
rating_collector-mapping-delete = cloudkittyclient.v1.collector.shell_cli:CliCollectorMappingDelete
|
||||
rating_collector-state-get = cloudkittyclient.v1.collector.shell_cli:CliCollectorStateGet
|
||||
rating_collector-state-enable = cloudkittyclient.v1.collector.shell_cli:CliCollectorStateEnable
|
||||
rating_collector-state-disable = cloudkittyclient.v1.collector.shell_cli:CliCollectorStateDisable
|
||||
|
||||
rating_storage-dataframe-list = cloudkittyclient.v1.storage.shell_cli:CliStorageDataframeList
|
||||
|
||||
rating_hashmap-service-create = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapServiceCreate
|
||||
rating_hashmap-service-list = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapServiceList
|
||||
rating_hashmap-service-delete = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapServiceDelete
|
||||
rating_hashmap-field-create = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapFieldCreate
|
||||
rating_hashmap-field-list = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapFieldList
|
||||
rating_hashmap-field-delete = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapFieldDelete
|
||||
rating_hashmap-mapping-create = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapMappingCreate
|
||||
rating_hashmap-mapping-update = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapMappingUpdate
|
||||
rating_hashmap-mapping-list = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapMappingList
|
||||
rating_hashmap-mapping-delete = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapMappingDelete
|
||||
rating_hashmap-group-create = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapGroupCreate
|
||||
rating_hashmap-group-list = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapGroupList
|
||||
rating_hashmap-group-delete = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapGroupDelete
|
||||
rating_hashmap-threshold-create = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdCreate
|
||||
rating_hashmap-threshold-update = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdUpdate
|
||||
rating_hashmap-threshold-list = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdList
|
||||
rating_hashmap-threshold-delete = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdDelete
|
||||
rating_hashmap-threshold-get = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdGet
|
||||
rating_hashmap-threshold-group = cloudkittyclient.v1.rating.hashmap.shell_cli:CliHashmapThresholdGroup
|
||||
|
||||
rating_pyscripts-script-create = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptCreate
|
||||
rating_pyscripts-script-list = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptList
|
||||
rating_pyscripts-script-get = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptGet
|
||||
rating_pyscripts-script-get-data = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptGetData
|
||||
rating_pyscripts-script-delete = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptDelete
|
||||
rating_pyscripts-script-update = cloudkittyclient.v1.rating.pyscripts.shell_cli:CliPyScriptUpdate
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
||||
2
setup.py
2
setup.py
@@ -25,5 +25,5 @@ except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
setup_requires=['pbr>=1.8'],
|
||||
pbr=True)
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking<0.10,>=0.9.2
|
||||
hacking>=0.12.0,!=0.13.0,<0.14 # Apache-2.0
|
||||
|
||||
coverage>=3.6
|
||||
discover
|
||||
python-subunit>=0.0.18
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||
oslosphinx<2.6.0,>=2.5.0 # Apache-2.0
|
||||
oslotest<1.6.0,>=1.5.1 # Apache-2.0
|
||||
testrepository>=0.0.18
|
||||
testscenarios>=0.4
|
||||
testtools!=1.2.0,>=0.9.36
|
||||
coverage>=3.6 # Apache-2.0
|
||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
|
||||
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
|
||||
oslotest>=1.10.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
|
||||
15
tox.ini
15
tox.ini
@@ -1,17 +1,20 @@
|
||||
[tox]
|
||||
minversion = 1.6
|
||||
envlist = py33,py34,py27,pypy,pep8
|
||||
envlist = py34,py27,pypy,pep8
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -U {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
|
||||
@@ -25,10 +28,12 @@ commands = python setup.py testr --coverage --testr-args='{posargs}'
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[flake8]
|
||||
# H803 skipped on purpose per list discussion.
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125,H803
|
||||
ignore = E123,E125
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
||||
|
||||
[hacking]
|
||||
import_exceptions = cloudkittyclient.i18n
|
||||
|
||||
Reference in New Issue
Block a user