]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: manual selection of subprocess controllers (+ small fixes of scripts)
authorVasek Sraier <git@vakabus.cz>
Fri, 2 Jul 2021 21:06:12 +0000 (23:06 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 8 Apr 2022 14:17:52 +0000 (16:17 +0200)
closes #9

manager/knot_resolver_manager/__main__.py
manager/knot_resolver_manager/kres_manager.py
manager/knot_resolver_manager/kresd_controller/__init__.py
manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py
manager/knot_resolver_manager/kresd_controller/systemd/__init__.py
manager/knot_resolver_manager/server.py
manager/scripts/configure-vscode
manager/scripts/run
manager/scripts/run-debug

index eff94cae0119f56dc899012e960c68e013a6e162..ee6ab5e9a224621c9a552f046e7dd06fd694f60a 100644 (file)
@@ -1,4 +1,5 @@
 import logging
+import sys
 from pathlib import Path
 from typing import List, Optional, Tuple
 
@@ -6,6 +7,7 @@ import click
 
 from knot_resolver_manager import compat
 from knot_resolver_manager.constants import LISTEN_SOCKET_PATH, LOG_LEVEL, MANAGER_CONFIG_FILE
+from knot_resolver_manager.kresd_controller import list_controller_names
 from knot_resolver_manager.server import start_server
 from knot_resolver_manager.utils import ignore_exceptions_optional
 
@@ -21,7 +23,17 @@ from knot_resolver_manager.utils import ignore_exceptions_optional
     default=None,
     help="Overrides default config location at '" + str(MANAGER_CONFIG_FILE) + "'",
 )
-def main(listen: Optional[str], config: Optional[str]):
+@click.option(
+    "--backend",
+    "-b",
+    type=str,
+    nargs=1,
+    required=False,
+    default=None,
+    help="Use specified subprocess controller, default auto detection",
+)
+@click.option("--list-backends", "-l", type=bool, is_flag=True, default=False)
+def main(listen: Optional[str], config: Optional[str], backend: Optional[str], list_backends: bool):
     # pylint: disable=expression-not-assigned
 
     """Knot Resolver Manager
@@ -30,9 +42,16 @@ def main(listen: Optional[str], config: Optional[str]):
         MANAGER_CONFIG_FILE
     )
 
+    # print list of backends and exit (if specified)
+    if list_backends:
+        click.echo("Available subprocess controllers are:")
+        for n in list_controller_names():
+            click.echo(f" - {n}")
+        sys.exit(0)
+
+    # determine where should the manager listen based on the given argument
     tcp: List[Tuple[str, int]] = []
     unix: List[Path] = []
-
     if listen is None:
         unix.append(LISTEN_SOCKET_PATH)
     else:
@@ -42,9 +61,10 @@ def main(listen: Optional[str], config: Optional[str]):
         else:
             unix.append(Path(listen))
 
+    # where to look for config
     config_path = MANAGER_CONFIG_FILE if config is None else Path(config)
 
-    compat.asyncio.run(start_server(tcp=tcp, unix=unix, config=config_path))
+    compat.asyncio.run(start_server(tcp=tcp, unix=unix, config=config_path, subprocess_controller_name=backend))
 
 
 if __name__ == "__main__":
index a79c58f0a1518ca426dd3bbffdc0f70ec067a418..88a740767984b0222ca304a76a63958ce148f705 100644 (file)
@@ -24,13 +24,16 @@ class KresManager:
     """
 
     @classmethod
-    async def create(cls: Type["KresManager"]) -> "KresManager":
+    async def create(cls: Type["KresManager"], controller: Optional[SubprocessController]) -> "KresManager":
         obj = cls()
-        await obj._async_init()  # pylint: disable=protected-access
+        await obj._async_init(controller)  # pylint: disable=protected-access
         return obj
 
