Files
debian-manager/app/core/systemd_svc.py
T

74 lines
2.2 KiB
Python
Raw Normal View History

"""systemd: юниты, действия, journalctl."""
from __future__ import annotations
from dataclasses import dataclass
from typing import List
from app.core.ssh import SSHClient
CRITICAL_UNITS = {"ssh.service", "sshd.service", "ssh.socket", "docker.service",
"networking.service", "systemd-networkd.service", "dbus.service"}
@dataclass
class Unit:
name: str
load: str
active: str
sub: str
description: str
enabled: str = ""
async def list_units(c: SSHClient) -> List[Unit]:
r = await c.sudo(
"systemctl list-units --type=service --all --no-legend --no-pager "
"--plain | awk '{$1=$1};1'", timeout=60
)
enabled_r = await c.sudo(
"systemctl list-unit-files --type=service --no-legend --no-pager", timeout=60
)
enabled_map = {}
for line in enabled_r.stdout.splitlines():
p = line.split()
if len(p) >= 2:
enabled_map[p[0]] = p[1]
units: List[Unit] = []
for line in r.stdout.splitlines():
p = line.split(None, 4)
if len(p) >= 4:
units.append(Unit(
name=p[0], load=p[1], active=p[2], sub=p[3],
description=p[4] if len(p) > 4 else "",
enabled=enabled_map.get(p[0], ""),
))
return units
async def failed_units(c: SSHClient) -> List[str]:
r = await c.sudo("systemctl --failed --no-legend --no-pager --plain", timeout=30)
return [l.split()[0] for l in r.stdout.splitlines() if l.strip() and not l.startswith("0 ")]
async def action(c: SSHClient, unit: str, act: str) -> str:
assert act in ("start", "stop", "restart", "reload", "enable", "disable", "mask", "unmask")
r = await c.sudo(f"systemctl {act} {unit}", timeout=120)
if not r.ok:
raise RuntimeError(r.stderr.strip() or f"rc={r.returncode}")
return r.stdout
async def logs(c: SSHClient, unit: str, lines: int = 200) -> str:
r = await c.sudo(f"journalctl -u {unit} -n {lines} --no-pager", timeout=60)
return r.stdout
async def cat_unit(c: SSHClient, unit: str) -> str:
r = await c.sudo(f"systemctl cat {unit}", timeout=30)
return r.stdout
async def daemon_reload(c: SSHClient) -> None:
await c.sudo("systemctl daemon-reload")