Skip to content

Commit 2a3dd27

Browse files
phunxpriteau
authored andcommitted
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
1 parent def5357 commit 2a3dd27

6 files changed

Lines changed: 134 additions & 2 deletions

File tree

cloudkittyclient/tests/functional/v2/test_dataframes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ def test_dataframes_add_with_hyphen_stdin(self):
162162
has_output=False,
163163
)
164164

165+
def test_dataframes_get(self):
166+
# TODO(jferrieu): functional tests will be added in another
167+
# patch for `dataframes get`
168+
pass
169+
165170

166171
class OSCDataframesTest(CkDataframesTest):
167172
def __init__(self, *args, **kwargs):

cloudkittyclient/tests/unit/v2/test_dataframes.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#
1515
import json
1616

17+
from collections import OrderedDict
18+
1719
from cloudkittyclient import exc
1820
from cloudkittyclient.tests.unit.v2 import base
1921

@@ -149,3 +151,22 @@ def test_add_dataframes_with_no_args_raises_exc(self):
149151
self.assertRaises(
150152
exc.ArgumentRequired,
151153
self.dataframes.add_dataframes)
154+
155+
def test_get_dataframes(self):
156+
self.dataframes.get_dataframes()
157+
self.api_client.get.assert_called_once_with('/v2/dataframes')
158+
159+
def test_get_dataframes_with_pagination_args(self):
160+
self.dataframes.get_dataframes(offset=10, limit=10)
161+
try:
162+
self.api_client.get.assert_called_once_with(
163+
'/v2/dataframes?limit=10&offset=10')
164+
except AssertionError:
165+
self.api_client.get.assert_called_once_with(
166+
'/v2/dataframes?offset=10&limit=10')
167+
168+
def test_get_dataframes_filters(self):
169+
self.dataframes.get_dataframes(
170+
filters=OrderedDict([('one', 'two'), ('three', 'four')]))
171+
self.api_client.get.assert_called_once_with(
172+
'/v2/dataframes?filters=one%3Atwo%2Cthree%3Afour')

cloudkittyclient/v2/dataframes.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,30 @@ def add_dataframes(self, **kwargs):
4848
url,
4949
data=dataframes,
5050
)
51+
52+
def get_dataframes(self, **kwargs):
53+
"""Returns a paginated list of DataFrames.
54+
55+
This support filters and datetime framing.
56+
57+
:param offset: Index of the first dataframe that should be returned.
58+
:type offset: int
59+
:param limit: Maximal number of dataframes to return.
60+
:type limit: int
61+
:param filters: Optional dict of filters to select data on.
62+
:type filters: dict
63+
:param begin: Start of the period to gather data from
64+
:type begin: datetime.datetime
65+
:param end: End of the period to gather data from
66+
:type end: datetime.datetime
67+
"""
68+
kwargs['filters'] = ','.join(
69+
'{}:{}'.format(k, v) for k, v in
70+
(kwargs.get('filters', None) or {}).items()
71+
)
72+
73+
authorized_args = [
74+
'offset', 'limit', 'filters', 'begin', 'end']
75+
76+
url = self.get_url(None, kwargs, authorized_args=authorized_args)
77+
return self.api_client.get(url).json()

cloudkittyclient/v2/dataframes_cli.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import argparse
1616

1717
from cliff import command
18+
from cliff import lister
19+
from oslo_utils import timeutils
1820

1921
from cloudkittyclient import utils
2022

