From: Aleš Mrázek Date: Thu, 7 Mar 2024 12:52:58 +0000 (+0100) Subject: datamodel: additional headers for json-schema X-Git-Tag: v6.0.9~17^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44cfa769c3c46c2ca3235335190897ce5744e7d2;p=thirdparty%2Fknot-resolver.git datamodel: additional headers for json-schema --- diff --git a/python/knot_resolver/client/commands/schema.py b/python/knot_resolver/client/commands/schema.py index f55384247..0c63f398e 100644 --- a/python/knot_resolver/client/commands/schema.py +++ b/python/knot_resolver/client/commands/schema.py @@ -4,7 +4,7 @@ import sys from typing import List, Optional, Tuple, Type from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command -from knot_resolver.datamodel.config_schema import KresConfig +from knot_resolver.datamodel import kres_config_json_schema from knot_resolver.utils.requests import request @@ -46,7 +46,7 @@ class SchemaCommand(Command): sys.exit(1) schema = response.body else: - schema = json.dumps(KresConfig.json_schema(), indent=4) + schema = json.dumps(kres_config_json_schema(), indent=4) if self.file: with open(self.file, "w") as f: diff --git a/python/knot_resolver/datamodel/__init__.py b/python/knot_resolver/datamodel/__init__.py index a0174acc5..81fd1ee99 100644 --- a/python/knot_resolver/datamodel/__init__.py +++ b/python/knot_resolver/datamodel/__init__.py @@ -1,3 +1,3 @@ -from .config_schema import KresConfig +from .config_schema import KresConfig, kres_config_json_schema -__all__ = ["KresConfig"] +__all__ = ["KresConfig", "kres_config_json_schema"] diff --git a/python/knot_resolver/datamodel/config_schema.py b/python/knot_resolver/datamodel/config_schema.py index fa108e79c..7d8b0b8d6 100644 --- a/python/knot_resolver/datamodel/config_schema.py +++ b/python/knot_resolver/datamodel/config_schema.py @@ -3,11 +3,12 @@ import os import socket from typing import Any, Dict, List, Literal, Optional, Tuple, Union -from knot_resolver.constants import API_SOCK_PATH_DEFAULT, RUN_DIR_DEFAULT, WORKERS_MAX_DEFAULT +from knot_resolver.constants import API_SOCK_PATH_DEFAULT, RUN_DIR_DEFAULT, VERSION, WORKERS_MAX_DEFAULT from knot_resolver.datamodel.cache_schema import CacheSchema from knot_resolver.datamodel.dns64_schema import Dns64Schema from knot_resolver.datamodel.dnssec_schema import DnssecSchema from knot_resolver.datamodel.forward_schema import ForwardSchema +from knot_resolver.datamodel.globals import Context, get_global_validation_context, set_global_validation_context from knot_resolver.datamodel.local_data_schema import LocalDataSchema, RPZSchema, RuleSchema from knot_resolver.datamodel.logging_schema import LoggingSchema from knot_resolver.datamodel.lua_schema import LuaSchema @@ -234,3 +235,25 @@ def get_rundir_without_validation(data: Dict[str, Any]) -> WritableDir: """ return WritableDir(data["rundir"] if "rundir" in data else RUN_DIR_DEFAULT, object_path="/rundir") + + +def kres_config_json_schema() -> Dict[str, Any]: + """ + At this moment, to create any instance of 'ConfigSchema' even with default values, it is necessary to set the global context. + In the case of generating a JSON schema, strict validation must be turned off, otherwise it may happen that the creation of the JSON schema fails, + It may fail due to non-existence of the directory/file or their rights. + This should be fixed in the future. For more info, see 'datamodel.globals.py' module. + """ + + context = get_global_validation_context() + set_global_validation_context(Context(None, False)) + + schema = KresConfig.json_schema( + schema_id=f"https://www.knot-resolver.cz/documentation/v{VERSION}/_static/config.schema.json", + title="Knot Resolver configuration JSON schema", + description=f"Version Knot Resolver {VERSION}", + ) + # setting back to previous values + set_global_validation_context(context) + + return schema diff --git a/python/knot_resolver/datamodel/globals.py b/python/knot_resolver/datamodel/globals.py index 610323fa0..88f95c2a4 100644 --- a/python/knot_resolver/datamodel/globals.py +++ b/python/knot_resolver/datamodel/globals.py @@ -38,6 +38,10 @@ def set_global_validation_context(context: Context) -> None: _global_context = context +def get_global_validation_context() -> Context: + return _global_context + + def reset_global_validation_context() -> None: global _global_context _global_context = Context(None) diff --git a/python/knot_resolver/manager/server.py b/python/knot_resolver/manager/server.py index d9f7f9eea..ea2b419c0 100644 --- a/python/knot_resolver/manager/server.py +++ b/python/knot_resolver/manager/server.py @@ -21,6 +21,7 @@ from knot_resolver.constants import CONFIG_FILE_PATH_DEFAULT, PID_FILE_NAME from knot_resolver.controller import get_best_controller_implementation from knot_resolver.controller.exceptions import SubprocessControllerExecException from knot_resolver.controller.registered_workers import command_single_registered_worker +from knot_resolver.datamodel import kres_config_json_schema from knot_resolver.datamodel.cache_schema import CacheClearRPCSchema from knot_resolver.datamodel.config_schema import KresConfig, get_rundir_without_validation from knot_resolver.datamodel.globals import Context, set_global_validation_context @@ -282,7 +283,7 @@ class Server: async def _handler_schema(self, _request: web.Request) -> web.Response: return web.json_response( - KresConfig.json_schema(), headers={"Access-Control-Allow-Origin": "*"}, dumps=partial(json.dumps, indent=4) + kres_config_json_schema(), headers={"Access-Control-Allow-Origin": "*"}, dumps=partial(json.dumps, indent=4) ) async def _handle_view_schema(self, _request: web.Request) -> web.Response: diff --git a/python/knot_resolver/utils/modeling/base_schema.py b/python/knot_resolver/utils/modeling/base_schema.py index aca3be05f..13539fe04 100644 --- a/python/knot_resolver/utils/modeling/base_schema.py +++ b/python/knot_resolver/utils/modeling/base_schema.py @@ -754,14 +754,31 @@ class BaseSchema(Serializable): return True @classmethod - def json_schema(cls: Type["BaseSchema"], include_schema_definition: bool = True) -> Dict[Any, Any]: + def json_schema( + cls: Type["BaseSchema"], + schema_id: Optional[str] = None, + title: Optional[str] = None, + description: Optional[str] = None, + include_schema_definition: bool = True, + ) -> Dict[Any, Any]: if cls._LAYER is not None: - return cls._LAYER.json_schema(include_schema_definition=include_schema_definition) + return cls._LAYER.json_schema( + schema_id=schema_id, + title=title, + description=description, + include_schema_definition=include_schema_definition, + ) schema: Dict[Any, Any] = {} if include_schema_definition: schema["$schema"] = "https://json-schema.org/draft/2020-12/schema" - if cls.__doc__ is not None: + if schema_id is not None: + schema["$id"] = schema_id + if title is not None: + schema["title"] = title + if description is not None: + schema["description"] = description + elif cls.__doc__ is not None: schema["description"] = _split_docstring(cls.__doc__)[0] schema["type"] = "object" schema["properties"] = _get_properties_schema(cls)