Compare commits

..

8 Commits

Author SHA1 Message Date
Zuul
c5d1526dec Merge "Add support for POST /v2/dataframes API endpoint to the client" into stable/train 2019-09-23 07:52:15 +00:00
Zuul
729ab402a5 Merge "Add functional test jobs for the v2 client" into stable/train 2019-09-23 07:51:04 +00:00
Zuul
3bcb6949b7 Merge "Add lower-constraints job" into stable/train 2019-09-23 07:51:03 +00:00
Justin Ferrieu
71fa216168 Add support for POST /v2/dataframes API endpoint to the client
Support for the ``/v2/dataframes`` endpoint has been added to the client.
A new ``dataframes add`` CLI command is also available.

Change-Id: I7fe9072d7280f251edc865a653a0b9ed2ab26c90
Story: 2005890
Task: 35970
(cherry picked from commit c8d7a9e1c5)
2019-09-20 14:34:45 -05:00
Luka Peschke
41fecfcd1e Add functional test jobs for the v2 client
This adds test jobs for the v2 client, in python2 and python3.

Work items:

* Remove the "functional" tox environment and introduce the "functional-v1"
  and "functional-v2" environments.

* Add zuul base jobs for python2 and python 3 testing. Two jobs inherit from
  each of these new jobs: one for the v1 client and one for the v2 client.

* Add "OS_ENDPOINT" to the list of environment variables forwarded to the
  functional test environments in order to ease local testing.

Change-Id: I54a43a1e844e92730afbf87316b9efe73a08d850
(cherry picked from commit dd4112acea)
2019-09-20 14:34:38 -05:00
pengyuesheng
5c31e34202 Add lower-constraints job
create a tox environment for running the unit tests against the lower
bounds of the dependencies.

Add openstack-tox-lower-constraints job to the zuul configuration.

See http://lists.openstack.org/pipermail/openstack-dev/2018-March/128352.html
for more details.

Change-Id: Iae676c4bbd00836cc6dce0f083f7aa308bbfc372
(cherry picked from commit 3010383f10)
2019-09-20 14:34:30 -05:00
22e9ffdb8b Update TOX/UPPER_CONSTRAINTS_FILE for stable/train
Update the URL to the upper-constraints file to point to the redirect
rule on releases.openstack.org so that anyone working on this branch
will switch to the correct upper-constraints list automatically when
the requirements repository branches.

Until the requirements repository has as stable/train branch, tests will
continue to use the upper-constraints list on master.

Change-Id: I2bc755e71ad06ebbb4aef23b25aa1cf310d0b897
2019-09-20 16:44:53 +00:00
e251e5c451 Update .gitreview for stable/train
Change-Id: Ia90ce3ac73c87953fc379d43c8005e24e57c5db5
2019-09-20 16:44:48 +00:00
43 changed files with 153 additions and 546 deletions

View File

@@ -2,4 +2,4 @@
host=review.opendev.org
port=29418
project=openstack/python-cloudkittyclient.git
defaultbranch=unmaintained/xena
defaultbranch=stable/train

View File

@@ -21,8 +21,6 @@
cloudkitty: https://opendev.org/openstack/cloudkitty
devstack_localrc:
CLOUDKITTY_FETCHER: keystone
DEVSTACK_GATE_USE_PYTHON3: "True"
USE_PYTHON3: True
devstack_services:
ck-api: true
horizon: false
@@ -41,24 +39,54 @@
vars:
tox_envlist: functional-v2
- job:
name: cloudkittyclient-devstack-functional-base-py3
parent: cloudkittyclient-devstack-functional-base
description: |
Job for cloudkittyclient functional tests, ran in python3.
vars:
devstack_localrc:
DEVSTACK_GATE_USE_PYTHON3: "True"
USE_PYTHON3: "True"
- job:
name: cloudkittyclient-devstack-functional-v1-client-py3
parent: cloudkittyclient-devstack-functional-base-py3
vars:
tox_envlist: functional-v1
- job:
name: cloudkittyclient-devstack-functional-v2-client-py3
parent: cloudkittyclient-devstack-functional-base-py3
vars:
tox_envlist: functional-v2
- project:
templates:
- openstack-lower-constraints-jobs
- check-requirements
- openstack-cover-jobs
- openstack-python3-xena-jobs
- openstack-python-jobs
- openstack-python3-train-jobs
- openstackclient-plugin-jobs
- publish-openstack-docs-pti
- release-notes-jobs-python3
check:
jobs:
- cloudkittyclient-devstack-functional-v1-client:
voting: true
- cloudkittyclient-devstack-functional-v2-client:
voting: true
- cloudkittyclient-devstack-functional-v1-client-py3:
voting: true
- cloudkittyclient-devstack-functional-v2-client-py3:
voting: true
gate:
jobs:
- cloudkittyclient-devstack-functional-v1-client:
voting: true
- cloudkittyclient-devstack-functional-v2-client:
voting: true
- cloudkittyclient-devstack-functional-v1-client-py3:
voting: true
- cloudkittyclient-devstack-functional-v2-client-py3:
voting: true

