From 380a96b5f2da032ec3d26abdf5a4babe7ac26766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Magimel?= Date: Thu, 28 Aug 2014 15:23:09 +0200 Subject: [PATCH] Add the billing/modules request (v1) Add only the generic requests. Change-Id: I6e120c0da6612259ad9ba5e5ef0df413f2dac4f5 --- .../tests/v1/billing/test_modules.py | 115 +++++++++++++++ cloudkittyclient/v1/billing/modules.py | 136 ++++++++++++++++++ cloudkittyclient/v1/client.py | 2 + 3 files changed, 253 insertions(+) create mode 100644 cloudkittyclient/tests/v1/billing/test_modules.py create mode 100644 cloudkittyclient/v1/billing/modules.py diff --git a/cloudkittyclient/tests/v1/billing/test_modules.py b/cloudkittyclient/tests/v1/billing/test_modules.py new file mode 100644 index 0000000..7de44fd --- /dev/null +++ b/cloudkittyclient/tests/v1/billing/test_modules.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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. +# +# @author: François Magimel (linkid) + +""" +Tests for the manager billing.modules `cloudkittyclient.v1.billing.modules`. +""" + +import json + +from cloudkittyclient.openstack.common.apiclient import fake_client +from cloudkittyclient.tests import base +from cloudkittyclient.v1.billing import modules +from cloudkittyclient.v1 import client + + +modules_test = ["noop", "test"] +info_module = { + "enabled": True, + "name": "test", + "hot-config": True, + "description": "Test description" +} + +fixtures_list_modules = { + '/v1/billing/modules': { + 'GET': ( + {}, + json.dumps(modules_test) + ), + } +} +fixtures_get_one_module = { + '/v1/billing/modules/test': { + 'GET': ( + {}, + json.dumps(info_module) + ), + } +} +fixtures_get_status_module = { + '/v1/billing/modules/test/enabled': { + 'GET': ( + {}, + json.dumps(str(info_module['enabled'])) + ), + } +} +fixtures_put_status_module = { + '/v1/billing/modules/test/enabled': { + 'PUT': ( + {}, + json.dumps(str(False)) + ), + } +} + + +class ModulesManagerTest(base.TestCase): + def connect_client(self, fixtures): + """Returns the manager.""" + fake_http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + api_client = client.Client(fake_http_client) + return modules.ModulesManager(api_client) + + def test_list_modules(self): + mgr = self.connect_client(fixtures_list_modules) + modules_expected = [ + modules.Module(modules.ModulesManager, module) + for module in modules_test + ] + + self.assertEqual(modules_expected, mgr.list()) + + def test_get_one_module(self): + mgr = self.connect_client(fixtures_get_one_module) + module_expected = modules.ExtensionSummary( + modules.ModulesManager, info_module) + module_get = mgr.get(module_id='test') + + self.assertIn('ExtensionSummary', repr(module_get)) + self.assertEqual(module_expected, module_get) + self.assertEqual(module_expected.enabled, module_get.enabled) + self.assertEqual('test', module_get.name) + self.assertEqual(getattr(module_expected, 'hot-config'), + getattr(module_get, 'hot-config')) + self.assertEqual(module_expected.description, module_get.description) + + def test_get_status_module(self): + mgr = self.connect_client(fixtures_get_status_module) + module_status_expected = info_module['enabled'] + module_status_get = mgr.get_status(module_id='test') + + self.assertIn('Module', repr(module_status_get)) + self.assertIn('test', repr(module_status_get)) + self.assertEqual(str(module_status_expected), module_status_get.id) + + def test_update_status_module(self): + mgr = self.connect_client(fixtures_put_status_module) + module_status_put = mgr.update(module_id='test', enabled=False) + + self.assertEqual('False', module_status_put.id) diff --git a/cloudkittyclient/v1/billing/modules.py b/cloudkittyclient/v1/billing/modules.py new file mode 100644 index 0000000..c724434 --- /dev/null +++ b/cloudkittyclient/v1/billing/modules.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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. +# +# @author: François Magimel (linkid) + +""" +Modules resource and manager. +""" + +from cloudkittyclient.openstack.common.apiclient import base + + +class ExtensionSummary(base.Resource): + """A billing extension summary.""" + + def __repr__(self): + return "" % self.name + + @property + def id(self): + return self.name + + +class Module(base.Resource): + def __repr__(self): + name = self._info + if hasattr(self.manager, 'module_id'): + name = self.manager.module_id + return "" % name + + def _add_details(self, info): + pass + + @property + def id(self): + name = self._info + return name + + +class ModulesManager(base.CrudManager): + resource_class = Module + collection_key = 'billing/modules' + key = 'module' + + def _list(self, url, response_key, obj_class=None, json=None): + if json: + body = self.client.post(url, json=json).json() + else: + body = self.client.get(url).json() + + if obj_class is None: + obj_class = self.resource_class + + # hack + if type(body) == dict: + data = body[response_key] + else: + data = body + + # NOTE(ja): keystone returns values as list as {'values': [ ... ]} + # unlike other services which just return the list... + try: + data = data['values'] + except (KeyError, TypeError): + pass + + return [obj_class(self, res, loaded=True) for res in data if res] + + def list(self, base_url=None, **kwargs): + """Get module list in the billing pipeline. + /v1/billing/modules + """ + return super(ModulesManager, self).list(base_url='/v1', **kwargs) + + def _get(self, url, response_key=None, obj_class=None): + body = self.client.get(url).json() + + if obj_class is None: + obj_class = self.resource_class + + # hack + if response_key is None: + return obj_class(self, body, loaded=True) + else: + return obj_class(self, body[response_key], loaded=True) + + def get(self, **kwargs): + """Get a module. + /v1/billing/module/ + """ + kwargs = self._filter_kwargs(kwargs) + self.module_id = kwargs.get('module_id') + + return self._get( + url=self.build_url(base_url='/v1', **kwargs), + response_key=None, + obj_class=ExtensionSummary) + + def get_status(self, **kwargs): + """Get the status of a module. + /v1/billing/module//enabled + """ + kwargs = self._filter_kwargs(kwargs) + self.module_id = kwargs.get('module_id') + + return self._get( + url='%(base_url)s/enabled' % { + 'base_url': self.build_url(base_url='/v1', **kwargs), + }, + response_key=None) + + def update(self, **kwargs): + """Update the status of a module. + /v1/billing/modules//enabled + """ + kwargs = self._filter_kwargs(kwargs) + self.module_id = kwargs.get('module_id') + + return self._put( + url='%(base_url)s/enabled' % { # hack + 'base_url': self.build_url(base_url='/v1', **kwargs), + }, + json=kwargs.get('enabled'), + response_key=None) diff --git a/cloudkittyclient/v1/client.py b/cloudkittyclient/v1/client.py index 146e587..118ba6a 100644 --- a/cloudkittyclient/v1/client.py +++ b/cloudkittyclient/v1/client.py @@ -20,6 +20,7 @@ OpenStack Client interface. Handles the REST calls and responses. """ from cloudkittyclient.openstack.common.apiclient import client +from cloudkittyclient.v1.billing import modules from cloudkittyclient.v1.billing import quote from cloudkittyclient.v1 import report @@ -37,4 +38,5 @@ class Client(client.BaseClient): class Billing(object): def __init__(self, http_client): + self.modules = modules.ModulesManager(http_client) self.quote = quote.QuoteManager(http_client)