Files
kodi 5196e7840f fix (helper): verplaats socket naar dedicated submap /run/podman-mvp/
Vervangt file bind-mount door directory mount om stale inode probleem
op te lossen: bij file bind-mounts bindt Podman de inode op run-tijd;
als podman-helper stopt en de socket verwijdert, wijst de container
nog steeds naar de verwijderde inode. Een directory mount lost altijd
op naar de huidige mapinhoud inclusief nieuwe inodes.

Wijzigingen:
- podman-helper.py: SOCKET_PATH → XDG_RUNTIME_DIR/podman-mvp/podman-helper.sock
- common.py: HELPER_SOCKET → /run/podman-mvp/podman-helper.sock
- CLAUDE.md: run-commando gebruikt -v /run/user/1000/podman-mvp:/run/podman-mvp

Deploy: kopieer podman-helper.py naar host, daemon-reload, restart helper,
rebuild backend image, herstart container met nieuwe mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 09:50:31 +01:00

107 lines
3.1 KiB
Python

import json
import socket
import subprocess
from fastapi import HTTPException
HELPER_SOCKET = "/run/podman-mvp/podman-helper.sock"
def _helper_call(action: str, unit: str) -> tuple[int, str]:
"""Stuur start/stop/restart naar de host-helper via Unix socket.
Returntype identiek aan run(): (returncode, output)."""
payload = json.dumps({"action": action, "unit": unit}).encode()
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.settimeout(35)
s.connect(HELPER_SOCKET)
s.sendall(payload)
s.shutdown(socket.SHUT_WR)
data = b""
while True:
chunk = s.recv(4096)
if not chunk:
break
data += chunk
resp = json.loads(data.decode())
if resp.get("ok"):
return 0, resp.get("output", "")
return 1, resp.get("error", "mislukt")
except Exception as e:
return 1, f"helper niet bereikbaar: {e}"
def run(cmd):
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
output = (result.stdout or "") + (result.stderr or "")
return result.returncode, output.strip()
except Exception as e:
return 1, str(e)
def _podman_get_json_checked(session, url: str):
r = session.get(url)
if r.status_code >= 400:
raise HTTPException(status_code=502, detail=r.text)
try:
return r.json()
except Exception:
raise HTTPException(status_code=502, detail=r.text)
def _podman_get_json(session, url: str):
return session.get(url).json()
def _podman_get_text(session, url: str) -> str:
return session.get(url).text
def _podman_post(session, url: str, **kwargs):
return session.post(url, **kwargs)
def _podman_action_post(session, podman_api_base: str, kind: str, name: str, action: str):
if kind == "pods":
url = f"{podman_api_base}/libpod/pods/{name}/{action}"
else:
url = f"{podman_api_base}/libpod/containers/{name}/{action}"
return _podman_post(session, url)
def _podman_delete(session, url: str):
return session.delete(url)
def _systemctl(cmd, run_func):
# Proxy to existing run() to avoid behavioral changes.
return run_func(cmd)
def _build_pod_to_containers_map(containers: list):
# preserves original order of containers processing; no sorting added
pod_to_containers = {}
for c in containers:
pod_name = c.get("PodName") or ""
if pod_name:
pod_to_containers.setdefault(pod_name, []).append((c.get("Names") or ["?"])[0])
return pod_to_containers
def _map_pod_to_unit(podname: str) -> str | None:
if not podname:
return None
if podname.startswith("pod"):
return f"{podname[3:]}.service"
return f"{podname}.service"
def _systemd_then_podman(systemd_callable, podman_callable):
systemd_res = systemd_callable()
if systemd_res is not None:
if isinstance(systemd_res, dict) and systemd_res.get("exit", 1) == 0:
return systemd_res
return podman_callable(systemd_res)
return podman_callable(None)