-    async def _async_init(self):
-        self._controller = await get_best_controller_implementation()
+    async def _async_init(self, selected_controller: Optional[SubprocessController]):
+        if selected_controller is None:
+            self._controller = await get_best_controller_implementation()
+        else:
+            self._controller = selected_controller
         await self._controller.initialize_controller()
         await self.load_system_state()
 
index e8840042da7c5745434f30ea3bd441340d353b77..3d2f7c29d1de91180de41de54c672c6e2c2b2ad1 100644 (file)
@@ -6,7 +6,7 @@ from imports, you can not see a simple list, but it's more complicated.
 
 import asyncio
 import logging
-from typing import List
+from typing import List, Optional
 
 from knot_resolver_manager.kresd_controller.interface import SubprocessController
 
@@ -71,6 +71,36 @@ async def get_best_controller_implementation() -> SubprocessController:
     raise LookupError("Can't find any available service manager!")
 
 
+def list_controller_names() -> List[str]:
+    """
+    Returns a list of names of registered controllers. The listed controllers are not necessarly functional.
+    """
+
+    return [str(controller) for controller in sorted(_registered_controllers, key=str)]
+
+
+async def get_controller_by_name(name: str) -> SubprocessController:
+    logger.debug("Subprocess controller selected manualy by the user, testing feasibility...")
+
+    controller: Optional[SubprocessController] = None
+    for c in sorted(_registered_controllers, key=str):
+        if str(c).startswith(name):
+            if str(c) != name:
+                logger.debug("Assuming '%s' is a shortcut for '%s'", name, str(c))
+            controller = c
+            break
+
+    if controller is None:
+        logger.error("Subprocess controller with name '%s' was not found", name)
+        raise LookupError(f"No subprocess controller named '{name}' found")
+
+    if await controller.is_controller_available():
+        logger.info("Selected controller '%s'", str(controller))
+        return controller
+    else:
+        raise LookupError("The selected subprocess controller is not available for use on this system.")
+
+
 # run the imports on module load
 try_systemd()
 try_supervisord()
index 576b915349cd7c033dac980afc07766b69a38a2b..ab88a3e0555d5c7ca8598d461445959f7a85616e 100644 (file)
@@ -54,7 +54,7 @@ class SupervisordSubprocessController(SubprocessController):
         self._watchdog_task: "Future[Any]"
 
     def __str__(self):
-        return type(self).__name__
+        return "supervisord"
 
     def should_be_running(self, subprocess: SupervisordSubprocess):
         return subprocess in self._running_instances
index 4164ae64e6411572f2a6d7c1d4398ee9bdc40186..9aaaefab029dc76ab2556366074b5a1f0fcfd961 100644 (file)
@@ -72,11 +72,11 @@ class SystemdSubprocessController(SubprocessController):
     def __str__(self):
         if self._systemd_type == systemd.SystemdType.SESSION:
             if self._persistance_type is SystemdPersistanceType.TRANSIENT:
-                return "SystemdController(SESSION, TRANSIENT)"
+                return "systemd-session-transient"
             else:
-                return "SystemdController(SESSION)"
+                return "systemd-session"
         elif self._systemd_type == systemd.SystemdType.SYSTEM:
-            return "SystemdController(SYSTEM)"
+            return "systemd"
         else:
             raise NotImplementedError("unknown systemd type")
 
index fc497e3c8797bfd4e22cf5580c38597f1aaf159f..da41541ffff253ce18a60ce182471c0188b2ad88 100644 (file)
@@ -5,7 +5,7 @@ from functools import partial
 from http import HTTPStatus
 from pathlib import Path
 from time import time
-from typing import Any, List, Tuple, Union
+from typing import Any, List, Optional, Tuple, Union
 
 from aiohttp import web
 from aiohttp.web import middleware
@@ -13,6 +13,8 @@ from aiohttp.web_response import json_response
 
 from knot_resolver_manager.constants import MANAGER_CONFIG_FILE
 from knot_resolver_manager.exceptions import ValidationException
