Files
biliup-next/src/biliup_next/infra/systemd_runtime.py

83 lines
2.8 KiB
Python

from __future__ import annotations
import subprocess
ALLOWED_SERVICES = {
"biliup-next-worker.service",
"biliup-next-api.service",
}
ALLOWED_ACTIONS = {"start", "stop", "restart"}
class SystemdRuntime:
def list_services(self) -> dict[str, object]:
items = []
for service in sorted(ALLOWED_SERVICES):
items.append(self._inspect_service(service))
return {"items": items}
def act(self, service: str, action: str) -> dict[str, object]:
if service not in ALLOWED_SERVICES:
raise ValueError(f"unsupported service: {service}")
if action not in ALLOWED_ACTIONS:
raise ValueError(f"unsupported action: {action}")
result = subprocess.run(
["sudo", "systemctl", action, service],
capture_output=True,
text=True,
check=False,
)
payload = self._inspect_service(service)
payload["action"] = action
payload["command_ok"] = result.returncode == 0
payload["stderr"] = (result.stderr or "").strip()
payload["stdout"] = (result.stdout or "").strip()
return payload
def _inspect_service(self, service: str) -> dict[str, object]:
show = subprocess.run(
[
"systemctl",
"show",
service,
"--property=Id,Description,LoadState,ActiveState,SubState,MainPID,ExecMainStatus,FragmentPath",
],
capture_output=True,
text=True,
check=False,
)
info = {
"id": service,
"description": "",
"load_state": "unknown",
"active_state": "unknown",
"sub_state": "unknown",
"main_pid": 0,
"exec_main_status": None,
"fragment_path": "",
}
for line in (show.stdout or "").splitlines():
if "=" not in line:
continue
key, value = line.split("=", 1)
if key == "Id":
info["id"] = value
elif key == "Description":
info["description"] = value
elif key == "LoadState":
info["load_state"] = value
elif key == "ActiveState":
info["active_state"] = value
elif key == "SubState":
info["sub_state"] = value
elif key == "MainPID":
try:
info["main_pid"] = int(value)
except ValueError:
info["main_pid"] = 0
elif key == "ExecMainStatus":
info["exec_main_status"] = value
elif key == "FragmentPath":
info["fragment_path"] = value
return info