From: Aleš Mrázek Date: Wed, 19 Feb 2025 12:16:46 +0000 (+0100) Subject: datamodel: management socket default based on rundir X-Git-Tag: v6.0.11~2^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10fb87547af05cd78e76dfb94951c34f4554d090;p=thirdparty%2Fknot-resolver.git datamodel: management socket default based on rundir --- diff --git a/doc/_static/config.schema.json b/doc/_static/config.schema.json index c0e30d3d3..aee7c3c4a 100644 --- a/doc/_static/config.schema.json +++ b/doc/_static/config.schema.json @@ -54,7 +54,7 @@ "default": 256 }, "management": { - "description": "Configuration of management HTTP API.", + "description": "Configuration of management HTTP API. By default, unix-socket is located in 'rundir'.", "type": "object", "properties": { "unix-socket": { @@ -75,7 +75,7 @@ } }, "default": { - "unix_socket": "/run/knot-resolver/kres-api.sock", + "unix_socket": "kres-api.sock", "interface": null } }, diff --git a/python/knot_resolver/client/command.py b/python/knot_resolver/client/command.py index 3966f8ca9..464eb16e6 100644 --- a/python/knot_resolver/client/command.py +++ b/python/knot_resolver/client/command.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Dict, List, Optional, Set, Tuple, Type, TypeVar from urllib.parse import quote -from knot_resolver.constants import API_SOCK_FILE, CONFIG_FILE +from knot_resolver.constants import API_SOCK_FILE, API_SOCK_NAME, CONFIG_FILE, RUN_DIR from knot_resolver.datamodel.types import IPAddressPort from knot_resolver.utils.modeling import parsing from knot_resolver.utils.modeling.exceptions import DataValidationError @@ -154,21 +154,38 @@ def get_socket_from_config(config: Path, optional_file: bool) -> Optional[Socket try: with open(config, "r", encoding="utf8") as f: data = parsing.try_to_parse(f.read()) + + rkey = "rundir" + rundir = Path(data[rkey]) if rkey in data else RUN_DIR + mkey = "management" if mkey in data: management = data[mkey] - if "unix-socket" in management: - return SocketDesc( - f'http+unix://{quote(management["unix-socket"], safe="")}/', - f'Key "/management/unix-socket" in "{config}" file', - ) - if "interface" in management: - ip = IPAddressPort(management["interface"], object_path=f"/{mkey}/interface") + + ikey = "interface" + if ikey in data[mkey]: + ip = IPAddressPort(data[mkey][ikey], object_path=f"/{mkey}/{ikey}") return SocketDesc( f"http://{ip.addr}:{ip.port}", f'Key "/management/interface" in "{config}" file', ) - return None + + skey = "unix-socket" + if skey in management: + socket = Path(management[skey]) + if not socket.is_absolute(): + socket = rundir / socket + return SocketDesc( + f'http+unix://{quote(str(socket), safe="")}/', + f'Key "/management/unix-socket" in "{config}" file', + ) + + socket = rundir / API_SOCK_NAME + return SocketDesc( + f'http+unix://{quote(str(socket), safe="")}/', + f'Key "/rundir" in "{config}" file', + ) + except ValueError as e: raise DataValidationError(*e.args) from e # pylint: disable=no-value-for-parameter except OSError as e: diff --git a/python/knot_resolver/datamodel/config_schema.py b/python/knot_resolver/datamodel/config_schema.py index 410e94d7c..f8733cb11 100644 --- a/python/knot_resolver/datamodel/config_schema.py +++ b/python/knot_resolver/datamodel/config_schema.py @@ -1,9 +1,10 @@ import logging import os import socket +from pathlib import Path from typing import Any, Dict, List, Literal, Optional, Tuple, Union -from knot_resolver.constants import API_SOCK_FILE, RUN_DIR, VERSION +from knot_resolver.constants import API_SOCK_NAME, RUN_DIR, VERSION from knot_resolver.datamodel.cache_schema import CacheSchema from knot_resolver.datamodel.defer_schema import DeferSchema from knot_resolver.datamodel.dns64_schema import Dns64Schema @@ -95,7 +96,7 @@ class KresConfig(ConfigSchema): rundir: Directory where the resolver can create files and which will be it's cwd. workers: The number of running kresd (Knot Resolver daemon) workers. If set to 'auto', it is equal to number of CPUs available. max_workers: The maximum number of workers allowed. Cannot be changed in runtime. - management: Configuration of management HTTP API. + management: Configuration of management HTTP API. By default, unix-socket is located in 'rundir'. webmgmt: Configuration of legacy web management endpoint. options: Fine-tuning global parameters of DNS resolver operation. network: Network connections and protocols configuration. @@ -118,7 +119,7 @@ class KresConfig(ConfigSchema): rundir: WritableDir = lazy_default(WritableDir, str(RUN_DIR)) workers: Union[Literal["auto"], IntPositive] = IntPositive(1) max_workers: IntPositive = IntPositive(WORKERS_MAX) - management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": str(API_SOCK_FILE)}) + management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": str(API_SOCK_NAME)}) webmgmt: Optional[WebmgmtSchema] = None options: OptionsSchema = OptionsSchema() network: NetworkSchema = NetworkSchema() @@ -173,6 +174,14 @@ class KresConfig(ConfigSchema): ) return obj.workers + def _management(self, obj: Raw) -> Any: + if obj.management.unix_socket: + soc = Path(obj.management.unix_socket.serialize()) + if soc.is_absolute(): + return obj.management + return ManagementSchema({"unix-socket": str(obj.rundir.to_path() / soc)}) + return obj.management + def _dnssec(self, obj: Raw) -> Any: if obj.dnssec is True: return DnssecSchema() @@ -259,7 +268,7 @@ def kres_config_json_schema() -> Dict[str, Any]: """ context = get_global_validation_context() - set_global_validation_context(Context(None, False)) + set_global_validation_context(Context(RUN_DIR, False)) schema = KresConfig.json_schema( schema_id=f"https://www.knot-resolver.cz/documentation/v{VERSION}/_static/config.schema.json", diff --git a/tests/manager/datamodel/test_config_schema.py b/tests/manager/datamodel/test_config_schema.py index 9ec2b31b2..437cade8d 100644 --- a/tests/manager/datamodel/test_config_schema.py +++ b/tests/manager/datamodel/test_config_schema.py @@ -1,7 +1,9 @@ import inspect import json +import os from typing import Any, Dict, Type, cast +from knot_resolver.constants import API_SOCK_FILE, API_SOCK_NAME, RUN_DIR from knot_resolver.datamodel import KresConfig from knot_resolver.datamodel.lua_schema import LuaSchema from knot_resolver.utils.modeling import BaseSchema @@ -49,10 +51,31 @@ def test_config_check_str_type(): def test_config_defaults(): config = KresConfig() + # Management API default + assert config.management.unix_socket.to_path() == API_SOCK_FILE + # DNS64 default assert config.dns64 == False +def test_management_unix_socket(): + cwd = os.getcwd() + config = KresConfig({"rundir": cwd}) + assert str(config.management.unix_socket) == f"{cwd}/{API_SOCK_NAME}" + + my_soc = "my-new.soc" + config = KresConfig({"management": {"unix-socket": my_soc}}) + assert str(config.management.unix_socket) == f"{RUN_DIR}/{my_soc}" + + +def test_management_interface(): + cwd = os.getcwd() + config = KresConfig({"rundir": cwd, "management": {"interface": "127.0.0.1@5000"}}) + + assert config.management.unix_socket == None + assert str(config.management.interface) == "127.0.0.1@5000" + + def test_dnssec_false(): config = KresConfig({"dnssec": False})