60 lines
2.4 KiB
Python
60 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise the independent recovery task after a real systemd service stop."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
from uuid import uuid4
|
|
|
|
|
|
def run(*args: str) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.run(args, check=True, capture_output=True, text=True, timeout=30)
|
|
|
|
|
|
def main() -> int:
|
|
if os.geteuid() != 0 or not Path("/run/systemd/system").is_dir():
|
|
raise RuntimeError("real systemd lifecycle test requires root on a systemd host")
|
|
token = uuid4().hex[:12]
|
|
directory_name = f"matrix-kernel-recovery-test-{token}"
|
|
main_unit = f"{directory_name}-main"
|
|
task_unit = f"{directory_name}-task"
|
|
runtime = Path("/run") / directory_name
|
|
if runtime.exists():
|
|
raise RuntimeError("isolated runtime directory already exists")
|
|
try:
|
|
run("systemd-run", "--quiet", f"--unit={main_unit}",
|
|
f"--property=RuntimeDirectory={directory_name}",
|
|
"--property=RuntimeDirectoryPreserve=yes", "/bin/sleep", "120")
|
|
for _ in range(30):
|
|
if runtime.is_dir():
|
|
break
|
|
time.sleep(0.1)
|
|
else:
|
|
raise RuntimeError("temporary service did not create its runtime directory")
|
|
if run("systemctl", "show", main_unit, "--property=RuntimeDirectoryPreserve", "--value").stdout.strip() != "yes":
|
|
raise RuntimeError("temporary service did not enable runtime preservation")
|
|
run("systemctl", "stop", main_unit)
|
|
if not runtime.is_dir():
|
|
raise RuntimeError("systemd removed the runtime directory after service stop")
|
|
proof = runtime / "independent-task.txt"
|
|
run("systemd-run", "--quiet", "--wait", "--collect", f"--unit={task_unit}",
|
|
"/usr/bin/python3", "-c",
|
|
"from pathlib import Path; import sys; Path(sys.argv[1]).write_text('ok', encoding='ascii')",
|
|
str(proof))
|
|
if proof.read_text(encoding="ascii") != "ok":
|
|
raise RuntimeError("independent task did not survive the main service stop")
|
|
print("real systemd recovery lifecycle passed")
|
|
return 0
|
|
finally:
|
|
subprocess.run(["systemctl", "stop", main_unit], check=False, capture_output=True, timeout=15)
|
|
if runtime.is_dir() and runtime.parent == Path("/run") and runtime.name == directory_name:
|
|
shutil.rmtree(runtime)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|