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
This commit is contained in:

committed by
Pierre Riteau

parent
def535752f
commit
2a3dd279dc
@@ -162,6 +162,11 @@ class CkDataframesTest(base.BaseFunctionalTest):
|
|||||||
has_output=False,
|
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):
|
class OSCDataframesTest(CkDataframesTest):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
#
|
#
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from cloudkittyclient import exc
|
from cloudkittyclient import exc
|
||||||
from cloudkittyclient.tests.unit.v2 import base
|
from cloudkittyclient.tests.unit.v2 import base
|
||||||
|
|
||||||
@@ -149,3 +151,22 @@ class TestDataframes(base.BaseAPIEndpointTestCase):
|
|||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exc.ArgumentRequired,
|
exc.ArgumentRequired,
|
||||||
self.dataframes.add_dataframes)
|
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')
|
||||||
|
@@ -48,3 +48,30 @@ class DataframesManager(base.BaseManager):
|
|||||||
url,
|
url,
|
||||||
data=dataframes,
|
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()
|
||||||
|
@@ -15,6 +15,8 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from cliff import command
|
from cliff import command
|
||||||
|
from cliff import lister
|
||||||
|
from oslo_utils import timeutils
|
||||||
|
|
||||||
from cloudkittyclient import utils
|
from cloudkittyclient import utils
|
||||||
|
|
||||||
@@ -40,3 +42,75 @@ class CliDataframesAdd(command.Command):
|
|||||||
utils.get_client_from_osc(self).dataframes.add_dataframes(
|
utils.get_client_from_osc(self).dataframes.add_dataframes(
|
||||||
dataframes=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
|
||||||
|
@@ -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.
|
@@ -88,6 +88,7 @@ openstack.rating.v1 =
|
|||||||
rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
|
rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
|
||||||
|
|
||||||
openstack.rating.v2 =
|
openstack.rating.v2 =
|
||||||
|
rating_dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
|
||||||
rating_dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
|
rating_dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
|
||||||
|
|
||||||
rating_scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
|
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_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
|
||||||
rating_collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
|
rating_collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
|
||||||
rating_collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
|
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_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
|
||||||
rating_pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
|
rating_pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
|
||||||
@@ -205,6 +205,7 @@ cloudkittyclient_v1 =
|
|||||||
|
|
||||||
cloudkittyclient_v2 =
|
cloudkittyclient_v2 =
|
||||||
dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
|
dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
|
||||||
|
dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
|
||||||
|
|
||||||
scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
|
scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
|
||||||
scope_state_reset = cloudkittyclient.v2.scope_cli:CliScopeStateReset
|
scope_state_reset = cloudkittyclient.v2.scope_cli:CliScopeStateReset
|
||||||
@@ -256,7 +257,6 @@ cloudkittyclient_v2 =
|
|||||||
collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
|
collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
|
||||||
collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
|
collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
|
||||||
collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
|
collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
|
||||||
dataframes_get = cloudkittyclient.v1.storage_cli:CliGetDataframes
|
|
||||||
|
|
||||||
pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
|
pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
|
||||||
pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
|
pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
|
||||||
|
Reference in New Issue
Block a user