Skip to content

Commit 7345b2e

Browse files
committed
Merge !1657: datamodel: management: default unix-socket based on rundir
2 parents 5025f1e + 9b6ba43 commit 7345b2e

File tree

7 files changed

+77
-21
lines changed

7 files changed

+77
-21
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Improvements
1212
------------
1313
- manager: allow multiple instances with different rundirs (!1656)
1414
- tests: disable problematic config.http test (#925, !1662)
15+
- /management/unix-socket: allow path relative to rundir (!1657)
1516

1617

1718
Knot Resolver 6.0.10 (2025-01-20)

doc/_static/config.schema.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"default": 256
5555
},
5656
"management": {
57-
"description": "Configuration of management HTTP API.",
57+
"description": "Configuration of management HTTP API. By default, unix-socket is located in 'rundir'.",
5858
"type": "object",
5959
"properties": {
6060
"unix-socket": {
@@ -75,7 +75,7 @@
7575
}
7676
},
7777
"default": {
78-
"unix_socket": "/run/knot-resolver/kres-api.sock",
78+
"unix_socket": "kres-api.sock",
7979
"interface": null
8080
}
8181
},

python/knot_resolver/client/command.py

+26-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import Dict, List, Optional, Set, Tuple, Type, TypeVar
55
from urllib.parse import quote
66

7-
from knot_resolver.constants import API_SOCK_FILE, CONFIG_FILE
7+
from knot_resolver.constants import API_SOCK_FILE, API_SOCK_NAME, CONFIG_FILE, RUN_DIR
88
from knot_resolver.datamodel.types import IPAddressPort
99
from knot_resolver.utils.modeling import parsing
1010
from knot_resolver.utils.modeling.exceptions import DataValidationError
@@ -154,21 +154,38 @@ def get_socket_from_config(config: Path, optional_file: bool) -> Optional[Socket
154154
try:
155155
with open(config, "r", encoding="utf8") as f:
156156
data = parsing.try_to_parse(f.read())
157+
158+
rkey = "rundir"
159+
rundir = Path(data[rkey]) if rkey in data else RUN_DIR
160+
157161
mkey = "management"
158162
if mkey in data:
159163
management = data[mkey]
160-
if "unix-socket" in management:
161-
return SocketDesc(
162-
f'http+unix://{quote(management["unix-socket"], safe="")}/',
163-
f'Key "/management/unix-socket" in "{config}" file',
164-
)
165-
if "interface" in management:
166-
ip = IPAddressPort(management["interface"], object_path=f"/{mkey}/interface")
164+
165+
ikey = "interface"
166+
if ikey in data[mkey]:
167+
ip = IPAddressPort(data[mkey][ikey], object_path=f"/{mkey}/{ikey}")
167168
return SocketDesc(
168169
f"http://{ip.addr}:{ip.port}",
169170
f'Key "/management/interface" in "{config}" file',
170171
)
171-
return None
172+
173+
skey = "unix-socket"
174+
if skey in management:
175+
socket = Path(management[skey])
176+
if not socket.is_absolute():
177+
socket = rundir / socket
178+
return SocketDesc(
179+
f'http+unix://{quote(str(socket), safe="")}/',
180+
f'Key "/management/unix-socket" in "{config}" file',
181+
)
182+
183+
socket = rundir / API_SOCK_NAME
184+
return SocketDesc(
185+
f'http+unix://{quote(str(socket), safe="")}/',
186+
f'Key "/rundir" in "{config}" file',
187+
)
188+
172189
except ValueError as e:
173190
raise DataValidationError(*e.args) from e # pylint: disable=no-value-for-parameter
174191
except OSError as e:

python/knot_resolver/constants.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
USER = "knot-resolver"
66
GROUP = "knot-resolver"
77

8-
# dirs paths
8+
# default files names
9+
API_SOCK_NAME = "kres-api.sock"
10+
11+
# default dirs paths
912
RUN_DIR = Path("/run/knot-resolver")
1013
ETC_DIR = Path("/etc/knot-resolver")
1114
SBIN_DIR = Path("/usr/sbin")
1215
CACHE_DIR = Path("/var/cache/knot-resolver")
1316

14-
# files paths
17+
# default files paths
1518
CONFIG_FILE = ETC_DIR / "config.yaml"
16-
API_SOCK_FILE = RUN_DIR / "kres-api.sock"
19+
API_SOCK_FILE = RUN_DIR / API_SOCK_NAME
1720

1821
# executables paths
1922
KRESD_EXECUTABLE = SBIN_DIR / "kresd"

python/knot_resolver/constants.py.in

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ VERSION = "@version@"
55
USER = "@user@"
66
GROUP = "@group@"
77

8-
# dirs paths
8+
# default files names
9+
API_SOCK_NAME = "kres-api.sock"
10+
11+
# default dirs paths
912
RUN_DIR = Path("@run_dir@")
1013
ETC_DIR = Path("@etc_dir@")
1114
SBIN_DIR = Path("@sbin_dir@")
1215
CACHE_DIR = Path("@cache_dir@")
1316

14-
# files paths
17+
# default files paths
1518
CONFIG_FILE = ETC_DIR / "config.yaml"
16-
API_SOCK_FILE = RUN_DIR / "kres-api.sock"
19+
API_SOCK_FILE = RUN_DIR / API_SOCK_NAME
1720

1821
# executables paths
1922
KRESD_EXECUTABLE = SBIN_DIR / "kresd"

python/knot_resolver/datamodel/config_schema.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import logging
22
import os
33
import socket
4+
from pathlib import Path
45
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
56

6-
from knot_resolver.constants import API_SOCK_FILE, RUN_DIR, VERSION
7+
from knot_resolver.constants import API_SOCK_NAME, RUN_DIR, VERSION
78
from knot_resolver.datamodel.cache_schema import CacheSchema
89
from knot_resolver.datamodel.defer_schema import DeferSchema
910
from knot_resolver.datamodel.dns64_schema import Dns64Schema
@@ -95,7 +96,7 @@ class Raw(ConfigSchema):
9596
rundir: Directory where the resolver can create files and which will be it's cwd.
9697
workers: The number of running kresd (Knot Resolver daemon) workers. If set to 'auto', it is equal to number of CPUs available.
9798
max_workers: The maximum number of workers allowed. Cannot be changed in runtime.
98-
management: Configuration of management HTTP API.
99+
management: Configuration of management HTTP API. By default, unix-socket is located in 'rundir'.
99100
webmgmt: Configuration of legacy web management endpoint.
100101
options: Fine-tuning global parameters of DNS resolver operation.
101102
network: Network connections and protocols configuration.
@@ -118,7 +119,7 @@ class Raw(ConfigSchema):
118119
rundir: WritableDir = lazy_default(WritableDir, str(RUN_DIR))
119120
workers: Union[Literal["auto"], IntPositive] = IntPositive(1)
120121
max_workers: IntPositive = IntPositive(WORKERS_MAX)
121-
management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": str(API_SOCK_FILE)})
122+
management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": str(API_SOCK_NAME)})
122123
webmgmt: Optional[WebmgmtSchema] = None
123124
options: OptionsSchema = OptionsSchema()
124125
network: NetworkSchema = NetworkSchema()
@@ -173,6 +174,14 @@ def _workers(self, obj: Raw) -> Any:
173174
)
174175
return obj.workers
175176

