From 7e7d25dd7871438745cf53fe6559fa45a095bdad Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Fri, 10 May 2019 12:07:14 +0200 Subject: [PATCH] Add support for /v2/scope API endpoint to the client This allows to retrieve the state of one or several scopes through the API via the client library and cli tool. Change-Id: I53995062fe76100f6dfcc672af482f653cc85bde Story: 2005395 Task: 30795 Depends-On: https://review.opendev.org/#/c/658073/ --- .../tests/functional/{v1 => }/base.py | 0 .../tests/functional/v1/test_collector.py | 2 +- .../tests/functional/v1/test_hashmap.py | 2 +- .../tests/functional/v1/test_info.py | 2 +- .../tests/functional/v1/test_pyscripts.py | 2 +- .../tests/functional/v1/test_rating.py | 2 +- .../tests/functional/v1/test_report.py | 2 +- .../tests/functional/v1/test_storage.py | 2 +- .../tests/functional/v2/__init__.py | 0 .../tests/functional/v2/test_scope.py | 35 ++++++++++++ cloudkittyclient/tests/unit/v2/__init__.py | 0 cloudkittyclient/tests/unit/v2/base.py | 24 ++++++++ cloudkittyclient/tests/unit/v2/test_scope.py | 31 +++++++++++ cloudkittyclient/v2/client.py | 3 + cloudkittyclient/v2/scope.py | 50 +++++++++++++++++ cloudkittyclient/v2/scope_cli.py | 55 +++++++++++++++++++ setup.cfg | 4 ++ 17 files changed, 209 insertions(+), 7 deletions(-) rename cloudkittyclient/tests/functional/{v1 => }/base.py (100%) create mode 100644 cloudkittyclient/tests/functional/v2/__init__.py create mode 100644 cloudkittyclient/tests/functional/v2/test_scope.py create mode 100644 cloudkittyclient/tests/unit/v2/__init__.py create mode 100644 cloudkittyclient/tests/unit/v2/base.py create mode 100644 cloudkittyclient/tests/unit/v2/test_scope.py create mode 100644 cloudkittyclient/v2/scope.py create mode 100644 cloudkittyclient/v2/scope_cli.py diff --git a/cloudkittyclient/tests/functional/v1/base.py b/cloudkittyclient/tests/functional/base.py similarity index 100% rename from cloudkittyclient/tests/functional/v1/base.py rename to cloudkittyclient/tests/functional/base.py diff --git a/cloudkittyclient/tests/functional/v1/test_collector.py b/cloudkittyclient/tests/functional/v1/test_collector.py index a6c85db..977ce4d 100644 --- a/cloudkittyclient/tests/functional/v1/test_collector.py +++ b/cloudkittyclient/tests/functional/v1/test_collector.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkCollectorTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_hashmap.py b/cloudkittyclient/tests/functional/v1/test_hashmap.py index 3d7957c..7e9058b 100644 --- a/cloudkittyclient/tests/functional/v1/test_hashmap.py +++ b/cloudkittyclient/tests/functional/v1/test_hashmap.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkHashmapTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_info.py b/cloudkittyclient/tests/functional/v1/test_info.py index 9ed44c8..58cb6c6 100644 --- a/cloudkittyclient/tests/functional/v1/test_info.py +++ b/cloudkittyclient/tests/functional/v1/test_info.py @@ -15,7 +15,7 @@ # import jsonpath_rw_ext as jp -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkInfoTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_pyscripts.py b/cloudkittyclient/tests/functional/v1/test_pyscripts.py index dbd7570..0f05427 100644 --- a/cloudkittyclient/tests/functional/v1/test_pyscripts.py +++ b/cloudkittyclient/tests/functional/v1/test_pyscripts.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkPyscriptTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_rating.py b/cloudkittyclient/tests/functional/v1/test_rating.py index 38988cd..c3b2814 100644 --- a/cloudkittyclient/tests/functional/v1/test_rating.py +++ b/cloudkittyclient/tests/functional/v1/test_rating.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkRatingTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_report.py b/cloudkittyclient/tests/functional/v1/test_report.py index cde71d7..42d00c7 100644 --- a/cloudkittyclient/tests/functional/v1/test_report.py +++ b/cloudkittyclient/tests/functional/v1/test_report.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkReportTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v1/test_storage.py b/cloudkittyclient/tests/functional/v1/test_storage.py index be170a6..6e92562 100644 --- a/cloudkittyclient/tests/functional/v1/test_storage.py +++ b/cloudkittyclient/tests/functional/v1/test_storage.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # -from cloudkittyclient.tests.functional.v1 import base +from cloudkittyclient.tests.functional import base class CkStorageTest(base.BaseFunctionalTest): diff --git a/cloudkittyclient/tests/functional/v2/__init__.py b/cloudkittyclient/tests/functional/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cloudkittyclient/tests/functional/v2/test_scope.py b/cloudkittyclient/tests/functional/v2/test_scope.py new file mode 100644 index 0000000..67210e0 --- /dev/null +++ b/cloudkittyclient/tests/functional/v2/test_scope.py @@ -0,0 +1,35 @@ +# Copyright 2019 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. +# +from cloudkittyclient.tests.functional import base + + +class CkScopeTest(base.BaseFunctionalTest): + + def __init__(self, *args, **kwargs): + super(CkScopeTest, self).__init__(*args, **kwargs) + self.runner = self.cloudkitty + + def test_scope_state_get(self): + return True + # FIXME(peschk_l): Uncomment and update this once there is a way to set + # the state of a scope through the client + # resp = self.runner('scope state get') + + +class OSCScopeTest(CkScopeTest): + + def __init__(self, *args, **kwargs): + super(OSCScopeTest, self).__init__(*args, **kwargs) + self.runner = self.openstack diff --git a/cloudkittyclient/tests/unit/v2/__init__.py b/cloudkittyclient/tests/unit/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cloudkittyclient/tests/unit/v2/base.py b/cloudkittyclient/tests/unit/v2/base.py new file mode 100644 index 0000000..c5239b7 --- /dev/null +++ b/cloudkittyclient/tests/unit/v2/base.py @@ -0,0 +1,24 @@ +# Copyright 2019 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. + +from cloudkittyclient.tests import utils +from cloudkittyclient.v2 import scope + + +class BaseAPIEndpointTestCase(utils.BaseTestCase): + + def setUp(self): + super(BaseAPIEndpointTestCase, self).setUp() + self.api_client = utils.FakeHTTPClient() + self.scope = scope.ScopeManager(self.api_client) diff --git a/cloudkittyclient/tests/unit/v2/test_scope.py b/cloudkittyclient/tests/unit/v2/test_scope.py new file mode 100644 index 0000000..b78736e --- /dev/null +++ b/cloudkittyclient/tests/unit/v2/test_scope.py @@ -0,0 +1,31 @@ +# Copyright 2019 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. +# +from cloudkittyclient.tests.unit.v2 import base + + +class TestScope(base.BaseAPIEndpointTestCase): + + def test_get_scope(self): + self.scope.get_scope_state() + self.api_client.get.assert_called_once_with('/v2/scope') + + def test_get_scope_with_args(self): + self.scope.get_scope_state(offset=10, limit=10) + try: + self.api_client.get.assert_called_once_with( + '/v2/scope?limit=10&offset=10') + except AssertionError: + self.api_client.get.assert_called_once_with( + '/v2/scope?offset=10&limit=10') diff --git a/cloudkittyclient/v2/client.py b/cloudkittyclient/v2/client.py index f70c716..68f595a 100644 --- a/cloudkittyclient/v2/client.py +++ b/cloudkittyclient/v2/client.py @@ -14,6 +14,7 @@ # under the License. # from cloudkittyclient.v1 import client +from cloudkittyclient.v2 import scope # NOTE(peschk_l) v2 client needs to implement v1 until the v1 API has been @@ -33,3 +34,5 @@ class Client(client.Client): insecure=insecure, **kwargs ) + + self.scope = scope.ScopeManager(self.api_client) diff --git a/cloudkittyclient/v2/scope.py b/cloudkittyclient/v2/scope.py new file mode 100644 index 0000000..4f5c8f5 --- /dev/null +++ b/cloudkittyclient/v2/scope.py @@ -0,0 +1,50 @@ +# Copyright 2019 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. +# +from cloudkittyclient.common import base + + +class ScopeManager(base.BaseManager): + """Class used to handle /v2/scope endpoint""" + + url = '/v2/scope' + + def get_scope_state(self, **kwargs): + """Returns a paginated list of scopes along with their state. + + Some optional filters can be provided. + + :param offset: Index of the first scope that should be returned. + :type offset: int + :param limit: Maximal number of scopes to return. + :type limit: int + :param collector: Optional collector to filter on. + :type collector: str or list of str + :param fetcher: Optional fetcher to filter on. + :type fetcher: str or list of str + :param scope_id: Optional scope_id to filter on. + :type scope_id: str or list of str + :param scope_key: Optional scope_key to filter on. + :type scope_key: str or list of str + """ + + for key in ('collector', 'fetcher', 'scope_id', 'scope_key'): + if key in kwargs.keys(): + if isinstance(kwargs[key], list): + kwargs[key] = ','.join(kwargs[key]) + + authorized_args = [ + 'offset', 'limit', 'collector', 'fetcher', 'scope_id', 'scope_key'] + url = self.get_url(None, kwargs, authorized_args=authorized_args) + return self.api_client.get(url).json() diff --git a/cloudkittyclient/v2/scope_cli.py b/cloudkittyclient/v2/scope_cli.py new file mode 100644 index 0000000..2b29def --- /dev/null +++ b/cloudkittyclient/v2/scope_cli.py @@ -0,0 +1,55 @@ +# Copyright 2019 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. +# +from cliff import lister + +from cloudkittyclient import utils + + +class CliScopeStateGet(lister.Lister): + """Get information about current state of several scopes.""" + info_columns = [ + ('scope_id', 'Scope ID'), + ('scope_key', 'Scope Key'), + ('collector', 'Collector'), + ('fetcher', 'Fetcher'), + ('state', 'State') + ] + + def get_parser(self, prog_name): + parser = super(CliScopeStateGet, self).get_parser(prog_name) + + for col in self.info_columns[:-1]: + parser.add_argument( + '--' + col[0].replace('_', '-'), type=str, + action='append', help='Optional filter on ' + col[1]) + + parser.add_argument('--offset', type=int, default=0, + help='Index of the first scope') + parser.add_argument('--limit', type=int, default=100, + help='Maximal number of scopes') + + return parser + + def take_action(self, parsed_args): + resp = utils.get_client_from_osc(self).scope.get_scope_state( + offset=parsed_args.offset, + limit=parsed_args.limit, + collector=parsed_args.collector, + fetcher=parsed_args.fetcher, + scope_id=parsed_args.scope_id, + scope_key=parsed_args.scope_key, + ) + values = utils.list_to_cols(resp['results'], self.info_columns) + return [col[1] for col in self.info_columns], values diff --git a/setup.cfg b/setup.cfg index adba6bd..2088fd0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -86,6 +86,8 @@ openstack.rating.v1 = rating_pyscript_delete = cloudkittyclient.v1.rating.pyscripts_cli:CliDeleteScript openstack.rating.v2 = + rating_scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet + rating_total_get = cloudkittyclient.v1.report_cli:CliTotalGet rating_summary_get = cloudkittyclient.v1.report_cli:CliSummaryGet rating_report_tenant_list = cloudkittyclient.v1.report_cli:CliTenantList @@ -142,6 +144,8 @@ openstack.rating.v2 = cloudkittyclient = + scope_state_get = cloudkittyclient.v2.scope_cli:CliScopeStateGet + total_get = cloudkittyclient.v1.report_cli:CliTotalGet summary_get = cloudkittyclient.v1.report_cli:CliSummaryGet report_tenant_list = cloudkittyclient.v1.report_cli:CliTenantList