From: Aleš Mrázek Date: Thu, 29 Aug 2024 11:30:27 +0000 (+0200) Subject: python/knot_resolver: KresBaseException added X-Git-Tag: v6.0.9~18^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fc3bc8201b1ed1c274f96ecb986226c7d0cfcc7;p=thirdparty%2Fknot-resolver.git python/knot_resolver: KresBaseException added --- diff --git a/python/knot_resolver/__init__.py b/python/knot_resolver/__init__.py index 8407cd6d5..4529ec683 100644 --- a/python/knot_resolver/__init__.py +++ b/python/knot_resolver/__init__.py @@ -1,6 +1,6 @@ -from .datamodel import KresConfig +from .exceptions import KresBaseException from .constants import VERSION __version__ = VERSION -__all__ = ["KresConfig"] +__all__ = ["KresBaseException"] diff --git a/python/knot_resolver/controller/exceptions.py b/python/knot_resolver/controller/exceptions.py new file mode 100644 index 000000000..149c29891 --- /dev/null +++ b/python/knot_resolver/controller/exceptions.py @@ -0,0 +1,19 @@ +from typing import List + +from knot_resolver import KresBaseException + + +class SubprocessControllerException(KresBaseException): + pass + + +class SubprocessControllerExecException(Exception): + """ + Exception that is used to deliberately terminate system startup + and make exec() of something else. This is used by the subprocess controller + as supervisord to run as the top-level process in a process tree hierarchy. + """ + + def __init__(self, exec_args: List[str], *args: object) -> None: + self.exec_args = exec_args + super().__init__(*args) diff --git a/python/knot_resolver/controller/interface.py b/python/knot_resolver/controller/interface.py index 02bbaa500..ba9ac28d3 100644 --- a/python/knot_resolver/controller/interface.py +++ b/python/knot_resolver/controller/interface.py @@ -12,7 +12,7 @@ from weakref import WeakValueDictionary from knot_resolver.manager.constants import kresd_config_file, policy_loader_config_file from knot_resolver.datamodel.config_schema import KresConfig -from knot_resolver.manager.exceptions import SubprocessControllerException +from knot_resolver.controller.exceptions import SubprocessControllerException from knot_resolver.controller.registered_workers import register_worker, unregister_worker from knot_resolver.utils.async_utils import writefile diff --git a/python/knot_resolver/controller/registered_workers.py b/python/knot_resolver/controller/registered_workers.py index 2d3176c37..eed1adedb 100644 --- a/python/knot_resolver/controller/registered_workers.py +++ b/python/knot_resolver/controller/registered_workers.py @@ -2,7 +2,7 @@ import asyncio import logging from typing import TYPE_CHECKING, Dict, List, Tuple -from knot_resolver.manager.exceptions import SubprocessControllerException +from .exceptions import SubprocessControllerException if TYPE_CHECKING: from knot_resolver.controller.interface import KresID, Subprocess diff --git a/python/knot_resolver/controller/supervisord/__init__.py b/python/knot_resolver/controller/supervisord/__init__.py index 592b76be2..b9f3cae20 100644 --- a/python/knot_resolver/controller/supervisord/__init__.py +++ b/python/knot_resolver/controller/supervisord/__init__.py @@ -9,7 +9,7 @@ import supervisor.xmlrpc # type: ignore[import] from knot_resolver.compat.asyncio import async_in_a_thread from knot_resolver.manager.constants import supervisord_config_file, supervisord_pid_file, supervisord_sock_file from knot_resolver.datamodel.config_schema import KresConfig -from knot_resolver.manager.exceptions import CancelStartupExecInsteadException, SubprocessControllerException +from knot_resolver.controller.exceptions import SubprocessControllerExecException, SubprocessControllerException from knot_resolver.controller.interface import ( KresID, Subprocess, @@ -37,7 +37,7 @@ async def _exec_supervisord(config: KresConfig) -> NoReturn: logger.debug("Writing supervisord config") await write_config_file(config) logger.debug("Execing supervisord") - raise CancelStartupExecInsteadException( + raise SubprocessControllerExecException( [ str(which.which("supervisord")), "supervisord", diff --git a/python/knot_resolver/exceptions.py b/python/knot_resolver/exceptions.py new file mode 100644 index 000000000..3e90b0bcc --- /dev/null +++ b/python/knot_resolver/exceptions.py @@ -0,0 +1,4 @@ +class KresBaseException(Exception): + """ + Base class for all custom exceptions we use in Knot Resolver. + """ diff --git a/python/knot_resolver/manager/config_store.py b/python/knot_resolver/manager/config_store.py index 1c0174f23..d783f7384 100644 --- a/python/knot_resolver/manager/config_store.py +++ b/python/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.datamodel import KresConfig -from knot_resolver.manager.exceptions import KresManagerException +from knot_resolver import KresBaseException from knot_resolver.utils.functional import Result from knot_resolver.utils.modeling.exceptions import DataParsingError from knot_resolver.utils.modeling.types import NoneType @@ -27,7 +27,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 KresManagerException("Configuration validation failed. The reasons are:\n - " + "\n - ".join(errs)) + raise KresBaseException("Configuration validation failed. The reasons are:\n - " + "\n - ".join(errs)) async with self._update_lock: # update the stored config with the new version diff --git a/python/knot_resolver/manager/exceptions.py b/python/knot_resolver/manager/exceptions.py deleted file mode 100644 index 5b05d98eb..000000000 --- a/python/knot_resolver/manager/exceptions.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List - - -class CancelStartupExecInsteadException(Exception): - """ - Exception used for terminating system startup and instead - causing an exec of something else. Could be used by subprocess - controllers such as supervisord to allow them to run as top-level - process in a process tree. - """ - - def __init__(self, exec_args: List[str], *args: object) -> None: - self.exec_args = exec_args - super().__init__(*args) - - -class KresManagerException(Exception): - """ - Base class for all custom exceptions we use in our code - """ - - -class SubprocessControllerException(KresManagerException): - pass - - -class SubprocessControllerTimeoutException(KresManagerException): - pass diff --git a/python/knot_resolver/manager/kres_manager.py b/python/knot_resolver/manager/kres_manager.py index 606f5b243..913d87241 100644 --- a/python/knot_resolver/manager/kres_manager.py +++ b/python/knot_resolver/manager/kres_manager.py @@ -17,7 +17,7 @@ from knot_resolver.constants import ( FIX_COUNTER_DECREASE_INTERVAL_SEC, WATCHDOG_INTERVAL_SEC, ) -from knot_resolver.manager.exceptions import SubprocessControllerException +from knot_resolver.controller.exceptions import SubprocessControllerException from knot_resolver.controller.interface import ( Subprocess, SubprocessController, @@ -31,7 +31,7 @@ from knot_resolver.controller.registered_workers import ( from knot_resolver.utils.functional import Result from knot_resolver.utils.modeling.types import NoneType -from knot_resolver import KresConfig +from knot_resolver.datamodel import KresConfig logger = logging.getLogger(__name__) diff --git a/python/knot_resolver/manager/server.py b/python/knot_resolver/manager/server.py index a25b5eb2a..d95bcf7d5 100644 --- a/python/knot_resolver/manager/server.py +++ b/python/knot_resolver/manager/server.py @@ -19,6 +19,7 @@ from aiohttp.web_runner import AppRunner, TCPSite, UnixSite from typing_extensions import Literal import knot_resolver.utils.custom_atexit as atexit +from knot_resolver import KresBaseException from knot_resolver.constants import CONFIG_FILE_PATH_DEFAULT, PID_FILE_NAME from knot_resolver.manager import log, statistics from knot_resolver.compat import asyncio as asyncio_compat @@ -28,8 +29,8 @@ 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.exceptions import CancelStartupExecInsteadException, KresManagerException from knot_resolver.controller import get_best_controller_implementation +from knot_resolver.controller.exceptions import SubprocessControllerExecException from knot_resolver.controller.registered_workers import command_single_registered_worker from knot_resolver.utils import ignore_exceptions_optional from knot_resolver.utils.async_utils import readfile @@ -65,7 +66,7 @@ async def error_handler(request: web.Request, handler: Any) -> web.Response: return web.Response(text=f"validation of configuration failed:\n{e}", status=HTTPStatus.BAD_REQUEST) except DataParsingError as e: return web.Response(text=f"request processing error:\n{e}", status=HTTPStatus.BAD_REQUEST) - except KresManagerException as e: + except KresBaseException as e: return web.Response(text=f"request processing failed:\n{e}", status=HTTPStatus.INTERNAL_SERVER_ERROR) @@ -133,7 +134,7 @@ class Server: except (DataParsingError, DataValidationError) as e: logger.error(f"Failed to parse the updated configuration file: {e}") logger.error("Configuration have NOT been changed.") - except KresManagerException as e: + except KresBaseException as e: logger.error(f"Reloading of the configuration file failed: {e}") logger.error("Configuration have NOT been changed.") @@ -368,7 +369,7 @@ class Server: nsite = web.TCPSite(self.runner, str(mgn.interface.addr), int(mgn.interface.port)) logger.info(f"Starting API HTTP server on http://{mgn.interface.addr}:{mgn.interface.port}") else: - raise KresManagerException("Requested API on unsupported configuration format.") + raise KresBaseException("Requested API on unsupported configuration format.") await nsite.start() # stop the old listen @@ -399,7 +400,7 @@ async def _load_raw_config(config: Union[Path, Dict[str, Any]]) -> Dict[str, Any # Initial configuration of the manager if isinstance(config, Path): if not config.exists(): - raise KresManagerException( + raise KresBaseException( f"Manager is configured to load config file at {config} on startup, but the file does not exist." ) else: @@ -471,12 +472,12 @@ def _lock_working_directory(attempt: int = 0) -> None: os.unlink(PID_FILE_NAME) _lock_working_directory(attempt=attempt + 1) return - raise KresManagerException( + raise KresBaseException( "Another manager is running in the same working directory." f" PID file is located at {os.getcwd()}/{PID_FILE_NAME}" ) from e else: - raise KresManagerException( + raise KresBaseException( "Another manager is running in the same working directory." f" PID file is located at {os.getcwd()}/{PID_FILE_NAME}" ) from e @@ -566,7 +567,7 @@ async def start_server(config: Path = CONFIG_FILE_PATH_DEFAULT) -> int: # After we have loaded the configuration, we can start worring about subprocess management. manager = await _init_manager(config_store, server) - except CancelStartupExecInsteadException as e: + except SubprocessControllerExecException as e: # if we caught this exception, some component wants to perform a reexec during startup. Most likely, it would # be a subprocess manager like supervisord, which wants to make sure the manager runs under supervisord in # the process tree. So now we stop everything, and exec what we are told to. We are assuming, that the thing @@ -582,7 +583,7 @@ async def start_server(config: Path = CONFIG_FILE_PATH_DEFAULT) -> int: # and finally exec what we were told to exec os.execl(*e.exec_args) - except KresManagerException as e: + except KresBaseException as e: # We caught an error with a pretty error message. Just print it and exit. logger.error(e) return 1 diff --git a/python/knot_resolver/utils/modeling/exceptions.py b/python/knot_resolver/utils/modeling/exceptions.py index ea0573397..478f54884 100644 --- a/python/knot_resolver/utils/modeling/exceptions.py +++ b/python/knot_resolver/utils/modeling/exceptions.py @@ -1,9 +1,9 @@ from typing import Iterable, List -from knot_resolver.manager.exceptions import KresManagerException +from knot_resolver import KresBaseException -class DataModelingBaseException(KresManagerException): +class DataModelingBaseException(KresBaseException): """ Base class for all exceptions used in modelling. """ diff --git a/tests/manager/datamodel/types/test_base_types.py b/tests/manager/datamodel/types/test_base_types.py index c74fe945e..cf6248361 100644 --- a/tests/manager/datamodel/types/test_base_types.py +++ b/tests/manager/datamodel/types/test_base_types.py @@ -6,7 +6,7 @@ import pytest from pytest import raises from knot_resolver.datamodel.types.base_types import IntRangeBase, StringLengthBase -from knot_resolver.manager.exceptions import KresManagerException +from knot_resolver import KresBaseException @pytest.mark.parametrize("min,max", [(0, None), (None, 0), (1, 65535), (-65535, -1)]) @@ -34,7 +34,7 @@ def test_int_range_base(min: Optional[int], max: Optional[int]): invals.extend([random.randint(-sys.maxsize - 1, rmin - 1) for _ in range(n % 2)] if max else []) for inval in invals: - with raises(KresManagerException): + with raises(KresBaseException): Test(inval) @@ -62,5 +62,5 @@ def test_str_bytes_length_base(min: Optional[int], max: Optional[int]): invals.extend(["x" * random.randint(1, rmin - 1) for _ in range(n % 2)] if max else []) for inval in invals: - with raises(KresManagerException): + with raises(KresBaseException): Test(inval)