+from knot_resolver_manager.kresd_controller import get_controller_by_name
+from knot_resolver_manager.kresd_controller.interface import SubprocessController
 from knot_resolver_manager.utils.async_utils import readfile
 from knot_resolver_manager.utils.dataclasses_parservalidator import Format
 
@@ -111,14 +113,23 @@ class _DefaultSentinel:
 _DEFAULT_SENTINEL = _DefaultSentinel()
 
 
-async def _init_manager(config: Union[None, Path, KresConfig, _DefaultSentinel], app: web.Application):
+async def _init_manager(
+    config: Union[None, Path, KresConfig, _DefaultSentinel],
+    subprocess_controller_name: Optional[str],
+    app: web.Application,
+):
     """
     Called asynchronously when the application initializes.
     """
     try:
+        # if configured, create a subprocess controller manually
+        controller: Optional[SubprocessController] = None
+        if subprocess_controller_name is not None:
+            controller = await get_controller_by_name(subprocess_controller_name)
+
         # Create KresManager. This will perform autodetection of available service managers and
-        # select the most appropriate to use
-        manager = await KresManager.create()
+        # select the most appropriate to use (or use the one configured directly)
+        manager = await KresManager.create(controller)
         app[_MANAGER] = manager
 
         # Initial configuration of the manager
@@ -152,6 +163,7 @@ async def start_server(
     tcp: List[Tuple[str, int]],
     unix: List[Path],
     config: Union[None, Path, KresConfig, _DefaultSentinel] = _DEFAULT_SENTINEL,
+    subprocess_controller_name: Optional[str] = None,
 ):
     start_time = time()
 
@@ -160,7 +172,7 @@ async def start_server(
     app[_MANAGER] = None
     app[_SHUTDOWN_EVENT] = asyncio.Event()
 
-    app.on_startup.append(partial(_init_manager, config))
+    app.on_startup.append(partial(_init_manager, config, subprocess_controller_name))
 
     # configure routing
     setup_routes(app)
index dfbe4d6488c1a9dd5abf893848492c1bdfb379f9..5032a6ba17223442b84c88780f6d9ba792cc9326 100755 (executable)
@@ -21,7 +21,7 @@ mkdir -p .vscode
 # settings.json
 cat > .vscode/settings.json <<EOF
 {
-    "python.pythonPath": "$(poetry env info -p)",
+    "python.defaultInterpreterPath": "$(poetry env info -p)",
     "python.venvPath": "~/.cache/pypoetry/virtualenvs"
 }
 EOF
@@ -45,7 +45,7 @@ cat > .vscode/launch.json <<EOF
             },
             "pathMappings": [
                 {
-                    "localRoot": "${workspaceFolder}",
+                    "localRoot": "\${workspaceFolder}",
                     "remoteRoot": "."
                 }
             ]
index a975fb649d9cfe586790cf27349d9a3719ae4d9d..f267064a012bba708dd50ed3c92677be61df0c82 100755 (executable)
@@ -7,4 +7,4 @@ source $src_dir/_env.sh
 echo Knot Manager API is accessible on http://localhost:5000
 echo -------------------------------------------------------
 
-poetry run python -m knot_resolver_manager 5000 # -c config/kres-manager.yaml
\ No newline at end of file
+poetry run python -m knot_resolver_manager 5000 $@
\ No newline at end of file
index f1754ec01afd020e082d43b0147b9a75e20a0816..7f7746b5613764dca485834684e8905b11de810a 100755 (executable)
@@ -10,4 +10,4 @@ echo The manager will start after you connect
 echo API will be running on port 5000
 echo ----------------------------------------
 
-poetry run python -m debugpy --listen 0.0.0.0:5678 --wait-for-client -m knot_resolver_manager 5000
\ No newline at end of file
+poetry run python -m debugpy --listen 0.0.0.0:5678 --wait-for-client -m knot_resolver_manager 5000 $@
\ No newline at end of file