From: Vasek Sraier Date: Tue, 11 Jan 2022 12:03:57 +0000 (+0100) Subject: manager: fixed error handling in SIGHUP handler X-Git-Tag: v6.0.0a1~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8eaff9f1f68b2627d69d4f145a940f6709f96304;p=thirdparty%2Fknot-resolver.git manager: fixed error handling in SIGHUP handler --- diff --git a/manager/knot_resolver_manager/config_store.py b/manager/knot_resolver_manager/config_store.py index 6b68db6be..cfc505d82 100644 --- a/manager/knot_resolver_manager/config_store.py +++ b/manager/knot_resolver_manager/config_store.py @@ -3,7 +3,7 @@ from asyncio import Lock from typing import Any, Awaitable, Callable, List, Tuple from knot_resolver_manager.datamodel import KresConfig -from knot_resolver_manager.exceptions import DataException, KresdManagerException +from knot_resolver_manager.exceptions import DataException, KresManagerException from knot_resolver_manager.utils.functional import Result VerifyCallback = Callable[[KresConfig, KresConfig], Awaitable[Result[None, str]]] @@ -25,7 +25,7 @@ class ConfigStore: err_res = filter(lambda r: r.is_err(), results) errs = list(map(lambda r: r.unwrap_err(), err_res)) if len(errs) > 0: - raise KresdManagerException("Validation of the new config failed. The reasons are:", *errs) + raise KresManagerException("Validation of the new config failed. The reasons are:", *errs) async with self._update_lock: # update the stored config with the new version diff --git a/manager/knot_resolver_manager/exceptions.py b/manager/knot_resolver_manager/exceptions.py index ed7de7804..a57d70c52 100644 --- a/manager/knot_resolver_manager/exceptions.py +++ b/manager/knot_resolver_manager/exceptions.py @@ -1,14 +1,14 @@ -class KresdManagerException(Exception): +class KresManagerException(Exception): """ Base class for all custom exceptions we use in our code """ -class SubprocessControllerException(KresdManagerException): +class SubprocessControllerException(KresManagerException): pass -class TreeException(KresdManagerException): +class TreeException(KresManagerException): def __init__(self, msg: str, tree_path: str) -> None: super().__init__(msg) self._tree_path = tree_path @@ -24,9 +24,9 @@ class SchemaException(TreeException): pass -class DataException(KresdManagerException): +class DataException(KresManagerException): pass -class ParsingException(KresdManagerException): +class ParsingException(KresManagerException): pass diff --git a/manager/knot_resolver_manager/server.py b/manager/knot_resolver_manager/server.py index da478da5c..05f185bd4 100644 --- a/manager/knot_resolver_manager/server.py +++ b/manager/knot_resolver_manager/server.py @@ -20,7 +20,7 @@ from knot_resolver_manager.config_store import ConfigStore from knot_resolver_manager.constants import DEFAULT_MANAGER_CONFIG_FILE from knot_resolver_manager.datamodel.config_schema import KresConfig from knot_resolver_manager.datamodel.types import Listen, ListenType -from knot_resolver_manager.exceptions import DataException, KresdManagerException, TreeException +from knot_resolver_manager.exceptions import DataException, KresManagerException, SchemaException, TreeException 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 @@ -44,7 +44,7 @@ async def error_handler(request: web.Request, handler: Any): try: return await handler(request) - except KresdManagerException as e: + except KresManagerException as e: if isinstance(e, TreeException): return web.Response( text=f"Configuration validation failed @ '{e.where()}': {e}", status=HTTPStatus.BAD_REQUEST @@ -98,13 +98,23 @@ class Server: if self._config_path is None: logger.warning("The manager was started with inlined configuration - can't reload") else: - data = await readfile(self._config_path) - config = KresConfig(parse_yaml(data)) - try: + data = await readfile(self._config_path) + config = KresConfig(parse_yaml(data)) await self.config_store.update(config) - except KresdManagerException as e: - logger.error(f"Reloading of the configuration file failed. {e}") + logger.info("Configuration file successfully reloaded") + except FileNotFoundError: + logger.error( + f"Configuration file was not found at '{self._config_path}'." + " Something must have happened to it while we were running." + ) + logger.error("Configuration have NOT been changed.") + except SchemaException as e: + logger.error(f"Failed to parse the updated configuration file: {e}") + logger.error("Configuration have NOT been changed.") + except KresManagerException as e: + logger.error(f"Reloading of the configuration file failed: {e}") + logger.error("Configuration have NOT been changed.") async def start(self): self._setup_routes() @@ -216,7 +226,7 @@ class Server: nsite = web.TCPSite(self.runner, str(mgn.listen.ip), mgn.listen.port) logger.info(f"Starting API HTTP server on http://{mgn.listen.ip}:{mgn.listen.port}") else: - raise KresdManagerException(f"Requested API on unsupported configuration format {mgn.listen.typ}") + raise KresManagerException(f"Requested API on unsupported configuration format {mgn.listen.typ}") await nsite.start() # stop the old listen @@ -242,7 +252,7 @@ async def _load_raw_config(config: Union[Path, ParsedTree]) -> ParsedTree: # Initial configuration of the manager if isinstance(config, Path): if not config.exists(): - raise KresdManagerException( + raise KresManagerException( f"Manager is configured to load config file at {config} on startup, but the file does not exist." ) else: @@ -293,7 +303,7 @@ def _set_working_directory(config_raw: ParsedTree): config = KresConfig(config_raw) if not config.server.rundir.to_path().exists(): - raise KresdManagerException(f"`rundir` directory ({config.server.rundir}) does not exist!") + raise KresManagerException(f"`rundir` directory ({config.server.rundir}) does not exist!") os.chdir(config.server.rundir.to_path()) @@ -337,7 +347,7 @@ async def start_server(config: Union[Path, ParsedTree] = DEFAULT_MANAGER_CONFIG_ # After we have loaded the configuration, we can start worring about subprocess management. manager = await _init_manager(config_store) - except KresdManagerException as e: + except KresManagerException as e: logger.error(e) sys.exit(1) except BaseException: diff --git a/manager/knot_resolver_manager/utils/async_utils.py b/manager/knot_resolver_manager/utils/async_utils.py index 67d1490aa..23b6f3608 100644 --- a/manager/knot_resolver_manager/utils/async_utils.py +++ b/manager/knot_resolver_manager/utils/async_utils.py @@ -5,7 +5,7 @@ import time from asyncio import create_subprocess_exec, create_subprocess_shell from pathlib import PurePath from threading import Thread -from typing import Generic, List, Optional, TypeVar, Union +from typing import Any, Dict, Generic, List, Optional, TypeVar, Union from knot_resolver_manager.compat.asyncio import to_thread @@ -16,7 +16,7 @@ async def call( """ custom async alternative to subprocess.call() """ - kwargs = {} + kwargs: Dict[str, Any] = {} if discard_output: kwargs["stdout"] = asyncio.subprocess.DEVNULL kwargs["stderr"] = asyncio.subprocess.DEVNULL