Add rating modules GET endpoints to v2 API
This introduces GET methods for rating modules in the v2 API. Work items: * Implement the "/v1/rating/modules" endpoints in the v2 API, including unit tests and documentation Story: 2006572 Task: 36677 Co-Authored-By: Rafael Weingärtner <rafael@apache.org> Change-Id: I0a2f24051d268a396955c8df7e3e5615546f6293
This commit is contained in:

committed by
Rafael Weingärtner

parent
34d121bf18
commit
9f9f4f1233
@@ -34,7 +34,8 @@ API_MODULES = [
|
||||
'cloudkitty.api.v2.scope',
|
||||
'cloudkitty.api.v2.dataframes',
|
||||
'cloudkitty.api.v2.summary',
|
||||
'cloudkitty.api.v2.task'
|
||||
'cloudkitty.api.v2.task',
|
||||
'cloudkitty.api.v2.rating',
|
||||
]
|
||||
|
||||
|
||||
|
31
cloudkitty/api/v2/rating/__init__.py
Normal file
31
cloudkitty/api/v2/rating/__init__.py
Normal file
@@ -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 cloudkitty.api.v2 import utils as api_utils
|
||||
|
||||
|
||||
def init(app):
|
||||
api_utils.do_init(app, 'rating', [
|
||||
{
|
||||
'module': __name__ + '.' + 'modules',
|
||||
'resource_class': 'RatingModule',
|
||||
'url': '/modules/<string:module_id>',
|
||||
},
|
||||
{
|
||||
'module': __name__ + '.' + 'modules',
|
||||
'resource_class': 'RatingModuleList',
|
||||
'url': '/modules',
|
||||
},
|
||||
])
|
||||
return app
|
102
cloudkitty/api/v2/rating/modules.py
Normal file
102
cloudkitty/api/v2/rating/modules.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
import flask
|
||||
from oslo_concurrency import lockutils
|
||||
from stevedore import extension
|
||||
import voluptuous
|
||||
from werkzeug import exceptions as http_exceptions
|
||||
|
||||
from cloudkitty.api.v2 import base
|
||||
from cloudkitty.api.v2 import utils as api_utils
|
||||
from cloudkitty.common import policy
|
||||
from cloudkitty import utils as ck_utils
|
||||
from cloudkitty.utils import validation as vutils
|
||||
|
||||
|
||||
PROCESSORS_NAMESPACE = 'cloudkitty.rating.processors'
|
||||
|
||||
MODULE_SCHEMA = {
|
||||
voluptuous.Required(
|
||||
'description',
|
||||
default=None,
|
||||
): vutils.get_string_type(),
|
||||
voluptuous.Required(
|
||||
'module_id',
|
||||
default=None,
|
||||
): vutils.get_string_type(),
|
||||
voluptuous.Required(
|
||||
'enabled',
|
||||
default=None,
|
||||
): voluptuous.Boolean(),
|
||||
voluptuous.Required(
|
||||
'hot_config',
|
||||
default=None,
|
||||
): voluptuous.Boolean(),
|
||||
voluptuous.Required(
|
||||
'priority',
|
||||
default=None,
|
||||
): voluptuous.All(int, min=1),
|
||||
}
|
||||
|
||||
|
||||
class BaseRatingModule(base.BaseResource):
|
||||
|
||||
@classmethod
|
||||
def reload(cls):
|
||||
super(BaseRatingModule, cls).reload()
|
||||
with lockutils.lock('rating-modules'):
|
||||
ck_utils.refresh_stevedore(PROCESSORS_NAMESPACE)
|
||||
cls.rating_modules = extension.ExtensionManager(
|
||||
PROCESSORS_NAMESPACE, invoke_on_load=True)
|
||||
|
||||
|
||||
class RatingModule(BaseRatingModule):
|
||||
|
||||
@api_utils.add_output_schema(MODULE_SCHEMA)
|
||||
def get(self, module_id):
|
||||
policy.authorize(flask.request.context, 'v2_rating:get_module', {})
|
||||
try:
|
||||
module = self.rating_modules[module_id]
|
||||
except KeyError:
|
||||
raise http_exceptions.NotFound(
|
||||
"Module '{}' not found".format(module_id))
|
||||
infos = module.obj.module_info.copy()
|
||||
return {
|
||||
'module_id': module_id,
|
||||
'description': infos['description'],
|
||||
'enabled': infos['enabled'],
|
||||
'hot_config': infos['hot_config'],
|
||||
'priority': infos['priority'],
|
||||
}
|
||||
|
||||
|
||||
class RatingModuleList(BaseRatingModule):
|
||||
|
||||
@api_utils.add_output_schema({
|
||||
'modules': [MODULE_SCHEMA],
|
||||
})
|
||||
def get(self):
|
||||
modules = []
|
||||
for module in self.rating_modules:
|
||||
infos = module.obj.module_info.copy()
|
||||
modules.append({
|
||||
'module_id': infos['name'],
|
||||
'description': infos['description'],
|
||||
'enabled': infos['enabled'],
|
||||
'hot_config': infos['hot_config'],
|
||||
'priority': infos['priority'],
|
||||
})
|
||||
return {'modules': modules}
|
@@ -22,6 +22,7 @@ from cloudkitty.common.policies.v1 import rating as v1_rating
|
||||
from cloudkitty.common.policies.v1 import report as v1_report
|
||||
from cloudkitty.common.policies.v1 import storage as v1_storage
|
||||
from cloudkitty.common.policies.v2 import dataframes as v2_dataframes
|
||||
from cloudkitty.common.policies.v2 import rating as v2_rating
|
||||
from cloudkitty.common.policies.v2 import scope as v2_scope
|
||||
from cloudkitty.common.policies.v2 import summary as v2_summary
|
||||
from cloudkitty.common.policies.v2 import tasks as v2_tasks
|
||||
@@ -36,6 +37,7 @@ def list_rules():
|
||||
v1_report.list_rules(),
|
||||
v1_storage.list_rules(),
|
||||
v2_dataframes.list_rules(),
|
||||
v2_rating.list_rules(),
|
||||
v2_scope.list_rules(),
|
||||
v2_summary.list_rules(),
|
||||
v2_tasks.list_rules()
|
||||
|
37
cloudkitty/common/policies/v2/rating.py
Normal file
37
cloudkitty/common/policies/v2/rating.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2019 Objectif Libre.
|
||||
# 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 oslo_policy import policy
|
||||
|
||||
from cloudkitty.common.policies import base
|
||||
|
||||
rating_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
name='v2_rating:list_modules',
|
||||
check_str=base.ROLE_ADMIN,
|
||||
description='Returns the list of loaded modules in Cloudkitty.',
|
||||
operations=[{'path': '/v2/rating/modules',
|
||||
'method': 'GET'}]),
|
||||
policy.DocumentedRuleDefault(
|
||||
name='v2_rating:get_module',
|
||||
check_str=base.ROLE_ADMIN,
|
||||
description='Get specified module.',
|
||||
operations=[{'path': '/v2/rating/modules/{module_id}',
|
||||
'method': 'GET'}]),
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return rating_policies
|
42
cloudkitty/tests/gabbi/gabbits/v2-rating-modules.yaml
Normal file
42
cloudkitty/tests/gabbi/gabbits/v2-rating-modules.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
fixtures:
|
||||
- ConfigFixtureStorageV2
|
||||
- RatingModulesFixture
|
||||
- QuoteFakeRPC
|
||||
|
||||
tests:
|
||||
- name: list all modules available
|
||||
url: /v2/rating/modules
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.modules.`len`: 3
|
||||
$.modules[0].priority: 3
|
||||
$.modules[0].module_id: "fake1"
|
||||
$.modules[0].enabled: false
|
||||
$.modules[0].description: "fake rating module"
|
||||
$.modules[0].hot_config: false
|
||||
$.modules[1].priority: 1
|
||||
$.modules[1].module_id: "fake2"
|
||||
$.modules[1].enabled: false
|
||||
$.modules[1].description: "fake rating module"
|
||||
$.modules[1].hot_config: false
|
||||
$.modules[2].priority: 2
|
||||
$.modules[2].module_id: "fake3"
|
||||
$.modules[2].enabled: false
|
||||
$.modules[2].description: "fake rating module"
|
||||
$.modules[2].hot_config: false
|
||||
|
||||
- name: get information of one module
|
||||
url: /v2/rating/modules/fake2
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.priority: 1
|
||||
$.module_id: "fake2"
|
||||
$.enabled: false
|
||||
$.description: "fake rating module"
|
||||
$.hot_config: false
|
||||
|
||||
- name: get information of a unknown module
|
||||
url: /v2/rating/modules/fakb
|
||||
status: 404
|
||||
response_json_paths:
|
||||
$.message: "Module 'fakb' not found"
|
@@ -1215,18 +1215,6 @@
|
||||
# heartbeat. (integer value)
|
||||
#heartbeat_rate = 2
|
||||
|
||||
# DEPRECATED: (DEPRECATED) Enable/Disable the RabbitMQ mandatory flag
|
||||
# for direct send. The direct send is used as reply, so the
|
||||
# MessageUndeliverable exception is raised in case the client queue
|
||||
# does not exist.MessageUndeliverable exception will be used to loop
|
||||
# for a timeout to lets a chance to sender to recover.This flag is
|
||||
# deprecated and it will not be possible to deactivate this
|
||||
# functionality anymore (boolean value)
|
||||
# This option is deprecated for removal.
|
||||
# Its value may be silently ignored in the future.
|
||||
# Reason: Mandatory flag no longer deactivable.
|
||||
#direct_mandatory_flag = true
|
||||
|
||||
# Enable x-cancel-on-ha-failover flag so that rabbitmq server will
|
||||
# cancel and notify consumerswhen queue is down (boolean value)
|
||||
#enable_cancel_on_failover = false
|
||||
|
@@ -89,6 +89,14 @@
|
||||
# GET /v2/dataframes
|
||||
#"dataframes:get": "rule:admin_or_owner"
|
||||
|
||||
# Returns the list of loaded modules in Cloudkitty.
|
||||
# GET /v2/rating/modules
|
||||
#"v2_rating:list_modules": "role:admin"
|
||||
|
||||
# Get specified module.
|
||||
# GET /v2/rating/modules/{module_id}
|
||||
#"v2_rating:get_module": "role:admin"
|
||||
|
||||
# Get the state of one or several scopes
|
||||
# GET /v2/scope
|
||||
#"scope:get_state": "role:admin"
|
||||
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"module_id": "sample_id",
|
||||
"description": "Sample extension",
|
||||
"enabled": true,
|
||||
"hot-config": false,
|
||||
"priority": 2
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"module_id": "noop"
|
||||
"description": "Dummy test module.",
|
||||
"enabled": true,
|
||||
"hot-config": false,
|
||||
"priority": 1
|
||||
},
|
||||
{
|
||||
"module_id": "hashmap",
|
||||
"description": "HashMap rating module.",
|
||||
"enabled": false,
|
||||
"hot-config": true,
|
||||
"priority": 2
|
||||
}
|
||||
]
|
||||
}
|
@@ -4,3 +4,4 @@
|
||||
.. include:: scope/scope.inc
|
||||
.. include:: summary/summary.inc
|
||||
.. include:: task/reprocessing.inc
|
||||
.. include:: rating/modules.inc
|
||||
|
1
doc/source/api-reference/v2/rating/http_status.yml
Symbolic link
1
doc/source/api-reference/v2/rating/http_status.yml
Symbolic link
@@ -0,0 +1 @@
|
||||
../http_status.yml
|
76
doc/source/api-reference/v2/rating/modules.inc
Normal file
76
doc/source/api-reference/v2/rating/modules.inc
Normal file
@@ -0,0 +1,76 @@
|
||||
=======================
|
||||
Rating modules endpoint
|
||||
=======================
|
||||
|
||||
Get the list of modules
|
||||
=======================
|
||||
|
||||
Returns the list of all rating modules loaded. This method does not require any
|
||||
parameter.
|
||||
|
||||
.. rest_method:: GET /v2/rating/modules
|
||||
|
||||
Status codes
|
||||
------------
|
||||
|
||||
.. rest_status_code:: success http_status.yml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error http_status.yml
|
||||
|
||||
- 400
|
||||
- 401
|
||||
- 403
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: rating/modules_parameters.yml
|
||||
|
||||
- modules: modules_list
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: ./api_samples/rating/modules_list_get.json
|
||||
:language: javascript
|
||||
|
||||
Get one module
|
||||
==============
|
||||
|
||||
Returns the details of one specific module. This method does not require any
|
||||
parameter.
|
||||
|
||||
.. rest_method:: GET /v2/rating/modules/<module_id>
|
||||
|
||||
Status codes
|
||||
------------
|
||||
|
||||
.. rest_status_code:: success http_status.yml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error http_status.yml
|
||||
|
||||
- 400
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: rating/modules_parameters.yml
|
||||
|
||||
- module_id: module_id
|
||||
- description: description
|
||||
- enabled: enabled
|
||||
- hot_config: hot_config
|
||||
- priority: priority
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: ./api_samples/rating/module_get.json
|
||||
:language: javascript
|
49
doc/source/api-reference/v2/rating/modules_parameters.yml
Normal file
49
doc/source/api-reference/v2/rating/modules_parameters.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
description:
|
||||
in: body
|
||||
description: |
|
||||
A quick description of the module
|
||||
type: string
|
||||
required: true
|
||||
|
||||
enabled: &enabled
|
||||
in: body
|
||||
description: |
|
||||
Boolean representing if the module is enabled
|
||||
type: bool
|
||||
required: true
|
||||
|
||||
enabled_opt:
|
||||
<<: *enabled
|
||||
required: false
|
||||
|
||||
hot_config:
|
||||
in: body
|
||||
description: |
|
||||
Boolean representing if the module supports hot-config
|
||||
type: bool
|
||||
required: true
|
||||
|
||||
module_id:
|
||||
in: body
|
||||
description: |
|
||||
The id of the module
|
||||
type: string
|
||||
required: true
|
||||
|
||||
modules_list:
|
||||
in: body
|
||||
description: |
|
||||
List of modules.
|
||||
type: list
|
||||
required: true
|
||||
|
||||
priority: &priority
|
||||
in: body
|
||||
description: |
|
||||
Priority of the module, relative to other modules
|
||||
type: int
|
||||
required: true
|
||||
|
||||
priority_opt:
|
||||
<<: *priority
|
||||
required: false
|
@@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add rating modules GET endpoints to v2 API.
|
Reference in New Issue
Block a user