diff --git a/bin/piggyback_hub b/bin/piggyback_hub index 02d1cd57b86..0962f21946c 100755 --- a/bin/piggyback_hub +++ b/bin/piggyback_hub @@ -4,8 +4,37 @@ # conditions defined in the file COPYING, which is part of this source code package. import sys +import traceback +from typing import Literal + +import cmk.ccc.version as cmk_version +from cmk.ccc import crash_reporting + +import cmk.utils.paths from cmk.piggyback_hub.main import main +CrashReportStore = crash_reporting.CrashReportStore + + +@crash_reporting.crash_report_registry.register +class PiggybackHubCrashReport(crash_reporting.ABCCrashReport): + @classmethod + def type(cls) -> Literal["piggyback_hub"]: + return "piggyback_hub" + + +def create_crash_report_callback() -> str: + try: + crash = PiggybackHubCrashReport.from_exception( + cmk.utils.paths.crash_dir, + cmk_version.get_general_version_infos(cmk.utils.paths.omd_root), + ) + CrashReportStore().save(crash) + return f"Please submit a crash report! (Crash-ID: {crash.ident_to_text()})" + except Exception: + return f"Failed to create a crash report: {traceback.format_exc()}" + + if __name__ == "__main__": - sys.exit(main()) + sys.exit(main(crash_report_callback=create_crash_report_callback)) diff --git a/cmk/piggyback_hub/main.py b/cmk/piggyback_hub/main.py index 269cfffcb74..58a428b5713 100644 --- a/cmk/piggyback_hub/main.py +++ b/cmk/piggyback_hub/main.py @@ -7,6 +7,7 @@ import logging import signal import sys +from collections.abc import Callable from dataclasses import dataclass from itertools import cycle from logging import getLogger @@ -89,7 +90,9 @@ def _setup_logging(args: Arguments) -> logging.Logger: return logger -def run_piggyback_hub(logger: logging.Logger, omd_root: Path) -> int: +def run_piggyback_hub( + logger: logging.Logger, omd_root: Path, crash_report_callback: Callable[[], str] +) -> int: reload_config = make_event() processes = ( ReceivingProcess( @@ -97,15 +100,17 @@ def run_piggyback_hub(logger: logging.Logger, omd_root: Path) -> int: omd_root, PiggybackPayload, save_payload_on_message(logger, omd_root), + crash_report_callback, QueueName("payload"), message_ttl=600, ), - SendingPayloadProcess(logger, omd_root, reload_config), + SendingPayloadProcess(logger, omd_root, reload_config, crash_report_callback), ReceivingProcess( logger, omd_root, PiggybackHubConfig, save_config_on_message(logger, omd_root, reload_config), + crash_report_callback, CONFIG_QUEUE, message_ttl=None, ), @@ -134,10 +139,17 @@ def terminate_all_processes(reason: str) -> int: raise RuntimeError("Unreachable code reached") -def main(argv: list[str] | None = None) -> int: +def main(crash_report_callback: Callable[[], str], argv: list[str] | None = None) -> int: if argv is None: argv = sys.argv + if crash_report_callback is None: + + def dummy_crash_report(): + return "No crash report created" + + crash_report_callback = dummy_crash_report + args = _parse_arguments(argv) logger = _setup_logging(args) omd_root = Path(args.omd_root) @@ -150,9 +162,11 @@ def main(argv: list[str] | None = None) -> int: try: with pid_file_lock(Path(args.pid_file)): - return run_piggyback_hub(logger, omd_root) + return run_piggyback_hub(logger, omd_root, crash_report_callback) except Exception as exc: if args.debug: raise logger.exception("Exception: %s: %s", APP_NAME.value, exc) + crash_report_msg = crash_report_callback() + logger.error(crash_report_msg) return 1 diff --git a/cmk/piggyback_hub/payload.py b/cmk/piggyback_hub/payload.py index 5f1c9c1da43..29d8114c725 100644 --- a/cmk/piggyback_hub/payload.py +++ b/cmk/piggyback_hub/payload.py @@ -70,13 +70,20 @@ def _on_message( class SendingPayloadProcess(multiprocessing.Process): - def __init__(self, logger: logging.Logger, omd_root: Path, reload_config: Event) -> None: + def __init__( + self, + logger: logging.Logger, + omd_root: Path, + reload_config: Event, + crash_report_callback: Callable[[], str], + ) -> None: super().__init__() self.logger = logger self.omd_root = omd_root self.site = omd_root.name self.paths = create_paths(omd_root) self.reload_config = reload_config + self.crash_report_callback = crash_report_callback self.task_name = "publishing on queue 'payload'" def run(self): @@ -102,6 +109,9 @@ def run(self): self.logger.error("Connection error: %s: %s", self.task_name, exc) except Exception as exc: self.logger.exception("Exception: %s: %s", self.task_name, exc) + crash_report_msg = self.crash_report_callback() + self.logger.error(crash_report_msg) + raise def _handle_message( self, diff --git a/cmk/piggyback_hub/utils.py b/cmk/piggyback_hub/utils.py index 0f01cf17a90..2e1e252005a 100644 --- a/cmk/piggyback_hub/utils.py +++ b/cmk/piggyback_hub/utils.py @@ -37,6 +37,7 @@ def __init__( omd_root: Path, model: type[_ModelT], callback: Callable[[Channel[_ModelT], DeliveryTag, _ModelT], None], + crash_report_callback: Callable[[], str], queue: QueueName, message_ttl: int | None, ) -> None: @@ -45,6 +46,7 @@ def __init__( self.omd_root = omd_root self.model = model self.callback = callback + self.crash_report_callback = crash_report_callback self.queue = queue self.message_ttl = message_ttl self.task_name = f"receiving on queue '{self.queue.value}'" @@ -72,6 +74,9 @@ def run(self) -> None: self.logger.error("Reconnecting failed: %s: %s", self.task_name, exc) except Exception as exc: self.logger.exception("Exception: %s: %s", self.task_name, exc) + crash_report_msg = self.crash_report_callback() + self.logger.error(crash_report_msg) + raise def make_connection(omd_root: Path, logger: logging.Logger, task_name: str) -> Connection: