mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-08-06 17:03:32 +02:00
Merge pull request #254 from yellowcooln/dev
docker: improve container restart handling, publishing, and config mounting
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user