#!/usr/bin/env python3 """t1teardown.py — R-1022 on Tester 1 through its dashboard's own endpoints (operator word 2026-10-17 10:47). Env: SC (0600 dir with .ctlpw = Tester 1's dashboard password), EV, TARGET=tester-1. Steps: apps stop + remove each test app WITHOUT „delete data" (remove_hdd_data=false, remove_backups=false) drives decommission media_a..media_d („anyway", type-to-confirm = the mount name), the dashboard's call state deployed apps, storage paths, the controller image and repo_url (read-only) """ import json, os, sys, time sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts") import box_walk as w # noqa: E402 EV = os.environ["EV"] LOG = open(os.path.join(EV, "t1-console.txt"), "a", buffering=1) _say = w.say def say(*a): _say(*a); LOG.write(time.strftime("%H:%M:%S ") + " ".join(str(x) for x in a) + "\n") w.say = say APPS = ["sonarr", "radarr", "qbittorrent", "transmission", "plex", "jellyfin", "prowlarr"] DRIVES = ["media_a", "media_b", "media_c", "media_d"] def state(): c, d = w.ctl("GET", "/api/stacks") dep = sorted(s.get("name") for s in (d.get("data") or []) if s.get("deployed")) say(f"deployed apps: {dep}") say(w.guest("cat /etc/felhom-controller-image; grep -n repo_url /var/lib/docker/volumes/felhom-controller-data/_data/controller.yaml; " "findmnt -rn -o TARGET | grep felhom-drives; python3 -c \"import json;d=json.load(open('/var/lib/docker/volumes/felhom-controller-data/_data/data/settings.json'));" "print('storage paths:', [(p.get('path'), 'decommissioned' if p.get('decommissioned') else 'live') for p in d.get('storage_paths') or []])\"")) def main(): step = sys.argv[1] w.login() if step == "apps": for a in APPS: st = w.stack(a) if not st.get("deployed"): say(f"{a}: not deployed — skipped"); continue c1, d1 = w.ctl("POST", f"/api/stacks/{a}/stop") for _ in range(36): time.sleep(5) if w.stack(a).get("state") != "running": break c2, d2 = w.ctl("POST", f"/api/stacks/{a}/remove", {"remove_hdd_data": False, "remove_backups": False}) say(f"{a}: stop -> {c1}; remove (keep data, keep backups) -> {c2} {json.dumps(d2, ensure_ascii=False)[:260]}") state() elif step == "drives": for m in DRIVES: c, d = w.ctl("POST", "/api/storage/decommission", {"where": f"/mnt/felhom-drives/{m}", "mode": "anyway", "mount_name": m}) say(f"decommission {m} -> {c} {json.dumps(d, ensure_ascii=False)[:300]}") time.sleep(5) state() elif step == "state": state() main()