Compare commits

...

60 Commits

Author SHA1 Message Date
OpenDev Sysadmins
c91e61fc9f OpenDev Migration Patch
This commit was bulk generated and pushed by the OpenDev sysadmins
as a part of the Git hosting and code review systems migration
detailed in these mailing list posts:

http://lists.openstack.org/pipermail/openstack-discuss/2019-March/003603.html
http://lists.openstack.org/pipermail/openstack-discuss/2019-April/004920.html

Attempts have been made to correct repository namespaces and
hostnames based on simple pattern matching, but it's possible some
were updated incorrectly or missed entirely. Please reach out to us
via the contact information listed at https://opendev.org/ with any
questions you may have.
2019-04-19 19:42:57 +00:00
Doug Hellmann
a4dafc254b import zuul job settings from project-config
This is a mechanically generated patch to complete step 1 of moving
the zuul job settings out of project-config and into each project
repository.

Because there will be a separate patch on each branch, the branch
specifiers for branch-specific jobs have been removed.

Because this patch is generated by a script, there may be some
cosmetic changes to the layout of the YAML file(s) as the contents are
normalized.

See the python3-first goal document for details:
https://governance.openstack.org/tc/goals/stein/python3-first.html

Change-Id: I065b81e1415ab468f5178d2333e147ef5d6d87cd
Story: #2002586
Task: #24289
2018-08-31 08:59:14 -04:00
65a6bb83cd Update UPPER_CONSTRAINTS_FILE for stable/queens
Change-Id: Ia7727c51060a125a3b37ec8a0fd63c1296be14ea
2018-01-30 00:35:35 +00:00
0353abdd7f Update .gitreview for stable/queens
Change-Id: Icf52f1a30b3360e8559d759776549ba1654038f1
2018-01-30 00:35:32 +00:00
Zuul
075cb4993d Merge "Delete outdated and unused directory" 2018-01-29 02:02:07 +00:00
Zuul
938697cb39 Merge "Remove log translations" 2018-01-26 13:55:16 +00:00
Zuul
7d3730cc77 Merge "Drop py34 target in tox.ini" 2018-01-26 13:23:13 +00:00
Zuul
8ba6712b74 Merge "Added release note for cloudkittyclient" 2018-01-26 13:22:08 +00:00
zhangguoqing
81bc4e3dce Added release note for cloudkittyclient
This adds the releasenotes directory to the python-cloudkittyclient repo.
It maintains the releasenotes for cloudkittyclient.

Change-Id: I31b310874c4cd0c26683c75c208edb607499d86b
2018-01-23 17:22:16 +00:00
lingyongxu
64129e43a1 Drop py34 target in tox.ini
We support py35 now.so it is no need to keep
the supoort for py34.

Change-Id: Ief8f6e8a383fd311c4bc4c552aabde4d80eb852b
2018-01-23 17:21:33 +00:00
Kiran_totad
bf30936048 Remove log translations
Log messages are no longer being translated. This removes all use of the
_LE, _LI, and _LW translation markers to simplify logging and to avoid
confusion with new contributions.

See:
http://lists.openstack.org/pipermail/openstack-i18n/2016-November/002574.html
http://lists.openstack.org/pipermail/openstack-dev/2017-March/113365.html

Change-Id: Ic22cf715a70e9e1ff734944015d2f8a1ab2dbef8
2018-01-23 17:20:16 +00:00
Luka Peschke
b07b8c2360 Update the README
- Change the client version from 0.2 to 1.1.0

       - Add a link to PyPi

Change-Id: Iac050bea6b662e210493fc4af2dd0cda218ad777
2017-09-21 10:06:04 +02:00
Andreas Jaeger
87dbe6ea2e Use openstackdocstheme
Use the new theme for the docs.

This needs an update of requirements, I synced all requirements with
global requirements list.