View File

@@ -1,19 +1,16 @@
The source repository for this project can be found at:
https://opendev.org/openstack/python-cloudkittyclient
If you would like to contribute to the development of OpenStack,
you must follow the steps in this page:
Pull requests submitted through GitHub are not monitored.
https://docs.openstack.org/infra/manual/developers.html
To start contributing to OpenStack, follow the steps in the contribution guide
to set up and use Gerrit:
Once those steps have been completed, changes to OpenStack
should be submitted for review via the Gerrit tool, following
the workflow documented at:
https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
https://docs.openstack.org/infra/manual/developers.html#development-workflow
Bugs should be filed on Storyboard:
Pull requests submitted through GitHub will be ignored.
https://storyboard.openstack.org/#!/project/895
Bugs should be filed on Storyboard, not GitHub:
For more specific information about contributing to this repository, see the
python-cloudkittyclient contributor guide:
https://docs.openstack.org/python-cloudkittyclient/latest/contributor/contributing.html
https://storyboard.openstack.org/#!/project/openstack/python-cloudkittyclient

2
babel.cfg Normal file
View File

@@ -0,0 +1,2 @@
[python: **.py]

View File

@@ -12,24 +12,13 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from string import Formatter as StringFormatter
from urllib.parse import urlencode
from cloudkittyclient import utils
from six.moves.urllib.parse import urlencode
class HttpDecoratorMeta(type):
ignore = ('get_url', )
def __new__(cls, *args, **kwargs):
return utils.format_http_errors(HttpDecoratorMeta.ignore)(
super(HttpDecoratorMeta, cls).__new__(cls, *args, **kwargs)
)
class BaseManager(object, metaclass=HttpDecoratorMeta):
class BaseManager(object):
"""Base class for Endpoint Manager objects."""
url = ''

View File

