]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
bug fixes
authorVasek Sraier <git@vakabus.cz>
Wed, 3 Nov 2021 11:02:27 +0000 (12:02 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 8 Apr 2022 14:17:53 +0000 (16:17 +0200)
- fixed failure to start on python 3.9
- fixed issues with starting with supervisord

manager/knot_resolver_manager/compat/asyncio.py
manager/knot_resolver_manager/compat/dataclasses.py
manager/knot_resolver_manager/kres_id.py
manager/knot_resolver_manager/kres_manager.py
manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py
manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2
manager/pyproject.toml
manager/scripts/codecheck
manager/scripts/container.py
manager/scripts/create_setup.py
manager/setup.py

index b1ff8b3a8eccf134256ca417ccd79cd343677dae..d7cf150c1c56a7f0be73e156805565b3f4cfcca3 100644 (file)
@@ -26,7 +26,7 @@ T = TypeVar("T")
 async def to_thread(func: Callable[..., T], *args: Any, **kwargs: Any) -> T:
     # version 3.9 and higher, call directly
     if sys.version_info.major >= 3 and sys.version_info.minor >= 9:
-        return asyncio.to_thread(func, *args, **kwargs)
+        return await asyncio.to_thread(func, *args, **kwargs)
 
     # earlier versions, run with default executor
     else:
index 7f5628c4c13e4250b9fa9607f78f7c099be3e53e..7302612f2066e89a4f185cd017fa7c4456877a17 100644 (file)
@@ -29,7 +29,10 @@ def dataclass(cls: Any):
 
         # set keyd arguments
         for key, val in kwargs.items():
-            assert key in anot, f"Key '{key}' not defined with a type annotation"
+            assert key in anot, (
+                f"Constructing dataclass with an argument '{key}' which is not defined with a type"
+                f" annotation in class {cls.__name__}"
+            )
             setattr(slf, key, val)
             used.add(key)
 
index 4ad83df06abb2cf984cc234ea83746d8cba1e1aa..002410630f884109d585377d5b78ed5a6e670b7a 100644 (file)
@@ -48,7 +48,7 @@ def alloc_from_string(val: str) -> KresID:
     int_val = ignore_exceptions_optional(int, None, ValueError)(int)(val)
     if int_val is not None:
         res = KresID(int_val)
-        assert res not in _used
+        assert res not in _used, "Force allocating a KresID, which already exists..."
         _used.add(res)
         return res
     else:
index 70ea02b6700eac5f9bc63c350bd525ca401cfafd..1dc772134efe5f140330dbff11919e4289d251f9 100644 (file)
@@ -154,13 +154,13 @@ class KresManager:
                     await self._stop_gc()
 
     async def stop(self):
+        if self._watchdog_task is not None:
+            self._watchdog_task.cancel()
+
         async with self._manager_lock:
             await self._ensure_number_of_children(KresConfig(), 0)
             await self._controller.shutdown_controller()
 
-        if self._watchdog_task is not None:
-            self._watchdog_task.cancel()
-
     async def _instability_handler(self) -> None:
         logger.error(
             "Instability callback invoked. Something is wrong, no idea how to react."
index 4a85cbcb20fa6386ef09b66e6d81a24a83607343..04ca84eea7d41b8173d3ed4229080dabe35f0e13 100644 (file)
@@ -25,7 +25,7 @@ from knot_resolver_manager.constants import (
     supervisord_subprocess_log_dir,
 )
 from knot_resolver_manager.datamodel.config_schema import KresConfig
-from knot_resolver_manager.kres_id import KresID, lookup_from_string
+from knot_resolver_manager.kres_id import KresID, alloc_from_string, lookup_from_string
 from knot_resolver_manager.kresd_controller.interface import (
     Subprocess,
     SubprocessController,
@@ -49,6 +49,7 @@ class _Instance:
     Data structure holding data for supervisord config template
     """
 
+    type: str
     logfile: str
     id: str
     workdir: str
@@ -68,7 +69,6 @@ def _get_command_based_on_type(config: KresConfig, i: "SupervisordSubprocess") -
 async def _write_config_file(config: KresConfig, instances: Set["SupervisordSubprocess"]):
     @dataclass
     class SupervisordConfig:
-        type: str
         unix_http_server: str
         pid_file: str
         workdir: str
@@ -80,7 +80,7 @@ async def _write_config_file(config: KresConfig, instances: Set["SupervisordSubp
     config_string = Template(template).render(
         instances=[
             _Instance(
-                type=i.type,
+                type=i.type.name,
                 logfile=supervisord_subprocess_log_dir(config) / f"{i.id}.log",
                 id=str(i.id),
                 workdir=str(os.getcwd()),
@@ -89,14 +89,12 @@ async def _write_config_file(config: KresConfig, instances: Set["SupervisordSubp
             )
             for i in instances
         ],
-        config={
-            SupervisordConfig(
-                unix_http_server=supervisord_sock_file(config),
-                pid_file=supervisord_pid_file(config),
-                workdir=str(config.server.management.rundir.to_path().absolute()),
-                log_file=supervisord_log_file(config),
-            )
-        },
+        config=SupervisordConfig(
+            unix_http_server=supervisord_sock_file(config),
+            pid_file=supervisord_pid_file(config),
+            workdir=str(config.server.management.rundir.to_path().absolute()),
+            logfile=supervisord_log_file(config),
+        ),
     )
     await writefile(supervisord_config_file_tmp(config), config_string)
     # atomically replace
@@ -191,7 +189,7 @@ async def _list_ids_from_existing_config(cfg: KresConfig) -> List[Tuple[Subproce
     for section in cp.sections():
         if section.startswith("program:"):
             program_id = section.replace("program:", "")
-            iid = lookup_from_string(program_id)
+            iid = alloc_from_string(program_id)
             typ = SubprocessType[cp[section].get("type")]
             res.append((typ, iid))
     return res
@@ -294,4 +292,4 @@ class SupervisordSubprocessController(SubprocessController):
         return SupervisordSubprocess(subprocess_config, self, id_hint, subprocess_type)
 
     async def get_subprocess_status(self) -> Dict[KresID, SubprocessStatus]:
-        return await to_thread(_list_subprocesses)
+        return await to_thread(_list_subprocesses, self._controller_config)
index 7739c4a0e332cf84fff739f96cb79cf790935bdf..84c7c55c322599c75f3ca1f380e49edeb5214a45 100644 (file)
@@ -2,7 +2,7 @@
 pidfile = {{ config.pid_file }}
 directory = {{ config.workdir }}
 nodaemon = false
-logfile = {{ config.log_file }}
+logfile = {{ config.logfile }}
 logfile_maxbytes = 50MB
 {# user=root #}
 
index f43566ee0d1c61e96df2bbf0720b27c7f8a115e6..8e2977a0a6bb526cab6a981ebf1e3215a00ad9a5 100644 (file)
@@ -3,7 +3,7 @@ name = "knot-resolver-manager"
 version = "0.1.0"
 description = "A central management tool for multiple instances of Knot Resolver"
 authors = [
-    "Vašek Šraier <git@vakabus.cz>",
+    "Václav Šraier <vaclav.sraier@nic.cz>",
     "Aleš Mrázek <ales.mrazek@nic.cz>"
 ]
 
@@ -41,7 +41,7 @@ run-debug = { cmd = "scripts/run-debug", help = "Run the manager under debugger"
 docs = { cmd = "scripts/docs", help = "Create HTML documentation" }
 test = { cmd = "pytest --cov=knot_resolver_manager --show-capture=all tests/", help = "Run tests" }
 check = { cmd = "scripts/codecheck", help = "Run static code analysis" }
-format = { shell = "poetry run black knot_resolver_manager/ tests/ integration/; isort .", help = "Run code formatter" }
+format = { shell = "black knot_resolver_manager/ tests/ integration/ scripts/; isort .", help = "Run code formatter" }
 fixdeps = { shell = "poetry install; npm install; npm update", help = "Install/update dependencies according to configuration files"}
 commit = { shell = "scripts/commit", help = "Invoke every single check before commiting" }
 container = { cmd = "scripts/container.py", help = "Manage containers" }
index 5f16d97851c70195f322c1912c7ef0ccbcc2e845..ea9c7d984597cfa1bbdac14e6aaa65bdded8d24f 100755 (executable)
@@ -18,7 +18,7 @@ set +e
 
 # check formatting using black
 echo -e "${yellow}Checking formatting using black...${reset}"
-black knot_resolver_manager tests integration --check --diff
+black knot_resolver_manager tests integration scripts --check --diff
 check_rv $?
 echo
 
index 5b6e85faa7d22dab07ea60479937034898ee2422..191fcae2b250bbcdca7dc802aef8d44acd848e2b 100755 (executable)
@@ -12,9 +12,7 @@ import click
 
 
 def _get_git_root() -> Path:
-    result = subprocess.run(
-        "git rev-parse --show-toplevel", shell=True, stdout=subprocess.PIPE
-    )
+    result = subprocess.run("git rev-parse --show-toplevel", shell=True, stdout=subprocess.PIPE)
     return Path(str(result.stdout, encoding="utf8").strip())
 
 
@@ -23,20 +21,13 @@ PODMAN_EXECUTABLE = "/usr/bin/podman"
 CACHE_DIR: Path = GIT_ROOT / ".podman-cache"
 
 
-
-
-def _start_detached(
-    image: str, publish: List[int] = [], ro_mounts: Dict[Path, Path] = {}
-) -> str:
+def _start_detached(image: str, publish: List[int] = [], ro_mounts: Dict[Path, Path] = {}) -> str:
     """Start a detached container"""
     options = [f"--publish={port}:{port}/tcp" for port in publish] + [
-        f"--volume={str(src)}:{str(dst)}:O"
-        for src, dst in ro_mounts.items()
+        f"--volume={str(src)}:{str(dst)}:O" for src, dst in ro_mounts.items()
     ]
     command = ["podman", "run", "--rm", "-d", "--security-opt=seccomp=unconfined", *options, image]
-    proc = subprocess.run(
-        command, shell=False, executable=PODMAN_EXECUTABLE, stdout=subprocess.PIPE
-    )
+    proc = subprocess.run(command, shell=False, executable=PODMAN_EXECUTABLE, stdout=subprocess.PIPE)
     assert proc.returncode == 0
     return str(proc.stdout, "utf8").strip()
 
@@ -70,24 +61,25 @@ def _extract_tag_from_name(name: str, all: List[str] = _list_available_image_tag
     if ":" in name:
         s = name.split(":")
         if not s[0].endswith("knot-manager"):
-            click.secho(f"Unexpected image name \'{s[0]}\', expected \'knot-manager\'", fg="red")
+            click.secho(f"Unexpected image name '{s[0]}', expected 'knot-manager'", fg="red")
             sys.exit(1)
         name = s[-1]
-    
+
     if not name in all:
-        click.secho(f"Unexpected tag \'{name}\'", fg="red")
+        click.secho(f"Unexpected tag '{name}'", fg="red")
         click.secho(f"Available tags are [{' '.join(all)}]", fg="yellow")
         sys.exit(1)
-    
+
     return name
 
+
 def _get_tags_to_work_on(args: List[str]) -> List[str]:
     args = list(args)
 
     all = _list_available_image_tags()
 
     # convert to tags, if the user specified full names
-    for i,a in enumerate(args):
+    for i, a in enumerate(args):
         args[i] = _extract_tag_from_name(a, all)
 
     if len(args) == 0:
@@ -101,7 +93,16 @@ def _full_name_from_tag(tag: str) -> str:
 
 
 def _build(tag: str):
-    command = ["podman", "build", "--security-opt=seccomp=unconfined", "-f", str(GIT_ROOT / "containers" / tag / "Containerfile"), "-t", _full_name_from_tag(tag), str(GIT_ROOT)]
+    command = [
+        "podman",
+        "build",
+        "--security-opt=seccomp=unconfined",
+        "-f",
+        str(GIT_ROOT / "containers" / tag / "Containerfile"),
+        "-t",
+        _full_name_from_tag(tag),
+        str(GIT_ROOT),
+    ]
     ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE)
     assert ret == 0
 
@@ -119,17 +120,34 @@ def _push(tag: str):
 
 
 def _login_ci():
-    command = ["podman", "login", "-u", environ["CI_REGISTRY_USER"], "-p", environ["CI_REGISTRY_PASSWORD"], environ["CI_REGISTRY"]]
+    command = [
+        "podman",
+        "login",
+        "-u",
+        environ["CI_REGISTRY_USER"],
+        "-p",
+        environ["CI_REGISTRY_PASSWORD"],
+        environ["CI_REGISTRY"],
+    ]
     ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE)
     assert ret == 0
 
 
 def _save(tag: str):
     CACHE_DIR.mkdir(exist_ok=True)
-    command = ["podman", "save", "--format", "oci-archive", "-o", str(CACHE_DIR / (tag + ".tar")), _full_name_from_tag(tag)]
+    command = [
+        "podman",
+        "save",
+        "--format",
+        "oci-archive",
+        "-o",
+        str(CACHE_DIR / (tag + ".tar")),
+        _full_name_from_tag(tag),
+    ]
     ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE)
     assert ret == 0
 
+
 def _load(tag: str):
     cache_file = CACHE_DIR / (tag + ".tar")
     if cache_file.exists():
@@ -138,7 +156,6 @@ def _load(tag: str):
         assert ret == 0
 
 
-
 @click.group()
 def main():
     pass
@@ -154,7 +171,6 @@ def pull(images: List[str]):
         _pull(tag)
 
 
-
 @main.command(help="Build project containers")
 @click.argument("images", nargs=-1)
 @click.option("-f", "--fetch", "fetch", is_flag=True, default=False, type=bool, help="Pull before building")
@@ -166,12 +182,12 @@ def build(images: List[str], fetch: bool, ci_login: bool, push: bool, file_cache
 
     if ci_login:
         _login_ci()
-    
+
     for tag in tags:
         if fetch:
             click.secho(f"Pulling image with tag {tag}", fg="yellow")
             _pull(tag)
-        
+
         if file_cache:
             _load(tag)
 
@@ -181,7 +197,7 @@ def build(images: List[str], fetch: bool, ci_login: bool, push: bool, file_cache
         if push:
             click.secho(f"Pushing image with {tag}", fg="yellow")
             _push(tag)
-        
+
         if file_cache:
             _save(tag)
 
@@ -189,9 +205,7 @@ def build(images: List[str], fetch: bool, ci_login: bool, push: bool, file_cache
 @main.command(help="Run project containers")
 @click.argument("image", nargs=1)
 @click.argument("command", nargs=-1)
-@click.option(
-    "-p", "--publish", "publish", multiple=True, type=int, help="Port which should be published"
-)
+@click.option("-p", "--publish", "publish", multiple=True, type=int, help="Port which should be published")
 @click.option(
     "-m",
     "--mount",
@@ -217,7 +231,7 @@ def build(images: List[str], fetch: bool, ci_login: bool, push: bool, file_cache
     default=False,
     is_flag=True,
     type=bool,
-    help="Drop into interactive shell if the command fails"
+    help="Drop into interactive shell if the command fails",
 )
 def run(
     image: str,
@@ -248,6 +262,7 @@ def run(
     # register cleanup function
     def cleanup():
         _stop(cont)
+
     atexit.register(cleanup)
 
     # wait for the container to boot properly
index 5c9b00407659fbc99309e5f3a45473d7589b0d3e..f3b6184a70edd879be7c22949e35eef5d798979a 100644 (file)
 # poetry when parsing the pyproject.toml.
 
 import os
+import re
 import sys
 from distutils.version import StrictVersion
-import re
 from typing import List
 
-
 # If there is a global installation of poetry, prefer that.
 lib = os.path.expanduser("~/.poetry/lib")
 vendors = os.path.join(lib, "poetry", "_vendor")
-current_vendors = os.path.join(
-    vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2]))
-)
+current_vendors = os.path.join(vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2])))
 
 sys.path.insert(0, lib)
 sys.path.insert(0, current_vendors)
@@ -43,9 +40,7 @@ try:
         from poetry.factory import Factory
     from poetry.__version__ import __version__
 except (ImportError, ModuleNotFoundError) as ee:
-    raise ImportError(
-        f"install poetry by doing pip install poetry to use this script: {ee}"
-    )
+    raise ImportError(f"install poetry by doing pip install poetry to use this script: {ee}")
 
 
 # Generate a Poetry object that knows about the metadata in pyproject.toml
@@ -63,8 +58,8 @@ setuppy_blob: bytes = sdist_builder.build_setup()
 
 # patch the result so that it does not contain upper bounds in dependencies
 # (but it should contain them in python version)
-setuppy = setuppy_blob.decode('utf8')
-setuppy, _ = re.subn(r'(\'[^\']+>=[^<>=,\']*),<[^<>=,\']*\'', '\\1\'', setuppy)
+setuppy = setuppy_blob.decode("utf8")
+setuppy, _ = re.subn(r"(\'[^\']+>=[^<>=,\']*),<[^<>=,\']*\'", "\\1'", setuppy)
 
 # output the setup.py script to stdout
 print(setuppy)
index cef6f48a6e6aa7c13650e6eb95b9bfd54dcf3c57..0198fcb9d11dc3f8c4659c721df91d60bb3c33d8 100644 (file)
@@ -29,8 +29,8 @@ setup_kwargs = {
     'version': '0.1.0',
     'description': 'A central management tool for multiple instances of Knot Resolver',
     'long_description': None,
-    'author': 'Vašek Šraier',
-    'author_email': 'git@vakabus.cz',
+    'author': 'Václav Šraier',
+    'author_email': 'vaclav.sraier@nic.cz',
     'maintainer': None,
     'maintainer_email': None,
     'url': None,