Files
felhom.eu/documentation/audits/night-2026-09-25/tools/d_waiting.py
T

48 lines
2.3 KiB
Python

"""Read-only: for each deployed app on a demo box's 9201, what the automatic leg would do tonight — computed from the
box's own app.yaml pins and the box's own catalog clone, with the leg's rules (proven, needs_person, files_may_change,
older-than-ladder, current). Usage: python3 d_waiting.py <ssh-host> <out.json>"""
import json, subprocess, sys
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
import ladder
host, outp = sys.argv[1], sys.argv[2]
def g(cmd):
return subprocess.run(["ssh", host, f"export LC_ALL=C; pct exec 9201 -- bash -c {json.dumps(cmd)}"], capture_output=True, text=True, timeout=120).stdout
VOL = "/var/lib/docker/volumes/felhom-controller-data/_data/data/catalog-cache/templates"
stacks = g("ls /opt/docker/stacks").split()
res = {}
for a in stacks:
app = g(f"cat /opt/docker/stacks/{a}/app.yaml 2>/dev/null")
if "deployed: true" not in app:
continue
pins, inst, sec = {}, {}, None
for l in app.splitlines():
if not l.startswith(" "):
sec = l.rstrip(":").strip()
continue
if sec == "pinned_images" and l.startswith(" ") and not l.startswith(" ") and ":" in l:
k, v = l.strip().split(":", 1); pins[k] = v.strip().strip('"')
fy = g(f"cat {VOL}/{a}/.felhom.yml 2>/dev/null")
E, _, err = ladder.parse(fy)
cat = ladder.images_in(g(f"cat {VOL}/{a}/docker-compose.yml 2>/dev/null"))
verdict = None
if not pins:
verdict = "unpinned"
elif pins == cat:
verdict = "current (pin = catalog head)"
elif not E:
verdict = "no_test_record"
else:
idx = max([i for i, e in enumerate(E) if e["from"] == pins] or [-1])
if idx < 0:
verdict = "no_test_record (at head)" if E[-1]["to"] == pins else "older_than_ladder"
else:
e = E[idx]
m = e.get("marks") or {}
if e["verdict"] != "proven": verdict = "not_proven"
elif m.get("needs_person"): verdict = "needs_person"
elif m.get("files_may_change"): verdict = "files_may_change (needs a fresh whole copy)"
else: verdict = "STEP WAITING: " + json.dumps(e["to"])
res[a] = {"pinned": pins, "catalog": cat, "ladder_len": len(E), "leg": verdict}
print(f"{a}: {verdict}")
json.dump(res, open(outp, "w"), indent=2)