From d740e3767219e6dd980fc10005ef110752ec406a Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 4 Feb 2013 19:11:50 +0100 Subject: [PATCH] Add support for v2 API Change-Id: I861e53db5446d2e3dc49935ea1cdd1607cff0a2a Signed-off-by: Julien Danjou --- ceilometerclient/common/base.py | 7 ++- ceilometerclient/v2/__init__.py | 16 ++++++ ceilometerclient/v2/client.py | 35 ++++++++++++ ceilometerclient/v2/samples.py | 48 +++++++++++++++++ ceilometerclient/v2/statistics.py | 31 +++++++++++ tests/v2/__init__.py | 0 tests/v2/test_samples.py | 82 ++++++++++++++++++++++++++++ tests/v2/test_statistics.py | 90 +++++++++++++++++++++++++++++++ 8 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 ceilometerclient/v2/__init__.py create mode 100644 ceilometerclient/v2/client.py create mode 100644 ceilometerclient/v2/samples.py create mode 100644 ceilometerclient/v2/statistics.py create mode 100644 tests/v2/__init__.py create mode 100644 tests/v2/test_samples.py create mode 100644 tests/v2/test_statistics.py diff --git a/ceilometerclient/common/base.py b/ceilometerclient/common/base.py index 057ef90c..c29ac183 100644 --- a/ceilometerclient/common/base.py +++ b/ceilometerclient/common/base.py @@ -49,13 +49,16 @@ class Manager(object): def __init__(self, api): self.api = api - def _list(self, url, response_key, obj_class=None, body=None): + def _list(self, url, response_key=None, obj_class=None, body=None): resp, body = self.api.json_request('GET', url) if obj_class is None: obj_class = self.resource_class - data = body[response_key] + if response_key: + data = body[response_key] + else: + data = body return [obj_class(self, res, loaded=True) for res in data if res] def _delete(self, url): diff --git a/ceilometerclient/v2/__init__.py b/ceilometerclient/v2/__init__.py new file mode 100644 index 00000000..07a4feb9 --- /dev/null +++ b/ceilometerclient/v2/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2012 OpenStack LLC. +# 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 ceilometerclient.v2.client import Client diff --git a/ceilometerclient/v2/client.py b/ceilometerclient/v2/client.py new file mode 100644 index 00000000..82b29e05 --- /dev/null +++ b/ceilometerclient/v2/client.py @@ -0,0 +1,35 @@ +# Copyright 2012 OpenStack LLC. +# 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 ceilometerclient.common import http +from ceilometerclient.v2 import samples +from ceilometerclient.v2 import statistics + + +class Client(http.HTTPClient): + """Client for the Ceilometer v2 API. + + :param string endpoint: A user-supplied endpoint URL for the ceilometer + service. + :param string token: Token for authentication. + :param integer timeout: Allows customization of the timeout for client + http requests. (optional) + """ + + def __init__(self, *args, **kwargs): + """ Initialize a new client for the Ceilometer v1 API. """ + super(Client, self).__init__(*args, **kwargs) + self.samples = samples.SampleManager(self) + self.statistics = statistics.StatisticsManager(self) diff --git a/ceilometerclient/v2/samples.py b/ceilometerclient/v2/samples.py new file mode 100644 index 00000000..f7e42686 --- /dev/null +++ b/ceilometerclient/v2/samples.py @@ -0,0 +1,48 @@ +# Copyright 2012 OpenStack LLC. +# 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 urllib + +from ceilometerclient.common import base + + +class Sample(base.Resource): + def __repr__(self): + return "" % self._info + + +class SampleManager(base.Manager): + resource_class = Sample + + @staticmethod + def build_url(path, q): + if q: + query_params = {'q.field': [], + 'q.value': [], + 'q.op': []} + + for query in q: + for name in ['field', 'op', 'value']: + query_params['q.%s' % name].append(query.get(name, '')) + + path += "?" + urllib.urlencode(query_params, doseq=True) + + return path + + def list(self, meter_name=None, q=None): + path = '/v2/meters' + if meter_name: + path += '/' + meter_name + return self._list(self.build_url(path, q)) diff --git a/ceilometerclient/v2/statistics.py b/ceilometerclient/v2/statistics.py new file mode 100644 index 00000000..9cf41982 --- /dev/null +++ b/ceilometerclient/v2/statistics.py @@ -0,0 +1,31 @@ +# Copyright 2012 OpenStack LLC. +# 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 ceilometerclient.v2 import samples +from ceilometerclient.common import base + + +class Statistics(base.Resource): + def __repr__(self): + return "" % self._info + + +class StatisticsManager(samples.SampleManager): + resource_class = Statistics + + def list(self, meter_name, q=None): + return self._list(self.build_url( + '/v2/meters/' + meter_name + '/statistics', + q)) diff --git a/tests/v2/__init__.py b/tests/v2/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/v2/test_samples.py b/tests/v2/test_samples.py new file mode 100644 index 00000000..91fc8a46 --- /dev/null +++ b/tests/v2/test_samples.py @@ -0,0 +1,82 @@ +# Copyright 2012 OpenStack LLC. +# 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 unittest + +import ceilometerclient.v2.samples +from tests import utils + + +fixtures = { + '/v2/meters/instance': + { + 'GET': ( + {}, + [ + {u'counter_name': u'instance', + u'user_id': u'user-id', + u'resource_id': u'resource-id', + u'timestamp': u'2012-07-02T10:40:00', + u'message_id': u'54558a1c-6ef3-11e2-9875-5453ed1bbb5f', + u'source': u'test_source', + u'counter_unit': u'', + u'counter_volume': 1.0, + u'project_id': u'project1', + u'resource_metadata': {u'tag': u'self.counter', + u'display_name': u'test-server'}, + u'counter_type': u'cumulative'}, + ] + ), + }, + '/v2/meters/instance?q.op=&q.op=&q.value=foo&q.value=bar&q.field=resource_id&q.field=source': + { + 'GET': ( + {}, + [], + ), + } +} + + +class SampleManagerTest(unittest.TestCase): + + def setUp(self): + self.api = utils.FakeAPI(fixtures) + self.mgr = ceilometerclient.v2.samples.SampleManager(self.api) + + def test_list_by_meter_name(self): + samples = list(self.mgr.list(meter_name='instance')) + expect = [ + ('GET', '/v2/meters/instance', {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].resource_id, 'resource-id') + + def test_list_by_meter_name_extended(self): + samples = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ])) + expect = [ + ('GET', + '/v2/meters/instance?q.op=&q.op=&q.value=foo&q.value=bar&q.field=resource_id&q.field=source', + {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(samples), 0) diff --git a/tests/v2/test_statistics.py b/tests/v2/test_statistics.py new file mode 100644 index 00000000..7b3f8e28 --- /dev/null +++ b/tests/v2/test_statistics.py @@ -0,0 +1,90 @@ +# Copyright 2012 OpenStack LLC. +# 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 unittest + +import ceilometerclient.v2.statistics +from tests import utils + + +fixtures = { + '/v2/meters/instance/statistics': + { + 'GET': ( + {}, + [{ + u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0, + }] + ), + }, + '/v2/meters/instance/statistics?q.op=&q.op=&q.value=foo&q.value=bar&q.field=resource_id&q.field=source': + { + 'GET': ( + {}, + [{ + u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0, + }] + ), + } +} + + +class StatisticsManagerTest(unittest.TestCase): + + def setUp(self): + self.api = utils.FakeAPI(fixtures) + self.mgr = ceilometerclient.v2.statistics.StatisticsManager(self.api) + + def test_list_by_meter_name(self): + stats = list(self.mgr.list(meter_name='instance')) + expect = [ + ('GET', '/v2/meters/instance/statistics', {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(stats), 1) + self.assertEqual(stats[0].count, 135) + + def test_list_by_meter_name_extended(self): + stats = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ])) + expect = [ + ('GET', + '/v2/meters/instance/statistics?q.op=&q.op=&q.value=foo&q.value=bar&q.field=resource_id&q.field=source', + {}, None), + ] + self.assertEqual(self.api.calls, expect) + self.assertEqual(len(stats), 1) + self.assertEqual(stats[0].count, 135)