@@ -94,7 +94,7 @@ class CloudKittyShell(cliff.app.App):
super(CloudKittyShell, self).__init__(
description='CloudKitty CLI client',
version=utils.get_version(),
command_manager=CommandManager('cloudkittyclient_v{}'.format(
command_manager=CommandManager('cloudkittyclient.v{}'.format(
self._get_api_version(args[:]),
)),
deferred_help=True,

View File

@@ -139,7 +139,7 @@ class CkDataframesTest(base.BaseFunctionalTest):
def test_dataframes_add_with_no_args(self):
self.assertRaisesRegexp(
RuntimeError,
'error: the following arguments are required: datafile',
'error: too few arguments',
self.runner,
'dataframes add',
fmt='',
@@ -162,11 +162,6 @@ class CkDataframesTest(base.BaseFunctionalTest):
has_output=False,
)
def test_dataframes_get(self):
# TODO(jferrieu): functional tests will be added in another
# patch for `dataframes get`
pass
class OSCDataframesTest(CkDataframesTest):
def __init__(self, *args, **kwargs):

View File

@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
from unittest import mock
import mock
from cloudkittyclient import exc
from cloudkittyclient.tests.unit.v1 import base

View File

@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
#
from collections import abc
from unittest import mock
import collections
import mock
from cloudkittyclient.tests.unit.v1 import base
from cloudkittyclient.v1 import report_cli
@@ -57,7 +57,7 @@ class TestReportCli(base.BaseAPIEndpointTestCase):
assert len(result) == 2
assert result[0] == ('Tenant ID', )
assert isinstance(result[1], abc.Iterable)
assert isinstance(result[1], collections.Iterable)
for res in result[1]:
assert isinstance(res, abc.Iterable)
assert isinstance(res, collections.Iterable)

View File

@@ -12,10 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from cloudkittyclient.tests import utils
from cloudkittyclient.v2 import dataframes
from cloudkittyclient.v2.rating import modules
from cloudkittyclient.v2 import scope
from cloudkittyclient.v2 import summary
@@ -28,4 +26,3 @@ class BaseAPIEndpointTestCase(utils.BaseTestCase):
self.dataframes = dataframes.DataframesManager(self.api_client)
self.scope = scope.ScopeManager(self.api_client)
self.summary = summary.SummaryManager(self.api_client)
self.rating = modules.RatingManager(self.api_client)

View File

@@ -14,8 +14,6 @@
#
import json
from collections import OrderedDict
from cloudkittyclient import exc
from cloudkittyclient.tests.unit.v2 import base
@@ -151,22 +149,3 @@ class TestDataframes(base.BaseAPIEndpointTestCase):
self.assertRaises(
exc.ArgumentRequired,
self.dataframes.add_dataframes)
def test_get_dataframes(self):
self.dataframes.get_dataframes()
self.api_client.get.assert_called_once_with('/v2/dataframes')
def test_get_dataframes_with_pagination_args(self):
self.dataframes.get_dataframes(offset=10, limit=10)
try:
self.api_client.get.assert_called_once_with(
'/v2/dataframes?limit=10&offset=10')
except AssertionError:
self.api_client.get.assert_called_once_with(
'/v2/dataframes?offset=10&limit=10')
def test_get_dataframes_filters(self):
self.dataframes.get_dataframes(
filters=OrderedDict([('one', 'two'), ('three', 'four')]))
self.api_client.get.assert_called_once_with(
'/v2/dataframes?filters=one%3Atwo%2Cthree%3Afour')

View File

@@ -1,38 +0,0 @@
# Copyright 2019 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 cloudkittyclient.tests.unit.v2 import base
class TestRating(base.BaseAPIEndpointTestCase):
def test_get_modules(self):
self.rating.get_module()
self.api_client.get.assert_called_once_with('/v2/rating/modules')
def test_get_one_module(self):
self.rating.get_module(module_id="moduleidtest")
self.api_client.get.assert_called_once_with(
'/v2/rating/modules/moduleidtest')
def test_update_one_module(self):
self.rating.update_module(module_id="moduleidtest",
enabled=False, priority=42)
self.api_client.put.assert_called_once_with(
'/v2/rating/modules/moduleidtest',
json={
'enabled': False,
'priority': 42,
})

View File

@@ -12,13 +12,12 @@
# 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 unittest import mock
import fixtures
import testtools
from keystoneauth1 import adapter
from keystoneauth1 import session
import mock
class BaseTestCase(testtools.TestCase):

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Objectif Libre
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -12,12 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
#
import inspect
import sys
import pbr.version
from keystoneauth1.exceptions import http
from oslo_utils import timeutils
@@ -59,44 +56,3 @@ def list_to_cols(list_obj, cols):
for item in list_obj:
values.append(dict_to_cols(item, cols))
return values
def http_error_formatter(func):
"""This decorator catches Http Errors and re-formats them"""
def wrap(*args, **kwargs):
try:
return func(*args, **kwargs)
except http.HttpError as e:
raise http.HttpError(message=e.response.text,
http_status=e.http_status)
return wrap
def format_http_errors(ignore):
"""Applies ``http_error_formatter`` to all methods of a class.
:param ignore: List of function names to ignore
:type ignore: iterable
"""
def wrap(cls):
# If you want pretty errors, use python3.
# __qualname__ does not exist in python 2
if sys.version_info.major < 3:
return cls
def predicate(item):
# This avoids decorating functions of parent classes
return (inspect.isfunction(item)
and item.__name__ not in ignore
and not item.__name__.startswith('_')
and cls.__name__ in item.__qualname__)
for name, func in inspect.getmembers(cls, predicate):
setattr(cls, name, http_error_formatter(func))
return cls
return wrap

View File

@@ -172,7 +172,7 @@ class HashmapManager(base.BaseManager):
:param value: Value of the mapping
:type value: str
"""
if kwargs.get('cost') is None:
if not kwargs.get('cost'):
raise exc.ArgumentRequired("'cost' argument is required")
if not kwargs.get('value'):
if not kwargs.get('service_id'):
@@ -373,7 +373,7 @@ class HashmapManager(base.BaseManager):
:type level: str
"""
for arg in ['cost', 'level']:
if kwargs.get(arg) is None:
if not kwargs.get(arg):
raise exc.ArgumentRequired(
"'{}' argument is required".format(arg))
if not kwargs.get('service_id') and not kwargs.get('field_id'):

View File

@@ -15,7 +15,6 @@
#
from cloudkittyclient.v1 import client
from cloudkittyclient.v2 import dataframes
from cloudkittyclient.v2.rating import modules
from cloudkittyclient.v2 import scope
from cloudkittyclient.v2 import summary
@@ -41,4 +40,3 @@ class Client(client.Client):
self.dataframes = dataframes.DataframesManager(self.api_client)
self.scope = scope.ScopeManager(self.api_client)
self.summary = summary.SummaryManager(self.api_client)
self.rating = modules.RatingManager(self.api_client)

View File

@@ -13,6 +13,7 @@
# under the License.
#
import json
import six
from cloudkittyclient.common import base
from cloudkittyclient import exc
@@ -35,7 +36,7 @@ class DataframesManager(base.BaseManager):
if not dataframes:
raise exc.ArgumentRequired("'dataframes' argument is required")
if not isinstance(dataframes, str):
if not isinstance(dataframes, six.string_types):
try:
dataframes = json.dumps(dataframes)
except TypeError:
@@ -48,30 +49,3 @@ class DataframesManager(base.BaseManager):
url,
data=dataframes,
)
def get_dataframes(self, **kwargs):
"""Returns a paginated list of DataFrames.
This support filters and datetime framing.
:param offset: Index of the first dataframe that should be returned.
:type offset: int
:param limit: Maximal number of dataframes to return.
:type limit: int
:param filters: Optional dict of filters to select data on.
:type filters: dict
:param begin: Start of the period to gather data from
:type begin: datetime.datetime
:param end: End of the period to gather data from
:type end: datetime.datetime
"""
kwargs['filters'] = ','.join(
'{}:{}'.format(k, v) for k, v in
(kwargs.get('filters', None) or {}).items()
)
authorized_args = [
'offset', 'limit', 'filters', 'begin', 'end']
url = self.get_url(None, kwargs, authorized_args=authorized_args)
return self.api_client.get(url).json()

View File

@@ -15,8 +15,6 @@
import argparse
from cliff import command
from cliff import lister
from oslo_utils import timeutils
from cloudkittyclient import utils
@@ -42,75 +40,3 @@ class CliDataframesAdd(command.Command):
utils.get_client_from_osc(self).dataframes.add_dataframes(
dataframes=dataframes,
)
class CliDataframesGet(lister.Lister):
"""Get dataframes from the storage backend."""
columns = [
('begin', 'Begin'),
('end', 'End'),
('metric', 'Metric Type'),
('unit', 'Unit'),
('qty', 'Quantity'),
('price', 'Price'),
('groupby', 'Group By'),
('metadata', 'Metadata'),
]
def get_parser(self, prog_name):
parser = super(CliDataframesGet, self).get_parser(prog_name)
def filter_(elem):
if len(elem.split(':')) != 2:
raise TypeError
return str(elem)
parser.add_argument('--offset', type=int, default=0,
help='Index of the first dataframe')
parser.add_argument('--limit', type=int, default=100,
help='Maximal number of dataframes')
parser.add_argument('--filter', type=filter_, action='append',
help="Optional filter, in 'key:value' format. Can "
"be specified several times.")
parser.add_argument('-b', '--begin', type=timeutils.parse_isotime,
help="Start of the period to query, in iso8601 "
"format. Example: 2019-05-01T00:00:00Z.")
parser.add_argument('-e', '--end', type=timeutils.parse_isotime,
help="End of the period to query, in iso8601 "
"format. Example: 2019-06-01T00:00:00Z.")
return parser
def take_action(self, parsed_args):
filters = dict(elem.split(':') for elem in (parsed_args.filter or []))
dataframes = utils.get_client_from_osc(self).dataframes.get_dataframes(
offset=parsed_args.offset,
limit=parsed_args.limit,
begin=parsed_args.begin,
end=parsed_args.end,
filters=filters,
).get('dataframes', [])
def format_(d):
return ' '.join([
'{}="{}"'.format(k, v) for k, v in (d or {}).items()])
values = []
for df in dataframes:
period = df['period']
usage = df['usage']
for metric_type, points in usage.items():
for point in points:
values.append([
period['begin'],
period['end'],
metric_type,
point['vol']['unit'],
point['vol']['qty'],
point['rating']['price'],
format_(point.get('groupby', {})),
format_(point.get('metadata', {})),
])
return [col[1] for col in self.columns], values

View File

@@ -1,59 +0,0 @@
# Copyright 2019 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 cloudkittyclient import exc
from cloudkittyclient.v1.client import rating
class RatingManager(rating.RatingManager):
"""Class used to handle /v2/rating/modules endpoint"""
url = '/v2/rating/modules'
def get_module(self, **kwargs):
"""Returns the given module.
If module_id is not specified, returns the list of loaded modules.
:param module_id: ID of the module on which you want information.
:type module_id: str
"""
module_id = kwargs.get('module_id', None)
if module_id is not None:
url = "{}/{}".format(self.url, module_id)
else:
url = self.url
return self.api_client.get(url).json()
def update_module(self, **kwargs):
"""Update the given module.
:param module_id: Id of the module to update.
:type module_id: str
:param enabled: Set to True to enable the module, False to disable it.
:type enabled: bool
:param priority: New priority of the module.
:type priority: int
"""
if not kwargs.get('module_id', None):
raise exc.ArgumentRequired("'module_id' argument is required.")
mutable_fields = ['enabled', 'priority']
changes = {}
for key, value in kwargs.items():
if value is not None and key in mutable_fields:
changes[key] = value
self.api_client.put("{}/{}".format(self.url, kwargs['module_id']),
json=changes)
return self.get_module(**kwargs)

View File

@@ -1,29 +0,0 @@
# Copyright 2019 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 cliff import lister
from cloudkittyclient import utils
class CliModuleList(lister.Lister):
"""Get loaded rating modules list"""
def get_parser(self, prog_name):
parser = super(CliModuleList, self).get_parser(prog_name)
return parser
def take_action(self, parsed_args):
resp = utils.get_client_from_osc(self).ratingmodules.get_modules_list()
return resp['modules']

View File

@@ -3,7 +3,6 @@
# process, which may cause wedges in the gate later.
openstackdocstheme>=1.30.0 # Apache-2.0
sphinx>=1.8.0,!=2.1.0 # BSD
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
sphinx>=1.6.2,!=1.6.6,!=1.6.7,<2.0.0;python_version=='2.7' # BSD
sphinx>=1.6.2,!=1.6.6,!=1.6.7,!=2.1.0;python_version>='3.4' # BSD
reno>=2.5.0 # Apache-2.0
cliff>=2.11.0 # Apache-2.0

View File

@@ -5,17 +5,18 @@ CLI Reference
V1 Client
=========
.. autoprogram-cliff:: cloudkittyclient_v1
.. autoprogram-cliff:: cloudkittyclient.v1
:application: cloudkitty
V2 Client
=========
.. autoprogram-cliff:: cloudkittyclient_v2
.. autoprogram-cliff:: cloudkittyclient.v2
:command: dataframes add
.. autoprogram-cliff:: cloudkittyclient_v2
.. autoprogram-cliff:: cloudkittyclient.v2
:command: scope state get
.. autoprogram-cliff:: cloudkittyclient_v2
.. autoprogram-cliff:: cloudkittyclient.v2
:command: summary get

View File

@@ -23,11 +23,8 @@ extensions = [
'cliff.sphinxext',
'sphinx.ext.autodoc',
'openstackdocstheme',
'sphinxcontrib.rsvgconverter',
]
autoprogram_cliff_application = 'cloudkitty'
autoprogram_cliff_ignored = [
"--format", "--column", "--max-width", "--fit-width", "--print-empty",
"--format-config-file", "--noindent", "--quote", "--sort-column",
@@ -60,7 +57,7 @@ add_function_parentheses = True
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'native'
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
@@ -77,30 +74,14 @@ html_last_updated_fmt = '%Y-%m-%d %H:%M'
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# -- Options for LaTeX output ---------------------------------------------
# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664
latex_use_xindy = False
latex_domain_indices = False
latex_elements = {
'makeindex': '',
'printindex': '',
'preamble': r'\setcounter{tocdepth}{3}',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
# NOTE: Specify toctree_only=True for a better document structure of
# the generated PDF file.
latex_documents = [
('index',
'doc-%s.tex' % project,
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'howto', True),
u'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.

View File

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

View File

@@ -1,47 +0,0 @@
============================
So You Want to Contribute...
============================
For general information on contributing to OpenStack, please check out the
`contributor guide <https://docs.openstack.org/contributors/>`_ to get started.
It covers all the basics that are common to all OpenStack projects: the accounts
you need, the basics of interacting with our Gerrit review system, how we
communicate as a community, etc.
Below will cover the more project specific information you need to get started
with python-cloudkittyclient.
Communication
~~~~~~~~~~~~~
* IRC channel #cloudkitty at `OFTC <http://oftc.net>`_
* Mailing list (prefix subjects with ``[cloudkitty]`` for faster responses)
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss
Contacting the Core Team
~~~~~~~~~~~~~~~~~~~~~~~~
Please refer the `python-cloudkittyclient Core Team
<https://review.opendev.org/admin/groups/4ac765c35f985b3ad9226da07fdcc205c1ce4fe1,members>`_ contacts.
New Feature Planning
~~~~~~~~~~~~~~~~~~~~
Cloudkitty features are tracked on `Storyboard <https://storyboard.openstack.org/#!/project/895>`_.
Task Tracking
~~~~~~~~~~~~~
We track our tasks in `Storyboard <https://storyboard.openstack.org/#!/project/895>`_.
If you're looking for some smaller, easier work item to pick up and get started
on, search for the 'low-hanging-fruit' tag.
Reporting a Bug
~~~~~~~~~~~~~~~
You found an issue and want to make sure we are aware of it? You can do so on
`StoryBoard <https://storyboard.openstack.org/#!/project/895>`_.
Getting Your Patch Merged
~~~~~~~~~~~~~~~~~~~~~~~~~
All changes proposed to the python-cloudkittyclient project require one or two +2 votes
from python-cloudkittyclient core reviewers before one of the core reviewers can approve
patch by giving ``Workflow +1`` vote.
Project Team Lead Duties
~~~~~~~~~~~~~~~~~~~~~~~~
All common PTL duties are enumerated in the `PTL guide
<https://docs.openstack.org/project-team-guide/ptl.html>`_.

View File

@@ -12,19 +12,10 @@ Contents:
install
usage
contributor
cli_reference
api_reference/index
For Contributors
================
* If you are a new contributor to python-cloudkittyclient please refer: :doc:`contributor/contributing`
.. toctree::
:hidden:
contributor/contributing
Indices and tables
==================

View File

@@ -1,20 +1,21 @@
# requirements
pbr==5.5.1 # Apache-2.0
cliff==3.5.0 # Apache-2.0
keystoneauth1==4.3.0 # Apache-2.0
oslo.utils==4.7.0 # Apache-2.0
oslo.log==4.4.0 # Apache-2.0
PyYAML==5.3.1 # MIT
jsonpath-rw-ext==1.2.0 # Apache-2.0
os-client-config==2.1.0 # Apache-2.0
osc-lib==2.3.0 # Apache-2.0
pbr==2.0.0 # Apache-2.0
cliff==2.11.0 # Apache-2.0
keystoneauth1==3.4.0 # Apache-2.0
oslo.utils==3.35 # Apache-2.0
oslo.log==3.36 # Apache-2.0
PyYAML==3.12 # MIT
jsonpath-rw-ext==1.0 # Apache-2.0
six==1.11 # MIT
os-client-config==1.29.0 # Apache-2.0
osc-lib==1.12.1 # Apache-2.0
# test-requirements.txt
pyflakes==2.1.1
coverage==4.0 # Apache-2.0
python-subunit==1.4.0 # Apache-2.0/BSD
python-subunit==0.0.18 # Apache-2.0/BSD
oslotest==1.10.0 # Apache-2.0
stestr==2.0 # Apache-2.0
mock==2.0 # BSD
python-openstackclient==3.14 # Apache-2.0
# doc/requirements.txt

View File

@@ -1,5 +0,0 @@
---
features:
- |
Support for the ``GET /v2/dataframes`` endpoint has been added
to the client. A new ``dataframes get`` CLI command is also available.

View File

@@ -1,7 +0,0 @@
---
upgrade:
- |
Python 2.7 support has been dropped. The last release of
``cloudkittyclient`` to support python 2.7 is OpenStack Train (3.1.0).
The minimum version of Python now supported by ``cloudkittyclient``
is Python 3.6.

View File

@@ -1,8 +0,0 @@
---
fixes:
- |
Fix `create_threshold` method when using cost as 0.
When using 0 as the cost, the `create_threshold` method
throws an exception. That happens because 0 (zero) is evaluated
to False. Therefore, we need to change the validation method to
check if the values are None.

View File

@@ -1,4 +0,0 @@
---
fixes:
- |
Fixes creation of hashmap mappings with a zero cost.

View File

@@ -82,7 +82,7 @@ exclude_patterns = []
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'native'
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

View File

@@ -8,10 +8,6 @@ Contents
:maxdepth: 2
unreleased
wallaby
victoria
ussuri
train
stein
rocky
queens

View File

@@ -1,6 +0,0 @@
==========================
Train Series Release Notes
==========================
.. release-notes::
:branch: stable/train

View File

@@ -1,6 +0,0 @@
===========================
Ussuri Series Release Notes
===========================
.. release-notes::
:branch: stable/ussuri

View File

@@ -1,6 +0,0 @@
=============================
Victoria Series Release Notes
=============================
.. release-notes::
:branch: stable/victoria

View File

@@ -1,6 +0,0 @@
============================
Wallaby Series Release Notes
============================
.. release-notes::
:branch: stable/wallaby

View File

@@ -2,12 +2,13 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=5.5.1 # Apache-2.0
cliff>=3.5.0 # Apache-2.0
keystoneauth1>=4.3.0 # Apache-2.0
oslo.utils>=4.7.0 # Apache-2.0
oslo.log>=4.4.0 # Apache-2.0
PyYAML>=5.3.1 # MIT
jsonpath-rw-ext>=1.2.0 # Apache-2.0
os-client-config>=2.1.0 # Apache-2.0
osc-lib>=2.3.0 # Apache-2.0
pbr>=2.0.0,!=2.1.0 # Apache-2.0
cliff>=2.11.0 # Apache-2.0
keystoneauth1>=3.4.0 # Apache-2.0
oslo.utils>=3.35 # Apache-2.0
oslo.log>=3.36 # Apache-2.0
PyYAML>=3.12 # MIT
jsonpath-rw-ext>=1.0 # Apache-2.0
six>=1.11 # MIT
os-client-config>=1.29.0 # Apache-2.0
osc-lib>=1.12.1 # Apache-2.0

View File

@@ -1,12 +1,11 @@
[metadata]
name = python-cloudkittyclient
summary = API client of cloudkitty, Rating as a Service project.
description_file =
description-file =
README.rst
author = OpenStack
author_email = openstack-discuss@lists.openstack.org
home_page = https://docs.openstack.org/python-cloudkittyclient/latest/
python_requires = >=3.6
author-email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/python-cloudkittyclient/latest/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -14,12 +13,11 @@ classifier =
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
[files]
packages =
@@ -88,7 +86,6 @@ openstack.rating.v1 =
rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
openstack.rating.v2 =
rating_dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
rating_dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
rating_scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
@@ -140,6 +137,7 @@ openstack.rating.v2 =
rating_collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
rating_collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
rating_collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
rating_dataframes_get = cloudkittyclient.v1.storage_cli:CliGetDataframes
rating_pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
rating_pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
@@ -147,7 +145,7 @@ openstack.rating.v2 =
rating_pyscript_update = cloudkittyclient.v1.rating.pyscripts_cli:CliUpdateScript
rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
cloudkittyclient_v1 =
cloudkittyclient.v1 =
total_get = cloudkittyclient.v1.report_cli:CliTotalGet
summary_get = cloudkittyclient.v1.report_cli:CliSummaryGet
report_tenant_list = cloudkittyclient.v1.report_cli:CliTenantList
@@ -203,9 +201,8 @@ cloudkittyclient_v1 =
pyscript_update = cloudkittyclient.v1.rating.pyscripts_cli:CliUpdateScript
pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
cloudkittyclient_v2 =
cloudkittyclient.v2 =
dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
scope_state_reset = cloudkittyclient.v2.scope_cli:CliScopeStateReset
@@ -257,6 +254,7 @@ cloudkittyclient_v2 =
collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
dataframes_get = cloudkittyclient.v1.storage_cli:CliGetDataframes
pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
@@ -269,3 +267,20 @@ keystoneauth1.plugin =
cliff.formatter.list =
df-to-csv = cloudkittyclient.format:DataframeToCsvFormatter
[upload_sphinx]
upload-dir = doc/build/html
[compile_catalog]
directory = cloudkittyclient/locale
domain = python-cloudkittyclient
[update_catalog]
domain = python-cloudkittyclient
output_dir = cloudkittyclient/locale
input_file = cloudkittyclient/locale/python-cloudkittyclient.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = cloudkittyclient/locale/python-cloudkittyclient.pot

View File

@@ -13,8 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
pbr=True)

View File

@@ -2,15 +2,11 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking>=3.0.1,<3.1.0 # Apache-2.0
# remove this pyflakes from here once you bump the
# hacking to 3.2.0 or above. hacking 3.2.0 takes
# care of pyflakes version compatibilty.
pyflakes>=2.1.1
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
coverage>=4.0,!=4.4 # Apache-2.0
python-subunit>=1.4.0 # Apache-2.0/BSD
python-subunit>=0.0.18 # Apache-2.0/BSD
oslotest>=1.10.0 # Apache-2.0
stestr>=2.0 # Apache-2.0
mock>=2.0 # BSD
python-openstackclient>=3.14 # Apache-2.0

37
tox.ini
View File

@@ -1,13 +1,11 @@
[tox]
minversion = 3.18.0
envlist = py3,pep8
minversion = 2.0
envlist = py27,py36,py37,pypy,pep8
skipsdist = True
ignore_basepython_conflict = True
[testenv]
basepython = python3
usedevelop = True
install_command = pip install -U {opts} {packages}
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train} -U {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/requirements.txt
@@ -15,6 +13,7 @@ deps = -r{toxinidir}/requirements.txt
commands = stestr run {posargs}
[testenv:cover]
basepython = python3
setenv =
VIRTUAL_ENV={envdir}
PYTHON=coverage run --source cloudkittyclient --parallel-mode
@@ -26,6 +25,7 @@ commands =
coverage report
[testenv:debug]
basepython = python3
commands = oslo_debug_helper -t cloudkittyclient/tests {posargs}
[testenv:functional-v1]
@@ -39,31 +39,23 @@ setenv = OS_RATING_API_VERSION=2
commands = stestr run --concurrency=1 --test-path ./cloudkittyclient/tests/functional/v2
[testenv:pep8]
basepython = python3
commands = flake8
[testenv:venv]
basepython = python3
commands = {posargs}
[testenv:docs]
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/xena}
-r{toxinidir}/doc/requirements.txt
commands = sphinx-build --keep-going -b html doc/source doc/build/html
[testenv:pdf-docs]
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
allowlist_externals =
make
commands =
sphinx-build --keep-going -b latex doc/source doc/build/pdf
make -C doc/build/pdf
basepython = python3
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -W -b html doc/source doc/build/html
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
ignore = E123,E125,W503,W504
ignore = E123,E125
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,releasenotes
@@ -71,13 +63,14 @@ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,releasenotes
import_exceptions = cloudkittyclient.i18n
[testenv:releasenotes]
basepython = python3
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/xena}
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
-r{toxinidir}/doc/requirements.txt
commands =
sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
[testenv:lower-constraints]
basepython = python3
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt