]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
python/knot_resolver: constants reorganization
authorAleš Mrázek <ales.mrazek@nic.cz>
Wed, 28 Aug 2024 09:01:34 +0000 (11:01 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 6 Sep 2024 22:28:31 +0000 (00:28 +0200)
python/knot_resolver/__init__.py
python/knot_resolver/client/command.py
python/knot_resolver/constants.py [new file with mode: 0644]
python/knot_resolver/controller/supervisord/config_file.py
python/knot_resolver/datamodel/config_schema.py
python/knot_resolver/datamodel/types/files.py
python/knot_resolver/manager/constants.py
python/knot_resolver/manager/kres_manager.py
python/knot_resolver/manager/log.py
python/knot_resolver/manager/main.py
python/knot_resolver/manager/server.py

index 511e8d44e7855b94e34c05426ceaf314dcbfb947..33ce9e879916242e672505ad70aec1b43104b339 100644 (file)
@@ -1,4 +1,4 @@
-from .datamodel.config_schema import KresConfig
+from .datamodel import KresConfig
 
 __version__ = "0.1.0"
 
index af59c42e7633393969644345d534c48f1369e60c..5d1bc3c7e755bc658f8cf3dcbddec1122892bad8 100644 (file)
@@ -5,8 +5,12 @@ from pathlib import Path
 from typing import Dict, List, Optional, Tuple, Type, TypeVar
 from urllib.parse import quote
 
-from knot_resolver.manager.constants import API_SOCK_ENV_VAR, CONFIG_FILE_ENV_VAR, DEFAULT_MANAGER_CONFIG_FILE
-from knot_resolver.datamodel.config_schema import DEFAULT_MANAGER_API_SOCK
+from knot_resolver.constants import (
+    CONFIG_FILE_PATH_DEFAULT,
+    CONFIG_FILE_PATH_ENV_VAR,
+    API_SOCK_PATH_ENV_VAR,
+    API_SOCK_PATH_DEFAULT,
+)
 from knot_resolver.datamodel.types import IPAddressPort
 from knot_resolver.utils.modeling import parsing
 from knot_resolver.utils.modeling.exceptions import DataValidationError
@@ -70,8 +74,8 @@ def determine_socket(namespace: argparse.Namespace) -> SocketDesc:
     if len(namespace.socket) > 0:
         return SocketDesc(namespace.socket[0], "--socket argument")
 
-    config_path = os.getenv(CONFIG_FILE_ENV_VAR)
-    socket_env = os.getenv(API_SOCK_ENV_VAR)
+    config_path = os.getenv(CONFIG_FILE_PATH_ENV_VAR)
+    socket_env = os.getenv(API_SOCK_PATH_ENV_VAR)
 
     socket: Optional[SocketDesc] = None
     # 2) socket from config file ('--config' argument)
@@ -82,15 +86,15 @@ def determine_socket(namespace: argparse.Namespace) -> SocketDesc:
         socket = get_socket_from_config(Path(config_path), False)
     # 4) socket from environment variable
     elif socket_env:
-        socket = SocketDesc(socket_env, f'Environment variable "{API_SOCK_ENV_VAR}"')
+        socket = SocketDesc(socket_env, f'Environment variable "{API_SOCK_PATH_ENV_VAR}"')
     # 5) socket from config file (default config file constant)
     else:
-        socket = get_socket_from_config(DEFAULT_MANAGER_CONFIG_FILE, True)
+        socket = get_socket_from_config(CONFIG_FILE_PATH_DEFAULT, True)
 
     if socket:
         return socket
     # 6) socket default
-    return SocketDesc(DEFAULT_MANAGER_API_SOCK, f'Default value "{DEFAULT_MANAGER_API_SOCK}"')
+    return SocketDesc(str(API_SOCK_PATH_DEFAULT), f'Default value "{API_SOCK_PATH_DEFAULT}"')
 
 
 class CommandArgs:
diff --git a/python/knot_resolver/constants.py b/python/knot_resolver/constants.py
new file mode 100644 (file)
index 0000000..f65876f
--- /dev/null
@@ -0,0 +1,41 @@
+import logging
+
+from importlib.metadata import version
+from importlib.util import find_spec
+from pathlib import Path
+
+# Installed Knot Resolver build options from Meson is semi-optional.
+# They are needed to run the resolver, but not for its unit tests.
+if find_spec("knot_resolver_build_options"):
+    import knot_resolver_build_options as build_conf  # type: ignore[import-not-found]
+else:
+    build_conf = None
+
+VERSION = version("knot_resolver") if find_spec("knot_resolver") else "6"
+WORKERS_MAX_DEFAULT = 256
+LOGGING_LEVEL_STARTUP = logging.DEBUG
+PID_FILE_NAME = "knot-resolver.pid"
+
+FIX_COUNTER_ATTEMPTS_MAX = 2
+FIX_COUNTER_DECREASE_INTERVAL_SEC = 30 * 60
+WATCHDOG_INTERVAL_SEC: float = 5
+
+USER_DEFAULT = build_conf.user if build_conf else "knot-resolver"
+GROUP_DEFAULT = build_conf.group if build_conf else "knot-resolver"
+
+RUN_DIR_DEFAULT: Path = build_conf.run_dir if build_conf else Path("/var/run/knot-resolver")
+ETC_DIR_DEFAULT: Path = build_conf.etc_dir if build_conf else Path("/etc/knot-resolver")
+CONFIG_FILE_PATH_DEFAULT = ETC_DIR_DEFAULT / "config.yaml"
+CONFIG_FILE_PATH_ENV_VAR = "KRES_MANAGER_CONFIG"
+API_SOCK_PATH_DEFAULT = RUN_DIR_DEFAULT / "kres-api.sock"
+API_SOCK_PATH_ENV_VAR = "KRES_MANAGER_API_SOCK"
+
+
+def kresd_executable() -> Path:
+    assert build_conf is not None
+    return build_conf.sbin_dir / "kresd"
+
+
+def kres_cache_gc_executable() -> Path:
+    assert build_conf is not None
+    return build_conf.sbin_dir / "kres-cache-gc"
index d9a79f9e48a7026157ba0db9ef0efd113c94711c..409c5387532bfab0c732d1889cd50e049c268c97 100644 (file)
@@ -6,11 +6,13 @@ from pathlib import Path
 from jinja2 import Template
 from typing_extensions import Literal
 
+from knot_resolver.constants import (
+    kres_cache_gc_executable,
+    kresd_executable,
+)
 from knot_resolver.manager.constants import (
-    kres_gc_executable,
-    kresd_cache_dir,
+    kres_cache_dir,
     kresd_config_file_supervisord_pattern,
-    kresd_executable,
     policy_loader_config_file,
     supervisord_config_file,
     supervisord_config_file_tmp,
@@ -96,7 +98,7 @@ class ProcessTypeConfig:
         return ProcessTypeConfig(  # type: ignore[call-arg]
             logfile=supervisord_subprocess_log_dir(config) / "gc.log",
             workdir=cwd,
-            command=f"{kres_gc_executable()} -c {kresd_cache_dir(config)}{kres_cache_gc_args(config)}",
+            command=f"{kres_cache_gc_executable()} -c {kres_cache_dir(config)}{kres_cache_gc_args(config)}",
             environment="",
         )
 
index 1ee300d85694f2bde9d77390c38a43c6b5dabfbf..e703f7a92b2f4cdd46b45591fc4a47313a966781 100644 (file)
@@ -5,7 +5,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union
 
 from typing_extensions import Literal
 
-from knot_resolver.manager.constants import MAX_WORKERS
+from knot_resolver.constants import RUN_DIR_DEFAULT, API_SOCK_PATH_DEFAULT, 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
@@ -25,10 +26,6 @@ from knot_resolver.utils.modeling import ConfigSchema
 from knot_resolver.utils.modeling.base_schema import lazy_default
 from knot_resolver.utils.modeling.exceptions import AggregateDataValidationError, DataValidationError
 
-_DEFAULT_RUNDIR = "/var/run/knot-resolver"
-
-DEFAULT_MANAGER_API_SOCK = _DEFAULT_RUNDIR + "/manager.sock"
-
 logger = logging.getLogger(__name__)
 
 
@@ -47,7 +44,7 @@ def _default_max_worker_count() -> int:
     c = _cpu_count()
     if c:
         return c * 10
-    return MAX_WORKERS
+    return WORKERS_MAX_DEFAULT
 
 
 def _get_views_tags(views: List[ViewSchema]) -> List[str]:
@@ -114,10 +111,10 @@ class KresConfig(ConfigSchema):
         version: int = 1
         nsid: Optional[EscapedStr] = None
         hostname: Optional[EscapedStr] = None
-        rundir: WritableDir = lazy_default(WritableDir, _DEFAULT_RUNDIR)
+        rundir: WritableDir = lazy_default(WritableDir, str(RUN_DIR_DEFAULT))
         workers: Union[Literal["auto"], IntPositive] = IntPositive(1)
         max_workers: IntPositive = IntPositive(_default_max_worker_count())
-        management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": DEFAULT_MANAGER_API_SOCK})
+        management: ManagementSchema = lazy_default(ManagementSchema, {"unix-socket": str(API_SOCK_PATH_DEFAULT)})
         webmgmt: Optional[WebmgmtSchema] = None
         options: OptionsSchema = OptionsSchema()
         network: NetworkSchema = NetworkSchema()
@@ -239,4 +236,4 @@ def get_rundir_without_validation(data: Dict[str, Any]) -> WritableDir:
     Used for initial manager startup.
     """
 
-    return WritableDir(data["rundir"] if "rundir" in data else _DEFAULT_RUNDIR, object_path="/rundir")
+    return WritableDir(data["rundir"] if "rundir" in data else RUN_DIR_DEFAULT, object_path="/rundir")
index 920d90b1379101ef09369c24dad4c4cef6b81882..2dde21e16e5fc7097c907d0b5986e5dd404a03eb 100644 (file)
@@ -6,7 +6,7 @@ from pathlib import Path
 from pwd import getpwnam
 from typing import Any, Dict, Tuple, Type, TypeVar
 
-from knot_resolver.manager.constants import kresd_group, kresd_user
+from knot_resolver.constants import USER_DEFAULT, GROUP_DEFAULT
 from knot_resolver.datamodel.globals import get_resolve_root, get_strict_validation
 from knot_resolver.utils.modeling.base_value_type import BaseValueType
 
@@ -157,14 +157,8 @@ def _kres_accessible(dest_path: Path, perm_mode: _PermissionMode) -> bool:
         _PermissionMode.EXECUTE: [stat.S_IXUSR, stat.S_IXGRP, stat.S_IXOTH],
     }
 
-    username = kresd_user()
-    groupname = kresd_group()
-
-    if username is None or groupname is None:
-        return True
-
-    user_uid = getpwnam(username).pw_uid
-    user_gid = getgrnam(groupname).gr_gid
+    user_uid = getpwnam(USER_DEFAULT).pw_uid
+    user_gid = getgrnam(GROUP_DEFAULT).gr_gid
 
     dest_stat = os.stat(dest_path)
     dest_uid = dest_stat.st_uid
@@ -201,7 +195,7 @@ class ReadableFile(File):
         super().__init__(source_value, parents=parents, object_path=object_path)
 
         if self.strict_validation and not _kres_accessible(self._value, _PermissionMode.READ):
-            raise ValueError(f"{kresd_user()}:{kresd_group()} has insufficient permissions to read '{self._value}'")
+            raise ValueError(f"{USER_DEFAULT}:{GROUP_DEFAULT} has insufficient permissions to read '{self._value}'")
 
 
 class WritableDir(Dir):
@@ -220,7 +214,7 @@ class WritableDir(Dir):
             self._value, _PermissionMode.WRITE | _PermissionMode.EXECUTE
         ):
             raise ValueError(
-                f"{kresd_user()}:{kresd_group()} has insufficient permissions to write/execute '{self._value}'"
+                f"{USER_DEFAULT}:{GROUP_DEFAULT} has insufficient permissions to write/execute '{self._value}'"
             )
 
 
@@ -241,5 +235,5 @@ class WritableFilePath(FilePath):
             self._value.parent, _PermissionMode.WRITE | _PermissionMode.EXECUTE
         ):
             raise ValueError(
-                f"{kresd_user()}:{kresd_group()} has insufficient permissions to write/execute'{self._value.parent}'"
+                f"{USER_DEFAULT}:{GROUP_DEFAULT} has insufficient permissions to write/execute'{self._value.parent}'"
             )
index 5a7317a59c3d823264ee5831f4dcdba3bdaa4e84..c1a6688498d0b9c1b1fc544ac02e70d01b204c0e 100644 (file)
@@ -1,49 +1,13 @@
-import importlib.util
-import logging
 from pathlib import Path
 from typing import TYPE_CHECKING, Optional
 
-# Install config is semi-optional - only needed to actually run Manager, but not
-# for its unit tests.
-if importlib.util.find_spec("knot_resolver_build_options"):
-    import knot_resolver_build_options  # type: ignore[import-not-found]
-else:
-    knot_resolver_build_options = None
-
 if TYPE_CHECKING:
     from knot_resolver.manager.config_store import ConfigStore
     from knot_resolver.datamodel.config_schema import KresConfig
     from knot_resolver.controller.interface import KresID
 
-STARTUP_LOG_LEVEL = logging.DEBUG
-DEFAULT_MANAGER_CONFIG_FILE = Path("/etc/knot-resolver/config.yaml")
-CONFIG_FILE_ENV_VAR = "KRES_MANAGER_CONFIG"
-API_SOCK_ENV_VAR = "KRES_MANAGER_API_SOCK"
-MANAGER_FIX_ATTEMPT_MAX_COUNTER = 2
-FIX_COUNTER_DECREASE_INTERVAL_SEC = 30 * 60
-PID_FILE_NAME = "manager.pid"
-MAX_WORKERS = 256
-
-
-def kresd_executable() -> Path:
-    assert knot_resolver_build_options is not None
-    return knot_resolver_build_options.sbin_dir / "kresd"
-
-
-def kres_gc_executable() -> Path:
-    assert knot_resolver_build_options is not None
-    return knot_resolver_build_options.sbin_dir / "kres-cache-gc"
-
 
-def kresd_user():
-    return None if knot_resolver is None else knot_resolver.user
-
-
-def kresd_group():
-    return None if knot_resolver is None else knot_resolver.group
-
-
-def kresd_cache_dir(config: "KresConfig") -> Path:
+def kres_cache_dir(config: "KresConfig") -> Path:
     return config.cache.storage.to_path()
 
 
@@ -79,12 +43,6 @@ def supervisord_subprocess_log_dir(_config: "KresConfig") -> Path:
     return Path("logs")
 
 
-WATCHDOG_INTERVAL: float = 5
-"""
-Used in KresdManager. It's a number of seconds in between system health checks.
-"""
-
-
 class _UserConstants:
     """
     Class for accessing constants, which are technically not constants as they are user configurable.
index 3dbc1079df7ac8603f2ab7cff41925d38bb97612..606f5b243d0d9ca9f5dc7cbec42673c2053ef728 100644 (file)
@@ -12,10 +12,10 @@ from knot_resolver.manager.config_store import (
     only_on_real_changes_update,
     only_on_real_changes_verifier,
 )
-from knot_resolver.manager.constants import (
+from knot_resolver.constants import (
+    FIX_COUNTER_ATTEMPTS_MAX,
     FIX_COUNTER_DECREASE_INTERVAL_SEC,
-    MANAGER_FIX_ATTEMPT_MAX_COUNTER,
-    WATCHDOG_INTERVAL,
+    WATCHDOG_INTERVAL_SEC,
 )
 from knot_resolver.manager.exceptions import SubprocessControllerException
 from knot_resolver.controller.interface import (
@@ -58,7 +58,7 @@ class _FixCounter:
         return str(self._counter)
 
     def is_too_high(self) -> bool:
-        return self._counter >= MANAGER_FIX_ATTEMPT_MAX_COUNTER
+        return self._counter >= FIX_COUNTER_ATTEMPTS_MAX
 
 
 async def _deny_max_worker_changes(config_old: KresConfig, config_new: KresConfig) -> Result[None, str]:
@@ -369,7 +369,7 @@ class KresManager:  # pylint: disable=too-many-instance-attributes
 
     async def _watchdog(self) -> None:  # pylint: disable=too-many-branches
         while True:
-            await asyncio.sleep(WATCHDOG_INTERVAL)
+            await asyncio.sleep(WATCHDOG_INTERVAL_SEC)
 
             self._fix_counter.try_decrease()
 
index a22898a5aae989dec273b3690f46a3fd484037d3..d34e57fe9005ac8459de6c54831ec8d0bc714377 100644 (file)
@@ -4,8 +4,8 @@ import os
 import sys
 from typing import Optional
 
+from knot_resolver.constants import LOGGING_LEVEL_STARTUP
 from knot_resolver.manager.config_store import ConfigStore, only_on_real_changes_update
-from knot_resolver.manager.constants import STARTUP_LOG_LEVEL
 from knot_resolver.datamodel.config_schema import KresConfig
 from knot_resolver.datamodel.logging_schema import LogTargetEnum
 
@@ -99,7 +99,7 @@ async def logger_init(config_store: ConfigStore) -> None:
 
 
 def logger_startup() -> None:
-    logging.getLogger().setLevel(STARTUP_LOG_LEVEL)
+    logging.getLogger().setLevel(LOGGING_LEVEL_STARTUP)
     err_handler = logging.StreamHandler(sys.stderr)
     err_handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
     logging.getLogger().addHandler(logging.handlers.MemoryHandler(10_000, logging.ERROR, err_handler))
index 5facc470ba7b3d7ed1c41248e6a1c136fb16d95e..315af01bf2990d7349dd6b62fc9d72bdd32b3f8b 100644 (file)
@@ -10,7 +10,7 @@ from pathlib import Path
 from typing import NoReturn
 
 from knot_resolver import compat
-from knot_resolver.manager.constants import CONFIG_FILE_ENV_VAR, DEFAULT_MANAGER_CONFIG_FILE
+from knot_resolver.constants import CONFIG_FILE_PATH_DEFAULT, CONFIG_FILE_PATH_ENV_VAR
 from knot_resolver.manager.log import logger_startup
 from knot_resolver.manager.server import start_server
 
@@ -20,7 +20,7 @@ def parse_args() -> argparse.Namespace:
     parser.add_argument(
         "-c",
         "--config",
-        help="Config file to load. Overrides default config location at '" + str(DEFAULT_MANAGER_CONFIG_FILE) + "'",
+        help="Config file to load. Overrides default config location at '" + str(CONFIG_FILE_PATH_ENV_VAR) + "'",
         type=str,
         nargs=1,
         required=False,
@@ -37,13 +37,13 @@ def main() -> NoReturn:
     args = parse_args()
 
     # where to look for config
-    config_env = os.getenv(CONFIG_FILE_ENV_VAR)
+    config_env = os.getenv(CONFIG_FILE_PATH_ENV_VAR)
     if args.config is not None:
         config_path = Path(args.config[0])
     elif config_env is not None:
         config_path = Path(config_env)
     else:
-        config_path = DEFAULT_MANAGER_CONFIG_FILE
+        config_path = CONFIG_FILE_PATH_DEFAULT
 
     exit_code = compat.asyncio.run(start_server(config=config_path))
     sys.exit(exit_code)
index cf31a3fc8cc9062bb5f5d62365da7680a30952a2..a25b5eb2a51995a625c36fa2ffc39e7126a8f595 100644 (file)
@@ -19,10 +19,11 @@ from aiohttp.web_runner import AppRunner, TCPSite, UnixSite
 from typing_extensions import Literal
 
 import knot_resolver.utils.custom_atexit as atexit
+from knot_resolver.constants import CONFIG_FILE_PATH_DEFAULT, PID_FILE_NAME
 from knot_resolver.manager import log, statistics
 from knot_resolver.compat import asyncio as asyncio_compat
 from knot_resolver.manager.config_store import ConfigStore
-from knot_resolver.manager.constants import DEFAULT_MANAGER_CONFIG_FILE, PID_FILE_NAME, init_user_constants
+from knot_resolver.manager.constants import init_user_constants
 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
@@ -504,7 +505,7 @@ async def _sigterm_while_shutting_down():
     sys.exit(128 + signal.SIGTERM)
 
 
-async def start_server(config: Path = DEFAULT_MANAGER_CONFIG_FILE) -> int:
+async def start_server(config: Path = CONFIG_FILE_PATH_DEFAULT) -> int:
     # This function is quite long, but it describes how manager runs. So let's silence pylint
     # pylint: disable=too-many-statements