Browse Source

Add support for GET /v2/dataframes API endpoint to the client

Support for the ``GET /v2/dataframes`` endpoint has been added
to the client. A new ``dataframes get`` CLI command is also available.

Story: 2005890
Task: 36384
Depends-On: https://review.opendev.org/#/c/679636
Change-Id: Idfe93025e0f740906d0f53f33547c7746fc15169
tags/4.1.0^0
Justin Ferrieu 1 year ago
committed by Pierre Riteau
parent
commit
2a3dd279dc
6 changed files with 134 additions and 2 deletions
  1. +5
    -0
      cloudkittyclient/tests/functional/v2/test_dataframes.py
  2. +21
    -0
      cloudkittyclient/tests/unit/v2/test_dataframes.py
  3. +27
    -0
      cloudkittyclient/v2/dataframes.py
  4. +74
    -0
      cloudkittyclient/v2/dataframes_cli.py
  5. +5
    -0
      releasenotes/notes/add-support-v2-dataframes-be3a17271f3c7188.yaml
  6. +2
    -2
      setup.cfg

+ 5
- 0
cloudkittyclient/tests/functional/v2/test_dataframes.py View File

@@ -162,6 +162,11 @@ 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):


+ 21
- 0
cloudkittyclient/tests/unit/v2/test_dataframes.py View File

@@ -14,6 +14,8 @@
#
import json

from collections import OrderedDict

from cloudkittyclient import exc
from cloudkittyclient.tests.unit.v2 import base

@@ -149,3 +151,22 @@ 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')

+ 27
- 0
cloudkittyclient/v2/dataframes.py View File

@@ -48,3 +48,30 @@ 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()

+ 74
- 0
cloudkittyclient/v2/dataframes_cli.py View File

@@ -15,6 +15,8 @@
import argparse

from cliff import command
from cliff import lister
from oslo_utils import timeutils

from cloudkittyclient import utils

@@ -40,3 +42,75 @@ 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

+ 5
- 0
releasenotes/notes/add-support-v2-dataframes-be3a17271f3c7188.yaml View File

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

+ 2
- 2
setup.cfg View File

@@ -88,6 +88,7 @@ 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
@@ -139,7 +140,6 @@ 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
@@ -205,6 +205,7 @@ cloudkittyclient_v1 =

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
@@ -256,7 +257,6 @@ 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


Loading…
Cancel
Save