Files
attack-defense-platform/panel/verify_platform_health.py
T

93 lines
3.5 KiB
Python
Raw Normal View History

2026-09-27 00:31:47 +08:00
#!/usr/bin/env python3
"""Live health check for the attack-defense platform after the PixiJS work.
Uses the panel's own API with credentials read from .env, so no shell quoting
hazard and no password on a command line.
"""
import json
import subprocess
import urllib.request
import http.cookiejar
from pathlib import Path
BASE = "http://127.0.0.1:18081"
ENV = Path("/opt/gemastik18-final/panel/.env")
def load_env():
cfg = {}
for line in ENV.read_text().splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, _, v = line.partition("=")
cfg[k.strip()] = v.strip().strip('"').strip("'")
return cfg
def get(url, cookie=None):
req = urllib.request.Request(url)
if cookie:
req.add_header("Cookie", "; ".join(f"{c.name}={c.value}" for c in cookie))
with urllib.request.urlopen(req, timeout=30) as r:
return r.read().decode()
def post_json(url, payload, cookie=None):
data = json.dumps(payload).encode()
req = urllib.request.Request(url, data=data, method="POST",
headers={"Content-Type": "application/json"})
if cookie:
req.add_header("Cookie", "; ".join(f"{c.name}={c.value}" for c in cookie))
with urllib.request.urlopen(req, timeout=30) as r:
return r.read().decode()
def main():
cfg = load_env()
jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
# main.py's /api/login expects {"user","pass"} — not username/password.
body = json.dumps({"user": cfg["PANEL_ADMIN_USER"],
"pass": cfg["PANEL_ADMIN_PASS"]}).encode()
req = urllib.request.Request(BASE + "/api/login", data=body, method="POST",
headers={"Content-Type": "application/json"})
with opener.open(req, timeout=30) as r:
login = json.loads(r.read().decode())
print("login:", login)
cookie = jar
teams_raw = json.loads(get(BASE + "/api/teams", cookie))
teams = teams_raw.get("teams", teams_raw) if isinstance(teams_raw, dict) else teams_raw
print("\nteams:")
for t in teams:
print(f" #{t.get('index')} {t.get('label')} domain={t.get('domain')} "
f"receivers={t.get('receiver_port')} challenges={len(t.get('challenges') or [])}")
topo = json.loads(get(BASE + "/api/topology", cookie))
print("\ntopology API:",
{k: (len(v) if isinstance(v, list) else v) for k, v in topo.items()})
containers = subprocess.run(
["docker", "ps", "--format", "{{.Names}}"],
capture_output=True, text=True, timeout=60).stdout.split()
team_ct = [c for c in containers if c.endswith(tuple(f"_team{i}" for i in range(1, 10)))]
orphans = [c for c in containers
if "_container" in c and not any(c.endswith(f"_team{i}") for i in range(1, 10))]
print(f"\ncontainers: {len(team_ct)} team-scoped, orphans={orphans}")
services = subprocess.run(
["systemctl", "is-active",
"gemastik-panel", "gemastik-receiver-service",
"gemastik-receiver-team1", "gemastik-receiver-team2"],
capture_output=True, text=True, timeout=60).stdout.strip()
print("services:\n ", services.replace("\n", "\n "))
load = subprocess.run(["uptime"], capture_output=True, text=True).stdout.strip()
print("load:", load)
print("expected team containers:", len(teams) * 16, "| actual:", len(team_ct))
if __name__ == "__main__":
main()