#!/usr/bin/env python3 """Generate + (re)start per-team receiver systemd services. Each team receiver becomes gemastik-receiver-teamN.service, independent of the panel service. This fixes the bug where restarting gemastik-panel killed all team receivers (they were child processes of the panel systemd cgroup). """ import json import os import subprocess import sys from pathlib import Path TEAMS_DIR = Path("/opt/gemastik18-final/teams") RECEIVER_VENV = "/opt/gemastik18-final/receiver/.venv/bin/python" UNIT_DIR = Path("/etc/systemd/system") def write_unit(idx: int, st: dict): port = st["ports"]["receiver"] recv_dir = TEAMS_DIR / f"team{idx}" / "receiver" env = {} # ports/containers for challenge classes for ch in st["ports"]: if ch in ("receiver", "panel"): continue env[f"CHALLENGE_PORT_{ch.upper()}"] = str(st["ports"][ch]["chall"]) env[f"CHALLENGE_CONTAINER_{ch.upper()}"] = f"{ch}_container_team{idx}" env["COMPOSE_LOCATION"] = str(TEAMS_DIR / f"team{idx}" / "services" / "docker-compose.yml") env_lines = "\n".join(f'Environment="{k}={v}"' for k, v in env.items()) unit = f"""[Unit] Description=Gemastik A/D receiver for team {idx} After=docker.service Wants=docker.service [Service] Type=simple WorkingDirectory={recv_dir} EnvironmentFile={recv_dir}/.env {env_lines} ExecStart={RECEIVER_VENV} -m uvicorn main:app --host 0.0.0.0 --port {port} Restart=always RestartSec=3 [Install] WantedBy=multi-user.target """ (UNIT_DIR / f"gemastik-receiver-team{idx}.service").write_text(unit) def main(): action = sys.argv[1] if len(sys.argv) > 1 else "start" for d in sorted(TEAMS_DIR.glob("team*")): sf = d / "state.json" if not sf.exists(): continue st = json.loads(sf.read_text()) idx = st["index"] write_unit(idx, st) subprocess.run(["systemctl", "daemon-reload"], check=False) subprocess.run(["systemctl", "enable", f"gemastik-receiver-team{idx}.service"], check=False) if action == "stop": subprocess.run(["systemctl", "stop", f"gemastik-receiver-team{idx}.service"], check=False) else: subprocess.run(["systemctl", "restart", f"gemastik-receiver-team{idx}.service"], check=False) print(f"gemastik-receiver-team{idx}: {action} (port {st['ports']['receiver']})") if __name__ == "__main__": main()