]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager, kresctl: allow environment variables to specify paths
authorOto Šťáva <oto.stava@nic.cz>
Thu, 14 Sep 2023 12:00:28 +0000 (14:00 +0200)
committerOto Šťáva <oto.stava@nic.cz>
Fri, 22 Sep 2023 08:58:41 +0000 (10:58 +0200)
This is a bigger feature commit for development convenience with Knot
Resolver Manager. Firstly, it allows the use of `KRES_MANAGER_CONFIG`
and `KRES_MANAGER_RUNTIME` environment variables to specify the paths to
the configuration file and Knot Resolver runtime directory. This lets us
create local workspace scripts with separate configurations e.g. like
this:

```sh
script_dir="$(dirname "$(readlink -f "$0")")"
export KRES_MANAGER_RUNTIME="$script_dir"
export KRES_MANAGER_CONFIG="$script_dir/config.yaml"
exec ~/Projects/knot/knot-resolver/manager/poe $@
```

This ties nicely into the second part, which is that `kresctl` is now
able to retrieve the management socket/address directly from the
declarative configuration file of Knot Resolver. This again increases
convenience for developers who may wish to change these often, and not
have to specify/change them every time they want to execute `kresctl`
from the command line.

`kresctl` adds a new `--config` option to specify the path to the
configuration file via command line arguments, and also respects the
same `KRES_MANAGER_CONFIG` environment variable, when the argument is
not specified.

Co-authored-by: Aleš Mrázek <ales.mrazek@nic.cz>
manager/knot_resolver_manager/cli/command.py
manager/knot_resolver_manager/cli/main.py
manager/knot_resolver_manager/constants.py
manager/knot_resolver_manager/main.py
manager/scripts/run

index 6533de46cbd1fa88ad41e473a7b08236db5db8ad..2c532e8db03712c6b568c6d0e5c6c1c4b1ea7533 100644 (file)
@@ -1,15 +1,22 @@
 import argparse
+import os
 from abc import ABC, abstractmethod  # pylint: disable=[no-name-in-module]
 from pathlib import Path
 from typing import Dict, List, Optional, Tuple, Type, TypeVar
 from urllib.parse import quote
 
+from knot_resolver_manager.constants import CONFIG_FILE_ENV_VAR
+from knot_resolver_manager.utils.modeling import parsing
+
 T = TypeVar("T", bound=Type["Command"])
 
 CompWords = Dict[str, Optional[str]]
 
 _registered_commands: List[Type["Command"]] = []
 
+# FIXME ostava: Someone put a FIXME on this value without an explanation, so who knows what is wrong with it?
+DEFAULT_SOCKET = "http+unix://%2Fvar%2Frun%2Fknot-resolver%2Fmanager.sock"
+
 
 def register_command(cls: T) -> T:
     _registered_commands.append(cls)
@@ -37,7 +44,26 @@ class CommandArgs:
         self.subparser: argparse.ArgumentParser = namespace.subparser
         self.command: Type["Command"] = namespace.command
 
-        self.socket: str = namespace.socket[0]
+        config_env = os.getenv(CONFIG_FILE_ENV_VAR)
+        if len(namespace.socket) == 0 and len(namespace.config) == 0 and config_env is not None:
+            namespace.config = [config_env]
+
+        self.socket: str = DEFAULT_SOCKET
+        if len(namespace.socket) > 0:
+            self.socket = namespace.socket[0]
+        elif len(namespace.config) > 0:
+            with open(namespace.config[0], "r") as f:
+                config = parsing.try_to_parse(f.read())
+            if "management" in config:
+                management = config["management"]
+                if "unix_socket" in management:
+                    self.socket = management["unix_socket"]
+                elif "interface" in management:
+                    split = management["interface"].split("@")
+                    host = split[0]
+                    port = split[1] if len(split) >= 2 else 80
+                    self.socket = f"http://{host}:{port}"
+
         if Path(self.socket).exists():
             self.socket = f'http+unix://{quote(self.socket, safe="")}/'
         if self.socket.endswith("/"):
index dff41df2203657345fdaf1ffd84a7a3471c8ae2a..6c144a14a2ad6f72d7f6d8ed1211de4b34c5148f 100644 (file)
@@ -28,13 +28,26 @@ def create_main_argument_parser() -> argparse.ArgumentParser:
     #     default=False,
     #     required=False,
     # )
-    parser.add_argument(
+    config_or_socket = parser.add_mutually_exclusive_group()
+    config_or_socket.add_argument(
         "-s",
         "--socket",
         action="store",
         type=str,
-        help="Optional, path to Unix-domain socket or network interface of the management API.",
-        default=["http+unix://%2Fvar%2Frun%2Fknot-resolver%2Fmanager.sock"],  # FIXME
+        help="Optional, path to Unix-domain socket or network interface of the management API. "
+        "Cannot be used together with '--config'.",
+        default=[],
+        nargs=1,
+        required=False,
+    )
+    config_or_socket.add_argument(
+        "-c",
+        "--config",
+        action="store",
+        type=str,
+        help="Optional, path to Knot Resolver declarative configuration to retrieve socket or network "
+        "interface of the management API from. Cannot be used together with '--socket'.",
+        default=[],
         nargs=1,
         required=False,
     )
index a502267b97fa79f394d1c4dcce437ea5ee291d04..4ee3a22f7df702f09409d8fc9d2e7b0dcd4e502f 100644 (file)
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
 
 STARTUP_LOG_LEVEL = logging.DEBUG
 DEFAULT_MANAGER_CONFIG_FILE = Path("/etc/knot-resolver/config.yaml")
+CONFIG_FILE_ENV_VAR = "KRES_MANAGER_CONFIG"
 MANAGER_FIX_ATTEMPT_MAX_COUNTER = 2
 FIX_COUNTER_DECREASE_INTERVAL_SEC = 30 * 60
 PID_FILE_NAME = "manager.pid"
index f10e1799bae5af6f0d392bb24a29e1b6124c046a..5cbc7f28a77e96cb3bc0777335823a6db65f7f48 100644 (file)
@@ -4,12 +4,13 @@ file to allow us to exclude the __main__.py file from black's autoformatting
 """
 
 import argparse
+import os
 import sys
 from pathlib import Path
 from typing import NoReturn
 
 from knot_resolver_manager import compat
-from knot_resolver_manager.constants import DEFAULT_MANAGER_CONFIG_FILE
+from knot_resolver_manager.constants import DEFAULT_MANAGER_CONFIG_FILE, CONFIG_FILE_ENV_VAR
 from knot_resolver_manager.log import logger_startup
 from knot_resolver_manager.server import start_server
 
@@ -36,7 +37,13 @@ def main() -> NoReturn:
     args = parse_args()
 
     # where to look for config
-    config_path = DEFAULT_MANAGER_CONFIG_FILE if args.config is None else Path(args.config[0])
+    config_env = os.getenv(CONFIG_FILE_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
 
     exit_code = compat.asyncio.run(start_server(config=config_path))
     sys.exit(exit_code)
index db925a0d37da75b9b7e1bd6147ed928ab7c64053..23ed2458afcc7022a22f5dd96e586ea94e79a1c8 100755 (executable)
@@ -26,6 +26,13 @@ echo Knot Manager API is accessible on http://localhost:5000
 echo -------------------------------------------------------
 
 # create runtime directories
-mkdir -p etc/knot-resolver/runtime etc/knot-resolver/cache
+if [ -z "${KRES_MANAGER_RUNTIME:-}" ]; then
+    KRES_MANAGER_RUNTIME="etc/knot-resolver"
+fi
+mkdir -p "$KRES_MANAGER_RUNTIME/runtime" "$KRES_MANAGER_RUNTIME/cache"
 
-python3 -m knot_resolver_manager -c etc/knot-resolver/config.dev.yaml $@
+if [ -z "${KRES_MANAGER_CONFIG:-}" ]; then
+    KRES_MANAGER_CONFIG="$KRES_MANAGER_RUNTIME/config.dev.yaml"
+fi
+export KRES_MANAGER_CONFIG
+python3 -m knot_resolver_manager $@