Change-Id: I50c451501a8c428a174f477b89a2986f93adfcb1
2017-07-02 19:36:48 +02:00
Andreas Jaeger
f3451d8656 Import cli-reference from openstack-manuals
Change-Id: I32849dd61c0e5435000d78e01ec211bf9c47668e
2017-07-02 19:25:19 +02:00
Andreas Jaeger
34aef63639 Tread Sphinx warnings as errors
Set this to not introduce any warnings.

Change-Id: Ia17b24e612d155adb17df107135c3c44e457a9ae
2017-07-02 19:24:04 +02:00
Andreas Jaeger
7b5bb67733 rearrange existing docs to fit the new standard layout
Refer to
https://specs.openstack.org/openstack/docs-specs/specs/pike/os-manuals-migration.html
for details.

Change-Id: I10a07ae0b419730960d7d1013ace259dab7a2455
2017-07-02 19:23:58 +02:00
Jeremy Liu
cf2b4f31c7 [Fix gate]Update test requirement
Since pbr already landed and the old version of hacking seems not
work very well with pbr>=2, we should update it to match global
requirement.

Change-Id: I9177c69fd96ecacf164768b9e08f0e91d3a8690a
Partial-Bug: #1668848
2017-03-04 14:26:57 +00:00
HaiJieZhang
87dadb689c Delete outdated and unused directory
The file in "tools" directory is outdated and unused,
so delete it from repo.

Change-Id: I7faf4966f15b6f7757953eb758ad6dcec6c184e3
Closes-Bug: #1669024
2017-03-01 23:42:48 +08:00
Jenkins
2fe71f729a Merge "Add --all-tenants when get total/summary" 2017-01-26 16:42:43 +00:00
Jenkins
c6b90fc6e6 Merge "Update .gitignore" 2017-01-26 11:50:13 +00:00
Jenkins
d9aa46de34 Merge "Remove white space between print ()" 2017-01-26 11:46:07 +00:00
Aaron-DH
56e6f689bb Add --all-tenants when get total/summary
Use `cloudkitty total-get --all-tenants` to get total
rate of all_tenants. Same with summary-get

Depends-On: 8cf7332162ad30bcdb2c8dfd10a3d348601c2870
Change-Id: I1efcbb8eff77c5f8d358a02178b1f99204b6cba7
2017-01-24 11:05:54 +08:00
Jenkins
75755b2af3 Merge "Add oslo_debug_helper to tox.ini" 2017-01-23 08:03:37 +00:00
Jenkins
40ddf6a470 Merge "Delete unnecessary utf-8 coding" 2017-01-22 15:36:25 +00:00
Jenkins
287dd57185 Merge "Improve User experience" 2017-01-22 15:24:57 +00:00
Jenkins
416a717ebc Merge "Remove white space between print () in cliutils.py" 2017-01-19 09:57:32 +00:00
Maxime Cottret
efb2b0949a Improve User experience
This patch adds access to new REST API for config and service
metadata retrieval.

The following work has been done:

* Create new manager for config retrieval
* Create new Resource and CRUD manager for service info retrieval
* Add managers to client
* Add new CLI command and openstack client entries

Change-Id: I43f572202b1cd3832a820f46f7c7b44a0d998406
Depends-on: https://review.openstack.org/#/c/406180/
2017-01-18 14:48:17 +00:00
Jenkins
a567600b77 Merge "Add client for get summary report" 2017-01-18 14:32:18 +00:00
Jeremy Liu
d04e5ac776 Update .gitignore
These directories are generated by command `python setup.py install`,
better put them into .gitignore.

Change-Id: I63137da72f144556530677b43219aa0e10220b6e
2017-01-18 10:15:57 +08:00
Anh Tran
a1f45a0206 Remove white space between print ()
Change-Id: I464707dd23f006d790c618ef44e37bf6e6de9a22
2017-01-17 10:31:19 +07:00
Aaron-DH
2211d48f72 Add oslo_debug_helper to tox.ini
oslo_debug_helper is used to assist in debugging of python code,
i.e. by adding breakpoints via pdb.

To enable debugging, run tox with the debug environment:
tox -e debug <test_path>

Reference link:
http://docs.openstack.org/developer/oslotest/features.html#debugging-with-oslo-debug-helper

