diff --git a/scylla_api_client/api.py b/scylla_api_client/api.py index 7fdcbb6..67ebc82 100644 --- a/scylla_api_client/api.py +++ b/scylla_api_client/api.py @@ -385,19 +385,46 @@ def load(self): if not top_json: log.error("Service is down. Failed to get api data") return + def add_command(module:ScyllaApiModule, command_name:str, command_json:str): + command = ScyllaApiCommand(module_name=module.name, + command_name=command_path, + host=self._host, + port=self._port) + command.load_json(command_json) + module.add_command(command) for module_def in top_json["apis"]: # FIXME: handle service down, errors - module_json = self.client.get_raw_api_json(f"{module_def['path']}/") + module_json = self.client.get_raw_api_json(f"/api-doc{module_def['path']}/") module_path = module_def['path'].strip(' /') module = ScyllaApiModule(module_path, module_def['description']) for command_json in module_json["apis"]: command_path = command_json['path'].strip(' /') if command_path.startswith(module_path): command_path = command_path[len(module_path)+1:] - command = ScyllaApiCommand(module_name=module_path, - command_name=command_path, - host=self._host, - port=self._port) - command.load_json(command_json) - module.add_command(command) + add_command(module, command_path, command_json) + self.add_module(module) + for module_def in [json.loads('{ "path": "/v2", "description": "V2 API"}')]: + module_json = self.client.get_raw_api_json(module_def['path'])["paths"] + module_path = module_def['path'].strip(' /') + module = ScyllaApiModule(module_path, module_def['description']) + for command_path in module_json: + operations = [] + for op, v2_meta in module_json[command_path].items(): + if op.upper() not in ["GET", "POST", "DELETE"]: + continue + operation = { "method": op } + kw_trans = { "description": "summary", "produces": "produces", "parameters": "parameters"} + for v2_kw, v1_kw in kw_trans.items(): + if v2_kw in v2_meta: + operation[v1_kw] = v2_meta[v2_kw] + operations.append(operation) + if "produces" in v2_meta: + operation["produces"] = v2_meta["produces"] + command_path = command_path.strip(' /') + if command_path.startswith(module_path): + command_path = command_path[len(module_path)+1:] + json_str = f'{{"path": "{command_path}", "operations": {json.dumps(operations)} }}' + command_json = json.loads(json_str) + log.debug(f"{module_path} {command_path}: {command_json}") + add_command(module, command_path, command_json) self.add_module(module) diff --git a/scylla_api_client/rest/scylla_rest_client.py b/scylla_api_client/rest/scylla_rest_client.py index bd57b42..79865fe 100644 --- a/scylla_api_client/rest/scylla_rest_client.py +++ b/scylla_api_client/rest/scylla_rest_client.py @@ -9,8 +9,8 @@ class ScyllaRestClient(RestClient): def __init__(self, host: str = "localhost", port: str = "10000"): super().__init__(host=host, port=port) - def get_raw_api_json(self, resource_path: str = ""): - if api := self.get(f"/api-doc{resource_path}"): + def get_raw_api_json(self, resource_path: str = "/api-doc"): + if api := self.get(resource_path): return api.json() return None diff --git a/tests/api_tests/conftest.py b/tests/api_tests/conftest.py index 0bc19c8..8a06285 100644 --- a/tests/api_tests/conftest.py +++ b/tests/api_tests/conftest.py @@ -22,6 +22,8 @@ def do_GET(self): content = json.dumps(self.error_injection()).encode(encoding="utf-8") elif self.path == "/api-doc/compaction_manager/": content = json.dumps(self.compaction_manager()).encode(encoding="utf-8") + elif self.path == "/v2": + content = json.dumps(self.v2()).encode(encoding="utf-8") else: content = json.dumps(f"""{{"URL": "{self.command}", "method": "{self.path}"}}""").encode(encoding="utf-8") @@ -609,6 +611,204 @@ def compaction_manager(self): } }""") + def v2(self): + json_resp = json.loads("""{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Scylla API", + "description": "The scylla API version 2.0", + "termsOfService": "http://www.scylladb.com/tos/", + "contact": { + "name": "Scylla Team", + "email": "info@scylladb.com", + "url": "http://scylladb.com" + }, + "license": { + "name": "AGPL", + "url": "https://github.com/scylladb/scylla/blob/master/LICENSE.AGPL" + } + }, + "host": "localhost:10000", + "basePath": "/", + "schemes": [ + "http" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v2/metrics-config/":{ + "get":{ + "description":"Return the metrics layer configuration", + "operationId":"get_metrics_config", + "produces":[ + "application/json" + ], + "tags":[ + "metrics" + ], + "parameters":[ + ], + "responses":{ + "200":{ + "schema": { + "type":"array", + "items":{ + "$ref":"#/definitions/metrics_config", + "description":"metrics Config value" + } + } + }, + "default":{ + "description":"unexpected error", + "schema":{ + "$ref":"#/definitions/ErrorModel" + } + } + } + }, + "post": { + "description":"Set the metrics layer relabel configuration", + "operationId":"set_metrics_config", + "produces":[ + "application/json" + ], + "tags":[ + "metrics" + ], + "parameters":[ + { + "in":"body", + "name":"conf", + "description":"An array of relabel_config objects", + "schema": { + "type":"array", + "items":{ + "$ref":"#/definitions/metrics_config", + "description":"metrics Config value" + } + } + } + ], + "responses":{ + "200":{ + "description": "OK" + }, + "default":{ + "description":"unexpected error", + "schema":{ + "$ref":"#/definitions/ErrorModel" + } + } + } + } + }, + "/v2/config/background_writer_scheduling_quota": { + "get": { + "description": "max cpu usage ratio (between 0 and 1) for compaction process. Not intended for setting in normal operations. Setting it to 1 or higher will disable it, recommended operational setting is 0.5.", + "operationId": "find_config_background_writer_scheduling_quota", + "produces": [ + "application/json" + ], + "tags": [ + "config" + ], + "parameters": [], + "responses": { + "200": { + "description": "Config value", + "schema": { + "type": "double" + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/ErrorModel" + } + } + } + } + }, + "/v2/config/log_to_syslog": { + "get": { + "description": "Send log output to syslog", + "operationId": "find_config_log_to_syslog", + "produces": [ + "application/json" + ], + "tags": [ + "config" + ], + "parameters": [], + "responses": { + "200": { + "description": "Config value", + "schema": { + "type": "bool" + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/ErrorModel" + } + } + } + } + } + }, + "definitions": { + "metrics_config": { + "id": "metrics_config", + "summary": "An entry in the metrics configuration", + "properties": { + "source_labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The source labels, a match is based on concatenation of the labels" + }, + "action": { + "type": "string", + "description": "The action to perform on match", + "enum": [ + "skip_when_empty", + "report_when_empty", + "replace", + "keep", + "drop", + "drop_label" + ] + }, + "target_label": { + "type": "string", + "description": "The application state version" + }, + "replacement": { + "type": "string", + "description": "The replacement string to use when replacing a value" + }, + "regex": { + "type": "string", + "description": "The regex string to use when replacing a value" + }, + "separator": { + "type": "string", + "description": "The separator string to use when concatenating the labels" + } + } + } + } +}""" + ) + return json_resp + class ScyllaApiServer: def __init__(self, port): diff --git a/tests/api_tests/test_scylla_api.py b/tests/api_tests/test_scylla_api.py index 8d38348..549f427 100644 --- a/tests/api_tests/test_scylla_api.py +++ b/tests/api_tests/test_scylla_api.py @@ -11,11 +11,11 @@ def scylla_api_obj(api_server): def test_number_of_scylla_api_modules(scylla_api_obj): - assert len(scylla_api_obj.modules) == 3 + assert len(scylla_api_obj.modules) == 4 def test_module_names(scylla_api_obj): - module_names = ["system", "compaction_manager", "error_injection"] + module_names = ["system", "compaction_manager", "error_injection", "v2"] for module, expected_name in zip(scylla_api_obj.modules, module_names): assert module == expected_name