feat (helper): daemon-reload via helper; verwijder D-Bus afhankelijkheid
- podman-helper: voeg daemon-reload toe aan ALLOWED_ACTIONS; actions in NO_UNIT_ACTIONS slaan unit-validatie over en bouwen cmd zonder unit argument - app_system: /daemon-reload endpoint gebruikt nu _helper_call in plaats van directe subprocess; verwijder subprocess import - app_system: health check legt systemd_reachable af van helper_ok in plaats van systemctl --user list-units — de helper draait als host-user en impliceert systemd bereikbaarheid - CLAUDE.md: verwijder DBUS_SESSION_BUS_ADDRESS env var; D-Bus mount is niet meer nodig Deploy: kopieer podman-helper.py naar host, daemon-reload, restart helper, rebuild backend image, herstart container zonder bus mount. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -42,7 +42,6 @@ podman pod create --name mvp-pod -p 8080:8000 -p 8081:8081 --userns=keep-id
|
|||||||
podman run -d --pod mvp-pod --name mvp-backend \
|
podman run -d --pod mvp-pod --name mvp-backend \
|
||||||
--ipc=host --pid=host \
|
--ipc=host --pid=host \
|
||||||
-e XDG_RUNTIME_DIR=/run/user/1000 \
|
-e XDG_RUNTIME_DIR=/run/user/1000 \
|
||||||
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
|
||||||
-v /run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock:rw \
|
-v /run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock:rw \
|
||||||
-v /run/user/1000/podman-mvp:/run/podman-mvp \
|
-v /run/user/1000/podman-mvp:/run/podman-mvp \
|
||||||
-v /home/kodi/.config/containers:/app/workloads:rw \
|
-v /home/kodi/.config/containers:/app/workloads:rw \
|
||||||
|
|||||||
+6
-16
@@ -1,6 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from common import (
|
from common import (
|
||||||
@@ -29,19 +28,6 @@ def init_system_router(session, podman_api_base: str, workloads_dir: str) -> API
|
|||||||
except Exception:
|
except Exception:
|
||||||
podman_ok = False
|
podman_ok = False
|
||||||
|
|
||||||
systemd_reachable = False
|
|
||||||
try:
|
|
||||||
res = subprocess.run(
|
|
||||||
["systemctl", "--user", "list-units", "--no-pager", "--no-legend"],
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
check=False,
|
|
||||||
timeout=2,
|
|
||||||
)
|
|
||||||
systemd_reachable = (res.returncode == 0)
|
|
||||||
except Exception:
|
|
||||||
systemd_reachable = False
|
|
||||||
|
|
||||||
helper_ok = False
|
helper_ok = False
|
||||||
try:
|
try:
|
||||||
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
|
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
|
||||||
@@ -51,7 +37,11 @@ def init_system_router(session, podman_api_base: str, workloads_dir: str) -> API
|
|||||||
except Exception:
|
except Exception:
|
||||||
helper_ok = False
|
helper_ok = False
|
||||||
|
|
||||||
ok = podman_ok and systemd_reachable
|
# Helper draait op de host als de kodi-user en voert systemctl --user uit.
|
||||||
|
# Als de helper bereikbaar is, is systemd ook bereikbaar.
|
||||||
|
systemd_reachable = helper_ok
|
||||||
|
|
||||||
|
ok = podman_ok and helper_ok
|
||||||
return {
|
return {
|
||||||
"ok": ok,
|
"ok": ok,
|
||||||
"podman": {"ok": podman_ok},
|
"podman": {"ok": podman_ok},
|
||||||
@@ -92,7 +82,7 @@ def init_system_router(session, podman_api_base: str, workloads_dir: str) -> API
|
|||||||
@router.post("/daemon-reload")
|
@router.post("/daemon-reload")
|
||||||
def api_daemon_reload():
|
def api_daemon_reload():
|
||||||
try:
|
try:
|
||||||
code, out = _systemctl(["systemctl", "--user", "daemon-reload"])
|
code, out = _helper_call("daemon-reload", "")
|
||||||
return {
|
return {
|
||||||
"cmd": "systemctl --user daemon-reload",
|
"cmd": "systemctl --user daemon-reload",
|
||||||
"exit": code,
|
"exit": code,
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ Unix socket helper die op de HOST draait als de gewone gebruiker.
|
|||||||
Ontvangt JSON verzoeken van de API container en voert systemctl --user uit.
|
Ontvangt JSON verzoeken van de API container en voert systemctl --user uit.
|
||||||
|
|
||||||
Beveiligingsmodel:
|
Beveiligingsmodel:
|
||||||
- Alleen start / stop / restart toegestaan
|
- Alleen start / stop / restart / daemon-reload toegestaan
|
||||||
- Alleen .service units
|
- start/stop/restart: alleen .service units met veilige tekens
|
||||||
- Unit naam mag alleen letters, cijfers, punt, koppelteken en underscore bevatten
|
- daemon-reload: geen unit naam, wordt genegeerd
|
||||||
- Meerdere gelijktijdige verbindingen worden afgehandeld via asyncio
|
- Meerdere gelijktijdige verbindingen worden afgehandeld via asyncio
|
||||||
|
|
||||||
Protocol:
|
Protocol:
|
||||||
Inkomend: {"action": "start"|"stop"|"restart", "unit": "naam.service"}
|
Inkomend: {"action": "start"|"stop"|"restart", "unit": "naam.service"}
|
||||||
|
{"action": "daemon-reload", "unit": ""}
|
||||||
Uitkomend: {"ok": true, "output": "..."} of {"ok": false, "error": "..."}
|
Uitkomend: {"ok": true, "output": "..."} of {"ok": false, "error": "..."}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -42,21 +43,25 @@ logging.basicConfig(
|
|||||||
log = logging.getLogger("podman-helper")
|
log = logging.getLogger("podman-helper")
|
||||||
|
|
||||||
# ── Whitelist ─────────────────────────────────────────────────────────────────
|
# ── Whitelist ─────────────────────────────────────────────────────────────────
|
||||||
ALLOWED_ACTIONS = {"start", "stop", "restart"}
|
ALLOWED_ACTIONS = {"start", "stop", "restart", "daemon-reload"}
|
||||||
UNIT_PATTERN = re.compile(r'^[a-zA-Z0-9._\-]+\.service$')
|
UNIT_PATTERN = re.compile(r'^[a-zA-Z0-9._\-]+\.service$')
|
||||||
|
NO_UNIT_ACTIONS = {"daemon-reload"}
|
||||||
|
|
||||||
|
|
||||||
def validate(action: str, unit: str) -> str | None:
|
def validate(action: str, unit: str) -> str | None:
|
||||||
"""Geeft een foutmelding terug als het verzoek niet toegestaan is, anders None."""
|
"""Geeft een foutmelding terug als het verzoek niet toegestaan is, anders None."""
|
||||||
if action not in ALLOWED_ACTIONS:
|
if action not in ALLOWED_ACTIONS:
|
||||||
return f"Actie '{action}' niet toegestaan. Gebruik: {', '.join(sorted(ALLOWED_ACTIONS))}"
|
return f"Actie '{action}' niet toegestaan. Gebruik: {', '.join(sorted(ALLOWED_ACTIONS))}"
|
||||||
if not UNIT_PATTERN.match(unit):
|
if action not in NO_UNIT_ACTIONS and not UNIT_PATTERN.match(unit):
|
||||||
return f"Ongeldige unit naam '{unit}'. Alleen .service units met veilige tekens."
|
return f"Ongeldige unit naam '{unit}'. Alleen .service units met veilige tekens."
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def run_systemctl(action: str, unit: str) -> dict:
|
async def run_systemctl(action: str, unit: str) -> dict:
|
||||||
"""Voert systemctl --user <action> <unit> uit en geeft het resultaat terug."""
|
"""Voert systemctl --user <action> [unit] uit en geeft het resultaat terug."""
|
||||||
|
if action in NO_UNIT_ACTIONS:
|
||||||
|
cmd = ["systemctl", "--user", action]
|
||||||
|
else:
|
||||||
cmd = ["systemctl", "--user", action, unit]
|
cmd = ["systemctl", "--user", action, unit]
|
||||||
log.info("Uitvoeren: %s", " ".join(cmd))
|
log.info("Uitvoeren: %s", " ".join(cmd))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user