@@ -40,3 +42,75 @@ def take_action(self, parsed_args):
4042
utils.get_client_from_osc(self).dataframes.add_dataframes(
4143
dataframes=dataframes,
4244
)
45+
46+
47+
class CliDataframesGet(lister.Lister):
48+
"""Get dataframes from the storage backend."""
49+
columns = [
50+
('begin', 'Begin'),
51+
('end', 'End'),
52+
('metric', 'Metric Type'),
53+
('unit', 'Unit'),
54+
('qty', 'Quantity'),
55+
('price', 'Price'),
56+
('groupby', 'Group By'),
57+
('metadata', 'Metadata'),
58+
]
59+
60+
def get_parser(self, prog_name):
61+
parser = super(CliDataframesGet, self).get_parser(prog_name)
62+
63+
def filter_(elem):
64+
if len(elem.split(':')) != 2:
65+
raise TypeError
66+
return str(elem)
67+
68+
parser.add_argument('--offset', type=int, default=0,
69+
help='Index of the first dataframe')
70+
parser.add_argument('--limit', type=int, default=100,
71+
help='Maximal number of dataframes')
72+
parser.add_argument('--filter', type=filter_, action='append',
73+
help="Optional filter, in 'key:value' format. Can "
74+
"be specified several times.")
75+
parser.add_argument('-b', '--begin', type=timeutils.parse_isotime,
76+
help="Start of the period to query, in iso8601 "
77+
"format. Example: 2019-05-01T00:00:00Z.")
78+
parser.add_argument('-e', '--end', type=timeutils.parse_isotime,
79+
help="End of the period to query, in iso8601 "
80+
"format. Example: 2019-06-01T00:00:00Z.")
81+
82+
return parser
83+
84+
def take_action(self, parsed_args):
85+
filters = dict(elem.split(':') for elem in (parsed_args.filter or []))
86+
87+
dataframes = utils.get_client_from_osc(self).dataframes.get_dataframes(
88+
offset=parsed_args.offset,
89+
limit=parsed_args.limit,
90+
begin=parsed_args.begin,
91+
end=parsed_args.end,
92+
filters=filters,
93+
).get('dataframes', [])
94+
95+
def format_(d):
96+
return ' '.join([
97+
'{}="{}"'.format(k, v) for k, v in (d or {}).items()])
98+
99+
values = []
100+
for df in dataframes:
101+
period = df['period']
102+
usage = df['usage']
103+
for metric_type, points in usage.items():
104+
for point in points:
105+
values.append([
106+
period['begin'],
107+
period['end'],
108+
metric_type,
109+
point['vol']['unit'],
110+
point['vol']['qty'],
111+
point['rating']['price'],
112+
format_(point.get('groupby', {})),
113+
format_(point.get('metadata', {})),
114+
])
115+
116+
return [col[1] for col in self.columns], values
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Support for the ``GET /v2/dataframes`` endpoint has been added
5+
to the client. A new ``dataframes get`` CLI command is also available.

setup.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ openstack.rating.v1 =
8888
rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript
8989

9090
openstack.rating.v2 =
91+
rating_dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
9192
rating_dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
9293

9394
rating_scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
@@ -139,7 +140,6 @@ openstack.rating.v2 =
139140
rating_collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
140141
rating_collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
141142
rating_collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
142-
rating_dataframes_get = cloudkittyclient.v1.storage_cli:CliGetDataframes
143143

144144
rating_pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
145145
rating_pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts
@@ -205,6 +205,7 @@ cloudkittyclient_v1 =
205205

206206
cloudkittyclient_v2 =
207207
dataframes_add = cloudkittyclient.v2.dataframes_cli:CliDataframesAdd
208+
dataframes_get = cloudkittyclient.v2.dataframes_cli:CliDataframesGet
208209

209210
scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet
210211
scope_state_reset = cloudkittyclient.v2.scope_cli:CliScopeStateReset
@@ -256,7 +257,6 @@ cloudkittyclient_v2 =
256257
collector_state_get = cloudkittyclient.v1.collector_cli:CliCollectorGetState
257258
collector_enable = cloudkittyclient.v1.collector_cli:CliCollectorEnable
258259
collector_disable = cloudkittyclient.v1.collector_cli:CliCollectorDisable
259-
dataframes_get = cloudkittyclient.v1.storage_cli:CliGetDataframes
260260

261261
pyscript_create = cloudkittyclient.v1.rating.pyscripts_cli:CliCreateScript
262262
pyscript_list = cloudkittyclient.v1.rating.pyscripts_cli:CliListScripts

0 commit comments

Comments
 (0)