Change-Id: I01d66328a3529e542e503be2cd7bbca69a77c4aa
2017-01-16 19:19:52 +08:00
Aaron-DH
e402ce676c Add client for get summary report
Use commands as follows to get summary:
  -- cloudkitty summary-get
  -- openstack rating summary-get

Change-Id: I07da26cb31a03104493ab749efffd73ba8d17d62
Implements: blueprint price-groupby-fields
2017-01-16 18:59:38 +08:00
Jenkins
c423ca4470 Merge "Remove unused pylintrc" 2017-01-09 08:15:38 +00:00
Jenkins
f750d31169 Merge "H803 hacking have been deprecated" 2017-01-09 07:51:21 +00:00
zhangguoqing
cdbcafd142 Remove white space between print () in cliutils.py
There is a white space in line [print (*, then we remove it.

REF. https://review.openstack.org/#/c/387303/

Change-Id: I6762b7d1d9f573d62e7466da134addd51e0b4163
2017-01-04 02:33:38 +00:00
gecong1973
cffa8b8936 Delete unnecessary utf-8 coding
The file was added redundant utf-8 coding by some editor.
we can delete it .

Change-Id: I618e0c8f43717fd13db7b4d5213fa92a7b98a357
2016-12-27 10:08:37 +08:00
xhzhf
10f80c7d02 H803 hacking have been deprecated
H803 hacking have been removed.
https://github.com/openstack-dev/hacking/blob/master/setup.cfg
Closes-Bug: #1650741

Change-Id: Ibeeca8f56dd3fe872e1611bd4b61ec515670ec8d
2016-12-17 20:21:45 +08:00
Jenkins
87cdbb1340 Merge "Change the time args format from timestamp to date/time when total-get" 2016-12-15 12:19:18 +00:00
Jenkins
cede66dde6 Merge "Unify the date format "YYYY-MM-DDTHH:MM:SS"" 2016-12-15 12:18:18 +00:00
Jeremy Liu
addb3a8b33 Set upper-constraints for tox
Change-Id: Ia1dd9b902eae4d3ebdbd46802f7ba8043b3ee2a8
2016-12-14 11:00:05 +08:00
Luka Peschke
04bf3504ee Add support for OpenStack client
Cloudkittyclient now provides a plugin for the Openstack client.
setup.cfg was modified to provide entrypoints for the Openstack client. These
entrypoints can be found in the different shell_cli.py files.
Python-openstackclient was added to the requirements.

Implements: blueprint openstackclient-support
Change-Id: If0bbd919b1552b82cd77a52ded4f4ec32e6e14d8
2016-11-30 15:17:32 +01:00
Maxime Cottret
b6f7a7831f Add module priority management
This patch binds the python client to the module priority REST api.
It also adds a CLI setter command and updates the module list CLI
output to show current priority value.

Change-Id: I06ab6611452cdc6e875b5534cd955a0a3092ed0d
Implements: blueprint module-priority-cli-command
2016-11-29 14:59:35 +00:00
Jenkins
70cef21224 Merge "Use os_project name in get_client" 2016-11-29 14:10:12 +00:00
Luka Peschke
8fa848fb51 Use os_project name in get_client
The cloudkitty Client object cannot authenticate into keystone
if 'os_project_name' is passed as parameter instead of 'os_tenant_name'.
It is the same if 'os_project_id' is passed instead of 'os_tenant_id'.

This patch fixes both of these issues.

Change-Id: Ife248e87e1126d101be5e4550b933e66eccadbb9
2016-11-29 14:32:45 +01:00
zhangguoqing
d70f9c778c Unify the date format "YYYY-MM-DDTHH:MM:SS"
Change-Id: I729cef6f09d1e61f0c99faf87a87955e4bde3c13
2016-11-29 12:29:38 +00:00
Luka Peschke
ddf93becc1 Catches the right exceptions shell.py files
This is a fix for the bug #1645380. The right exceptions are caught and
'counter_name' is not used for the Exception messages anymore.

Change-Id: I242ee04783c5c8b2699ef3efe70f8e397eb794b8
Closes-Bug: 1645380
2016-11-29 12:33:13 +01:00
Jenkins
0024760bef Merge "Show team and repo badges on README" 2016-11-28 14:44:36 +00:00
Jenkins
5d43074cc4 Merge "Make begin and end optional when get dataframes" 2016-11-28 14:15:18 +00:00
Jenkins
d82273fcd4 Merge "Add __ne__ built-in function" 2016-11-26 05:21:25 +00:00
Flavio Percoco
241d90f541 Show team and repo badges on README
This patch adds the team's and repository's badges to the README file.
The motivation behind this is to communicate the project status and
features at first glance.

For more information about this effort, please read this email thread:

http://lists.openstack.org/pipermail/openstack-dev/2016-October/105562.html

To see an example of how this would look like check:

https://gist.github.com/168107e62fde067f3925d71a5a0f2d4d

Change-Id: I8caa8cdaa4efc2ea438b2ace632b62afd5d322e5
2016-11-25 17:25:39 +01:00
zhangguoqing
708aeff9b7 Change the time args format from timestamp to date/time when total-get
The begin and end args format is timestamp in total-get command, which
is less convenient than date/time format(YYYY-MM-DDTHH:MM:SS). So this
patch make it easy to use.

Change-Id: Id83e132e6b8a090d1abfa3002d53de1b678fc9f2
2016-11-24 14:53:06 +00:00
Jenkins
9a9399f284 Merge "py33 is no longer supported by Infra's CI" 2016-11-24 09:16:28 +00:00
gecong1973
a070f5b16c Add __ne__ built-in function
In Python 3 __ne__ by default delegates to __eq__ and inverts the
result, but in Python 2 they urge you to define __ne__ when you
define __eq__ for it to work properly [1].There are no implied
relationships among the comparison operators. The truth of x==y
does not imply that x!=y is false. Accordingly, when defining __eq__(),
one should also define __ne__() so that the operators will behave as
expected.
[1]https://docs.python.org/2/reference/datamodel.html#object.__ne_

Change-Id: Id2d32eedddbbbb91c6da6e36f12515972aa9e5a5
2016-11-23 17:09:15 +08:00
Jeremy Liu
9a1f531155 Remove unused pylintrc
We didn't use it in the gate and it's unmaintained. Clean that.

Change-Id: I5366927f2dd5771c2b8b0f9c68bf0201b8681776
2016-11-22 11:19:35 +08:00
Aaron-DH
d0f0aaf346 Make begin and end optional when get dataframes
when get dataframes with `cloudkitty storage-dataframe-list`,
begin and end is mandatory. make it optional like get total

Change-Id: I0a0f4073888621833b0bb6588a0452a642327797
Closes-Bug: #1640372
2016-11-09 14:51:37 +08:00
Steve Martinelli
a93f8b04b1 move old oslo-incubator code out of openstack/common
As part of the first community-wide goal, teams were asked
to remove the openstack/common package of their projects
if one existed. This was a byproduct of the old oslo-incubator
form of syncing common functionality.

The package, apiclient, was moved to a top level location
and cliutils was moved to the common module. There are no oslo
specific libraries, the recommended solution is to move it
in tree and maintain it there.

Change-Id: I0603d3c1419a5344bee8e43cfbe794c26641960a
2016-10-31 11:15:10 -04:00
Jenkins
e6daa3df81 Merge "Fix the logic of do_hashmap_mapping_list" 2016-09-01 16:25:53 +00:00
Jenkins
7a199820d0 Merge "Add short arg for storage command" 2016-09-01 16:14:36 +00:00
zhangguoqing
d4ae928048 Add short arg for storage command
Change-Id: I6c29171d66527fe4284c0ce7b2e9fb2e17a7d49f
2016-08-10 10:45:42 +00:00
janonymous
0de831021d py33 is no longer supported by Infra's CI
Python 3.3 support would be dropped by
Infra team from mitaka,CI would no longer be testing it,
so projects should drop it also.

Change-Id: Ic03ded9bba499858a77debbcdc4fc9c9d963dd24
2015-12-26 15:47:45 +05:30
62 changed files with 2805 additions and 381 deletions

View File

@@ -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

4
.gitignore vendored
View File

@@ -11,3 +11,7 @@ cover
dist
*.egg
*.sw?
.eggs
AUTHORS
ChangeLog
releasenotes/build

View File

@@ -1,4 +1,5 @@
[gerrit]
host=review.openstack.org
host=review.opendev.org
port=29418
project=openstack/python-cloudkittyclient.git
defaultbranch=stable/queens

View File

@@ -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=_

8
.zuul.yaml Normal file
View File

@@ -0,0 +1,8 @@
- project:
templates:
- openstack-python-jobs
- openstack-python35-jobs
- openstackclient-plugin-jobs
post:
jobs:
- openstack-tox-cover

View File

@@ -1,7 +1,11 @@
Python bindings to the CloudKitty API
=====================================
================
CloudKittyClient
================
:version: 0.2
.. image:: http://governance.openstack.org/badges/python-cloudkittyclient.svg
:target: http://governance.openstack.org/reference/tags/index.html
:version: 1.1.0
:Wiki: `CloudKitty Wiki`_
:IRC: #cloudkitty @ freenode
@@ -9,15 +13,12 @@ Python bindings to the CloudKitty API
.. _CloudKitty Wiki: https://wiki.openstack.org/wiki/CloudKitty
python-cloudkittyclient
=======================
This is a client for CloudKitty_. It provides a Python api (the
``cloudkittyclient`` module), a command-line script (``cloudkitty``), and an
`OpenStack Client`_ extension (``openstack rating``).
This is a client library for CloudKitty built on the CloudKitty API. It
provides a Python API (the ``cloudkittyclient`` module).
Status
======
This project is **highly** work in progress.
The client is available on PyPi_.
.. _OpenStack Client: https://docs.openstack.org/python-openstackclient/latest/
.. _CloudKitty: https://github.com/openstack/cloudkitty
.. _PyPi: https://pypi.python.org/pypi/python-cloudkittyclient

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Objectif Libre
# Licensed under the Apache License, Version 2.0 (the "License"); you may

View File

@@ -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.

View File

@@ -44,8 +44,8 @@ from oslo_utils import strutils
import six
from six.moves.urllib import parse
from cloudkittyclient.apiclient import exceptions
from cloudkittyclient.i18n import _
from cloudkittyclient.openstack.common.apiclient import exceptions
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

View File

@@ -38,8 +38,9 @@ from oslo_utils import encodeutils
from oslo_utils import importutils
import requests
from cloudkittyclient.apiclient import exceptions
from cloudkittyclient.i18n import _
from cloudkittyclient.openstack.common.apiclient import exceptions
_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,

View File

@@ -42,8 +42,7 @@ 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")

View File

@@ -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)

View File

@@ -28,8 +28,8 @@ from oslo_utils import encodeutils
from oslo_utils import uuidutils
import six
from cloudkittyclient.apiclient import exceptions
from cloudkittyclient.i18n import _
from cloudkittyclient.openstack.common.apiclient import exceptions
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)

