diff --git a/repeater/service_utils.py b/repeater/service_utils.py index 9a9c4a1..f565de9 100644 --- a/repeater/service_utils.py +++ b/repeater/service_utils.py @@ -6,11 +6,14 @@ Provides functions for service control operations like restart. import logging import os import subprocess +import threading +import time from typing import Dict, Optional, Tuple logger = logging.getLogger("ServiceUtils") INIT_SCRIPT = "/etc/init.d/S80pymc-repeater" BUILDROOT_METADATA_PATH = "/etc/pymc-image-build-id" +_CONTAINER_RESTART_DELAY_SECONDS = 1.0 def is_buildroot() -> bool: @@ -46,6 +49,40 @@ def get_buildroot_image_version() -> Optional[str]: return get_buildroot_image_info().get("image_version") +def is_container() -> bool: + """Detect common Docker/LXC/containerized environments.""" + if os.path.exists("/.dockerenv") or os.environ.get("container"): + return True + + try: + with open("/proc/1/environ", "rb") as handle: + if b"container=" in handle.read(): + return True + except (OSError, PermissionError): + pass + + try: + with open("/proc/1/cgroup", "r", encoding="utf-8") as handle: + cgroup_data = handle.read() + if any(token in cgroup_data for token in ("docker", "containerd", "kubepods", "lxc")): + return True + except OSError: + pass + + return os.path.exists("/run/host/container-manager") + + +def _schedule_container_exit(delay_seconds: float = _CONTAINER_RESTART_DELAY_SECONDS) -> None: + """Exit the current process shortly after returning success to the caller.""" + + def _exit_process() -> None: + time.sleep(delay_seconds) + logger.warning("Exiting repeater process to trigger container restart") + os._exit(0) + + threading.Thread(target=_exit_process, name="container-restart-exit", daemon=True).start() + + def restart_service() -> Tuple[bool, str]: """ Restart the pymc-repeater service. @@ -58,6 +95,11 @@ def restart_service() -> Tuple[bool, str]: Returns: Tuple[bool, str]: (success, message) """ + if is_container(): + _schedule_container_exit() + logger.info("Container environment detected; scheduled process exit for container restart") + return True, "Container restart initiated" + if is_buildroot(): if not os.path.exists(INIT_SCRIPT): logger.error("Buildroot init script not found: %s", INIT_SCRIPT)