summaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
authorAleš Mrázek <ales.mrazek@nic.cz>2024-10-18 11:13:54 +0200
committerVladimír Čunát <vladimir.cunat@nic.cz>2024-12-03 08:53:33 +0100
commit37e5ec79b718f3502d3e043657349e16feba9c62 (patch)
tree85b247625c9cda0ab34a724f732f4bbc68868d9d /python
parentpyproject.toml: 'watchdog' added as optional dependency (diff)
downloadknot-resolver-37e5ec79b718f3502d3e043657349e16feba9c62.tar.xz
knot-resolver-37e5ec79b718f3502d3e043657349e16feba9c62.zip
python/knot_resolver/manager: added files watchdog
Diffstat (limited to 'python')
-rw-r--r--python/knot_resolver/manager/files/__init__.py3
-rw-r--r--python/knot_resolver/manager/files/watchdog.py88
-rw-r--r--python/knot_resolver/manager/server.py4
3 files changed, 94 insertions, 1 deletions
diff --git a/python/knot_resolver/manager/files/__init__.py b/python/knot_resolver/manager/files/__init__.py
new file mode 100644
index 00000000..49700656
--- /dev/null
+++ b/python/knot_resolver/manager/files/__init__.py
@@ -0,0 +1,3 @@
+from .watchdog import init_files_watchdog
+
+__all__ = ["init_files_watchdog"]
diff --git a/python/knot_resolver/manager/files/watchdog.py b/python/knot_resolver/manager/files/watchdog.py
new file mode 100644
index 00000000..9cb644a6
--- /dev/null
+++ b/python/knot_resolver/manager/files/watchdog.py
@@ -0,0 +1,88 @@
+import importlib
+import logging
+from pathlib import Path
+from typing import List, Optional, Union
+
+from knot_resolver.controller.registered_workers import command_registered_workers
+from knot_resolver.datamodel import KresConfig
+from knot_resolver.datamodel.types import File
+from knot_resolver.manager.config_store import ConfigStore, only_on_real_changes_update
+from knot_resolver.utils import compat
+
+_watchdog = False
+if importlib.util.find_spec("watchdog"):
+ _watchdog = True
+
+logger = logging.getLogger(__name__)
+
+
+def files_to_watch(config: KresConfig) -> List[Path]:
+ files: List[Optional[File]] = [
+ config.network.tls.cert_file,
+ config.network.tls.key_file,
+ ]
+ return [file.to_path() for file in files if file is not None]
+
+
+if _watchdog:
+ from watchdog.events import (
+ DirModifiedEvent,
+ FileModifiedEvent,
+ FileSystemEventHandler,
+ )
+ from watchdog.observers import Observer
+
+ _files_watchdog: Optional["FilesWatchDog"] = None
+
+ class CertificatesEventHandler(FileSystemEventHandler):
+
+ def __init__(self, config: KresConfig) -> None:
+ self._config = config
+ self._command = f"net.tls('{config.network.tls.cert_file}', '{config.network.tls.key_file}')"
+
+ # def on_any_event(self, event: FileSystemEvent) -> None:
+ # pass
+
+ # def on_created(self, event: Union[DirCreatedEvent, FileCreatedEvent]) -> None:
+ # pass
+
+ # def on_deleted(self, event: Union[DirDeletedEvent, FileDeletedEvent]) -> None:
+ # pass
+
+ def on_modified(self, event: Union[DirModifiedEvent, FileModifiedEvent]) -> None:
+ if compat.asyncio.is_event_loop_running():
+ compat.asyncio.create_task(command_registered_workers(self._command))
+ else:
+ compat.asyncio.run(command_registered_workers(self._command))
+
+ # def on_closed(self, event: FileClosedEvent) -> None:
+ # pass
+
+ class FilesWatchDog:
+ def __init__(self, config: KresConfig, files: List[Path]) -> None:
+ self._observer = Observer()
+ for file in files:
+ self._observer.schedule(CertificatesEventHandler(config), str(file), recursive=False)
+ logger.info(f"Watching '{file}. file")
+
+ def start(self) -> None:
+ if self._observer:
+ self._observer.start()
+
+ def stop(self) -> None:
+ if self._observer:
+ self._observer.stop()
+ self._observer.join()
+
+ @only_on_real_changes_update(files_to_watch)
+ async def _init_files_watchdog(config: KresConfig) -> None:
+ global _files_watchdog
+ if _files_watchdog is None:
+ logger.info("Starting files WatchDog")
+ _files_watchdog = FilesWatchDog(config, files_to_watch(config))
+ _files_watchdog.start()
+
+
+async def init_files_watchdog(config_store: ConfigStore) -> None:
+ if _watchdog:
+ await config_store.register_on_change_callback(_init_files_watchdog)
diff --git a/python/knot_resolver/manager/server.py b/python/knot_resolver/manager/server.py
index 90fd4d3b..fbfef244 100644
--- a/python/knot_resolver/manager/server.py
+++ b/python/knot_resolver/manager/server.py
@@ -27,7 +27,7 @@ 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
from knot_resolver.datamodel.management_schema import ManagementSchema
-from knot_resolver.manager import metrics
+from knot_resolver.manager import files, metrics
from knot_resolver.utils import custom_atexit as atexit
from knot_resolver.utils import ignore_exceptions_optional
from knot_resolver.utils.async_utils import readfile
@@ -566,6 +566,8 @@ async def start_server(config: Path = CONFIG_FILE) -> int: # noqa: PLR0915
# started, therefore before initializing manager
await metrics.init_prometheus(config_store)
+ await files.init_files_watchdog(config_store)
+
# prepare instance of the server (no side effects)
server = Server(config_store, config)