View File

@@ -22,11 +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 client
from cloudkittyclient.openstack.common.apiclient import exceptions
def _discover_auth_versions(session, auth_url):
@@ -306,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'),
@@ -339,7 +341,7 @@ 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'),

View File

@@ -22,9 +22,9 @@ import copy
from six.moves.urllib import parse
from cloudkittyclient.apiclient import base
from cloudkittyclient import exc
from cloudkittyclient.i18n import _
from cloudkittyclient.openstack.common.apiclient import base
def getid(obj):

View File

@@ -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)

View File

@@ -23,12 +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.i18n import _
from cloudkittyclient.openstack.common import cliutils
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):

View File

@@ -22,7 +22,3 @@ _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

35
cloudkittyclient/osc.py Normal file
View 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

View File

@@ -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

View File

@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#

View File

@@ -132,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)

View File

@@ -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

View File

@@ -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,
}
),
},
@@ -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)

View File

@@ -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
from cloudkittyclient.v1.rating import hashmap

View 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)

View File

@@ -57,8 +57,11 @@ class Client(object):
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):

View 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)

View File

@@ -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

View File

@@ -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',
@@ -92,8 +93,9 @@ def do_hashmap_field_list(cc, args={}):
"""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,8 +110,8 @@ 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):
@@ -179,8 +181,8 @@ def do_hashmap_mapping_update(cc, args={}):
}
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:
@@ -210,8 +212,9 @@ def do_hashmap_mapping_list(cc, args={}):
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',
@@ -230,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)
@@ -255,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']
@@ -277,7 +280,7 @@ 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)
@@ -348,8 +351,8 @@ def do_hashmap_threshold_update(cc, args={}):
}
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:
@@ -384,8 +387,8 @@ 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',
@@ -403,7 +406,7 @@ 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)
@@ -414,7 +417,7 @@ 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())
@@ -426,6 +429,6 @@ 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())

View 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)

View File

@@ -17,6 +17,7 @@ import functools
from oslo_utils import strutils
import six
from cloudkittyclient.apiclient import exceptions
from cloudkittyclient.common import utils
from cloudkittyclient import exc
@@ -64,7 +65,7 @@ def do_pyscripts_script_get(cc, args={}):
"""Get script."""
try:
script = cc.pyscripts.scripts.get(script_id=args.script_id)
except exc.HTTPNotFound:
except exceptions.NotFound:
raise exc.CommandError('Script not found: %s' % args.script_id)
utils.print_dict(script.to_dict())
@@ -76,7 +77,7 @@ def do_pyscripts_script_get_data(cc, args={}):
"""Get script data."""
try:
script = cc.pyscripts.scripts.get(script_id=args.script_id)
except exc.HTTPNotFound:
except exceptions.NotFound:
raise exc.CommandError('Script not found: %s' % args.script_id)
six.print_(script.data)
@@ -88,8 +89,8 @@ def do_pyscripts_script_delete(cc, args={}):
"""Delete a script."""
try:
cc.pyscripts.scripts.delete(script_id=args.script_id)
except exc.HTTPNotFound:
raise exc.CommandError('Script not found: %s' % args.counter_name)
except exceptions.NotFound:
raise exc.CommandError('Script not found: %s' % args.script_id)
@utils.arg('-s', '--script-id',
@@ -107,7 +108,7 @@ def do_pyscripts_script_update(cc, args={}):
content = fp.read()
try:
script = cc.pyscripts.scripts.get(script_id=args.script_id)
except exc.HTTPNotFound:
except exceptions.NotFound:
raise exc.CommandError('Script not found: %s' % args.script_id)
script_dict = script.to_dict()
for field in excluded_fields:

View 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)

View File

@@ -15,22 +15,31 @@
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=None, begin=None, end=None, service=None):
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:
@@ -41,6 +50,32 @@ class ReportManager(base.Manager):
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)

View File

@@ -30,6 +30,37 @@ def do_report_tenant_list(cc, args):
help='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)
@@ -39,12 +70,27 @@ def do_report_tenant_list(cc, args):
@utils.arg('-s', '--service',
help='Service Type',
required=False)
def do_total_get(cc, args):
"""Get total reports."""
@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(tenant_id=args.total_tenant_id,
begin=begin,
end=end,
service=args.service)
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)

View 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)

View File

@@ -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)

View 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)

View File

@@ -17,17 +17,17 @@
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)

View 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)

1106
doc/source/cli/index.rst Normal file

File diff suppressed because it is too large Load Diff

View 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
@@ -23,7 +22,7 @@ sys.path.insert(0, os.path.abspath('../..'))
extensions = [
'sphinx.ext.autodoc',
#'sphinx.ext.intersphinx',
'oslosphinx'
'openstackdocstheme'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
@@ -38,7 +37,12 @@ master_doc = 'index'
# General information about the project.
project = u'python-cloudkittyclient'
copyright = u'2013, OpenStack Foundation'
copyright = u'2017, OpenStack Foundation'
# openstackdocstheme options
repository_name = 'openstack/python-cloudkittyclient'
bug_project = 'cloudkitty'
bug_tag = 'python-cloudkittyclient'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
@@ -57,6 +61,10 @@ pygments_style = 'sphinx'
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
html_theme = 'openstackdocs'
# Must set this variable to include year, month, day, hours, and minutes.
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project

View File

@@ -1,4 +0,0 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

View File

@@ -0,0 +1,5 @@
============
Contributing
============
.. include:: ../../../CONTRIBUTING.rst

View File

@@ -1,20 +1,19 @@
.. python-cloudkittyclient documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
========================================================
Welcome to python-cloudkittyclient's documentation!
========================================================
This is a client library for CloudKitty built on the CloudKitty API. It
provides a Python API (the ``cloudkittyclient`` module).
Contents:
.. toctree::
:maxdepth: 2
readme
installation
usage
contributing
install/index
contributor/index
cli/index
user/index
Indices and tables
==================

View File

@@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@@ -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

263
releasenotes/source/conf.py Normal file
View File

@@ -0,0 +1,263 @@
# -*- coding: utf-8 -*-
#
# Cloudkitty Release Notes documentation build configuration file.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
import pbr.version
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'oslosphinx',
'reno.sphinxext',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Cloudkitty Client Release Notes'
copyright = u'2016, Cloudkitty developers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
cloudkittyclient_version = pbr.version.VersionInfo('python-cloudkittyclient')
# The short X.Y version.
version = cloudkittyclient_version.canonical_version_string()
# The full version, including alpha/beta/rc tags.
release = cloudkittyclient_version.version_string_with_vcs()
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'CloudkittyReleaseNotestdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'PythonCloudkitty.tex', u'Cloudkitty Release Notes Documentation',
u'Cloudkitty developers', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'cloudkittyclient',
u'Cloudkitty Client Release Notes Documentation',
[u'Cloudkitty developers'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'cloudkittyclient',
u'Cloudkitty Client Release Notes Documentation',
u'Cloudkitty Client developers', 'Cloudkittyclient',
'One line description of project.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@@ -0,0 +1,16 @@
Welcome to Cloudkitty Client Release Notes documentation!
=========================================================
Contents
========
.. toctree::
:maxdepth: 2
unreleased
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

View File

@@ -0,0 +1,5 @@
============================
Current Series Release Notes
============================
.. release-notes::

View File

@@ -2,11 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
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
stevedore>=1.10.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
pbr!=2.1.0,>=2.0.0 # Apache-2.0
Babel!=2.4.0,>=2.3.4 # BSD
python-keystoneclient>=3.8.0 # Apache-2.0
python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
oslo.i18n!=3.15.2,>=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
oslo.utils>=3.20.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD

View File

@@ -16,7 +16,7 @@ classifier =
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
[files]
packages =
@@ -30,10 +30,64 @@ 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
build-dir = doc/build
all_files = 1
warning-is-error = 1
[upload_sphinx]
upload-dir = doc/build/html

View File

@@ -25,5 +25,5 @@ except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=1.8'],
setup_requires=['pbr>=2.0.0'],
pbr=True)

View File

@@ -2,13 +2,14 @@
# 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.13.0,<0.14,>=0.12.0 # Apache-2.0
coverage>=3.6 # Apache-2.0
coverage!=4.4,>=4.0 # 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
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.11.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
reno>=1.8.0 # Apache2

View File

@@ -1,172 +0,0 @@
# Copyright 2013 OpenStack Foundation
# Copyright 2013 IBM Corp.
#
# 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.
"""Provides methods needed by installation script for OpenStack development
virtual environments.
Since this script is used to bootstrap a virtualenv from the system's Python
environment, it should be kept strictly compatible with Python 2.6.
Synced in from openstack-common
"""
from __future__ import print_function
import optparse
import os
import subprocess
import sys
class InstallVenv(object):
def __init__(self, root, venv, requirements,
test_requirements, py_version,
project):
self.root = root
self.venv = venv
self.requirements = requirements
self.test_requirements = test_requirements
self.py_version = py_version
self.project = project
def die(self, message, *args):
print(message % args, file=sys.stderr)
sys.exit(1)
def check_python_version(self):
if sys.version_info < (2, 6):
self.die("Need Python Version >= 2.6")
def run_command_with_code(self, cmd, redirect_output=True,
check_exit_code=True):
"""Runs a command in an out-of-process shell.
Returns the output of that command. Working directory is self.root.
"""
if redirect_output:
stdout = subprocess.PIPE
else:
stdout = None
proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
output = proc.communicate()[0]
if check_exit_code and proc.returncode != 0:
self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
return (output, proc.returncode)
def run_command(self, cmd, redirect_output=True, check_exit_code=True):
return self.run_command_with_code(cmd, redirect_output,
check_exit_code)[0]
def get_distro(self):
if (os.path.exists('/etc/fedora-release') or
os.path.exists('/etc/redhat-release')):
return Fedora(
self.root, self.venv, self.requirements,
self.test_requirements, self.py_version, self.project)
else:
return Distro(
self.root, self.venv, self.requirements,
self.test_requirements, self.py_version, self.project)
def check_dependencies(self):
self.get_distro().install_virtualenv()
def create_virtualenv(self, no_site_packages=True):
"""Creates the virtual environment and installs PIP.
Creates the virtual environment and installs PIP only into the
virtual environment.
"""
if not os.path.isdir(self.venv):
print('Creating venv...', end=' ')
if no_site_packages:
self.run_command(['virtualenv', '-q', '--no-site-packages',
self.venv])
else:
self.run_command(['virtualenv', '-q', self.venv])
print('done.')
else:
print("venv already exists...")
pass
def pip_install(self, *args):
self.run_command(['tools/with_venv.sh',
'pip', 'install', '--upgrade'] + list(args),
redirect_output=False)
def install_dependencies(self):
print('Installing dependencies with pip (this can take a while)...')
# First things first, make sure our venv has the latest pip and
# setuptools and pbr
self.pip_install('pip>=1.4')
self.pip_install('setuptools')
self.pip_install('pbr')
self.pip_install('-r', self.requirements, '-r', self.test_requirements)
def parse_args(self, argv):
"""Parses command-line arguments."""
parser = optparse.OptionParser()
parser.add_option('-n', '--no-site-packages',
action='store_true',
help="Do not inherit packages from global Python "
"install.")
return parser.parse_args(argv[1:])[0]
class Distro(InstallVenv):
def check_cmd(self, cmd):
return bool(self.run_command(['which', cmd],
check_exit_code=False).strip())
def install_virtualenv(self):
if self.check_cmd('virtualenv'):
return
if self.check_cmd('easy_install'):
print('Installing virtualenv via easy_install...', end=' ')
if self.run_command(['easy_install', 'virtualenv']):
print('Succeeded')
return
else:
print('Failed')
self.die('ERROR: virtualenv not found.\n\n%s development'
' requires virtualenv, please install it using your'
' favorite package management tool' % self.project)
class Fedora(Distro):
"""This covers all Fedora-based distributions.
Includes: Fedora, RHEL, CentOS, Scientific Linux
"""
def check_pkg(self, pkg):
return self.run_command_with_code(['rpm', '-q', pkg],
check_exit_code=False)[1] == 0
def install_virtualenv(self):
if self.check_cmd('virtualenv'):
return
if not self.check_pkg('python-virtualenv'):
self.die("Please install 'python-virtualenv'.")
super(Fedora, self).install_virtualenv()

15
tox.ini
View File

@@ -1,17 +1,20 @@
[tox]
minversion = 1.6
envlist = py34,py27,pypy,pep8
envlist = py35,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?h=stable/queens} -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,13 +28,15 @@ 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,releasenotes
[hacking]
import_exceptions = cloudkittyclient.i18n
[testenv:releasenotes]
commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html