177+
def _management(self, obj: Raw) -> Any:
178+
if obj.management.unix_socket:
179+
soc = Path(obj.management.unix_socket.serialize())
180+
if soc.is_absolute():
181+
return obj.management
182+
return ManagementSchema({"unix-socket": str(obj.rundir.to_path() / soc)})
183+
return obj.management
184+
176185
def _dnssec(self, obj: Raw) -> Any:
177186
if obj.dnssec is True:
178187
return DnssecSchema()
@@ -259,7 +268,7 @@ def kres_config_json_schema() -> Dict[str, Any]:
259268
"""
260269

261270
context = get_global_validation_context()
262-
set_global_validation_context(Context(None, False))
271+
set_global_validation_context(Context(RUN_DIR, False))
263272

264273
schema = KresConfig.json_schema(
265274
schema_id=f"https://www.knot-resolver.cz/documentation/v{VERSION}/_static/config.schema.json",

tests/manager/datamodel/test_config_schema.py

+23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import inspect
22
import json
3+
import os
34
from typing import Any, Dict, Type, cast
45

6+
from knot_resolver.constants import API_SOCK_FILE, API_SOCK_NAME, RUN_DIR
57
from knot_resolver.datamodel import KresConfig
68
from knot_resolver.datamodel.lua_schema import LuaSchema
79
from knot_resolver.utils.modeling import BaseSchema
@@ -49,10 +51,31 @@ def _check_str_type(cls: Type[Any], object_path: str = ""):
4951
def test_config_defaults():
5052
config = KresConfig()
5153

54+
# Management API default
55+
assert config.management.unix_socket.to_path() == API_SOCK_FILE
56+
5257
# DNS64 default
5358
assert config.dns64 == False
5459

5560

61+
def test_management_unix_socket():
62+
cwd = os.getcwd()
63+
config = KresConfig({"rundir": cwd})
64+
assert str(config.management.unix_socket) == f"{cwd}/{API_SOCK_NAME}"
65+
66+
my_soc = "my-new.soc"
67+
config = KresConfig({"management": {"unix-socket": my_soc}})
68+
assert str(config.management.unix_socket) == f"{RUN_DIR}/{my_soc}"
69+
70+
71+
def test_management_interface():
72+
cwd = os.getcwd()
73+
config = KresConfig({"rundir": cwd, "management": {"interface": "127.0.0.1@5000"}})
74+
75+
assert config.management.unix_socket == None
76+
assert str(config.management.interface) == "127.0.0.1@5000"
77+
78+
5679
def test_dnssec_false():
5780
config = KresConfig({"dnssec": False})
5881

0 commit comments

Comments
 (0)