53 lines
2.9 KiB
Python
53 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""walk_lifecycle.py — capability map B2 („App lifecycle") re-walked on scratch 9202 (night 2026-10-28) through the
|
|
dashboard's own API: install a throwaway Radicale, stop, start, restart, logs; the protected stacks refuse a stop; remove
|
|
with its data — and its labelled volume is gone (the re-check the map row asks for after R-1117)."""
|
|
import json, os, sys, time
|
|
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
|
os.environ.setdefault("SC", "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0b76c4d7-9b39-4e4e-869d-d0d2c6006331/scratchpad/rt-9202")
|
|
os.environ.setdefault("TARGET", "9202")
|
|
import box_walk as w
|
|
EV = "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0b76c4d7-9b39-4e4e-869d-d0d2c6006331/scratchpad/night/p5"
|
|
APP = "radicale"
|
|
w.login()
|
|
res = {}
|
|
|
|
|
|
def state():
|
|
return w.stack(APP).get("state")
|
|
|
|
|
|
def running_containers():
|
|
return w.guest(f"docker ps --filter label=com.docker.compose.project={APP} --format '{{{{.Names}}}} {{{{.Status}}}}'").strip()
|
|
|
|
|
|
res["deploy"] = w.deploy(APP, "radicale")
|
|
res["volumes_installed"] = w.guest(f"docker volume ls --filter label=com.docker.compose.project={APP} --format '{{{{.Name}}}}'").split()
|
|
for act in ("stop", "start", "restart"):
|
|
code, d = w.ctl("POST", f"/api/stacks/{APP}/{act}")
|
|
for _ in range(24):
|
|
time.sleep(5)
|
|
s = state()
|
|
if (act == "stop" and s != "running") or (act != "stop" and s == "running"):
|
|
break
|
|
res[act] = {"http": code, "state_after": state(), "containers": running_containers()}
|
|
w.say(f"B2 {act}: http={code} state={res[act]['state_after']} containers={res[act]['containers']!r}")
|
|
code, d = w.ctl("GET", f"/api/stacks/{APP}/logs?lines=20")
|
|
logs = (d.get("data") or {}) if isinstance(d, dict) else {}
|
|
txt = json.dumps(logs)
|
|
res["logs"] = {"http": code, "bytes": len(txt), "names_radicale": "radicale" in txt.lower()}
|
|
w.say(f"B2 logs: http={code}, {len(txt)} bytes, mention radicale: {res['logs']['names_radicale']}")
|
|
for prot in ("traefik", "felhom-controller", "cloudflared"):
|
|
code, d = w.ctl("POST", f"/api/stacks/{prot}/stop")
|
|
alive = w.guest(f"docker ps --filter name=^{prot}$ --format '{{{{.Status}}}}'").strip()
|
|
res[f"protected_{prot}"] = {"http": code, "msg": str(d)[:160], "still_running": alive}
|
|
w.say(f"B2 protected stop {prot}: http={code} ({str(d)[:100]}) still running: {alive!r}")
|
|
code = w.remove(APP)
|
|
time.sleep(5)
|
|
res["remove_http"] = code
|
|
res["volumes_after"] = w.guest(f"docker volume ls --filter label=com.docker.compose.project={APP} --format '{{{{.Name}}}}'").split()
|
|
res["containers_after"] = w.guest(f"docker ps -a --filter label=com.docker.compose.project={APP} --format '{{{{.Names}}}}'").split()
|
|
w.say(f"B2 remove with data: http={code}, labelled volumes left {res['volumes_after']}, containers left {res['containers_after']}")
|
|
json.dump(res, open(os.path.join(EV, "lifecycle-walk.json"), "w"), indent=1)
|
|
open(os.path.join(EV, "lifecycle-walk.log"), "w").write("\n".join(w.LOG) + "\n")
|