Merge pull request #254 from yellowcooln/dev

docker: improve container restart handling, publishing, and config mounting
This commit is contained in:
Lloyd
2026-05-18 21:10:34 +01:00
committed by GitHub
4 changed files with 76 additions and 4 deletions
+16 -1
View File
@@ -52,11 +52,26 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Determine image repository
id: image_repo
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.image_repository }}" ]; then
image_repository="${{ inputs.image_repository }}"
elif [ "${{ github.repository }}" = "yellowcooln/pyMC_Repeater" ]; then
image_repository="yellowcooln/pymc-repeater"
else
image_repository="pymcdev/pymc-repeater"
fi
echo "Using image repository: ${image_repository}"
echo "image_repository=${image_repository}" >> "$GITHUB_OUTPUT"
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ github.event_name == 'workflow_dispatch' && inputs.image_repository || 'pymcdev/pymc-repeater' }}
images: ${{ steps.image_repo.outputs.image_repository }}
tags: |
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/dev' }}
+1 -1
View File
@@ -22,5 +22,5 @@ services:
group_add:
- plugdev
volumes:
- ./config.yaml:/etc/pymc_repeater/config.yaml
- ./config:/etc/pymc_repeater
- ./data:/var/lib/pymc_repeater
+51
View File
@@ -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,49 @@ 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 get_container_restart_message() -> str:
"""Return the user-facing restart message for containerized installs."""
return (
"Container restart initiated. "
"If you are running pyMC Repeater via Docker or Home Assistant, pull or rebuild "
"a newer image for packaged image updates to take effect."
)
def restart_service() -> Tuple[bool, str]:
"""
Restart the pymc-repeater service.
@@ -58,6 +104,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, get_container_restart_message()
if is_buildroot():
if not os.path.exists(INIT_SCRIPT):
logger.error("Buildroot init script not found: %s", INIT_SCRIPT)
+8 -2
View File
@@ -29,7 +29,7 @@ from datetime import datetime
from typing import List, Optional
import cherrypy
from repeater.service_utils import is_buildroot
from repeater.service_utils import get_container_restart_message, is_buildroot, is_container
logger = logging.getLogger("HTTPServer")
@@ -891,7 +891,13 @@ def _do_install() -> None:
restart_msg = str(exc)
logger.warning(f"[Update] Could not restart service: {exc}")
if restart_ok:
_state.finish_install(True, f"Upgraded to latest on channel '{channel}' service restarted")
if is_container():
_state.finish_install(
True,
f"Upgraded to latest on channel '{channel}' {get_container_restart_message()}",
)
else:
_state.finish_install(True, f"Upgraded to latest on channel '{channel}' service restarted")
else:
_state.finish_install(False, f"Upgrade succeeded but service restart failed: {restart_msg}")
else: