Files
felhom.eu/documentation/audits/night-2026-09-24/tools/liveB2.py
T
2026-09-24 13:05:29 +02:00

73 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Part B live: a FLOATING tag (redis:7-alpine) whose tested digest moves in the catalog. (1) control: the box
runs the ladder's digest, badge current; (2) the drill ladder's head entry gets a different tested digest for the
same tag + a newer tested_at → badge must say behind (hu+en); (3) Update → the box pulls THAT digest, the compose
it runs names it, installed record's digest = it, badge current. Also: the pin and record stay digest-free."""
import json, re, sys, time, datetime
sys.path.insert(0, ".")
import walk as w
APP, SVC = "nextcloud", "nextcloud-redis"
NEW = "sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499" # back to the registry's real 7-alpine digest
CAT = f"{w.DRILL}/templates/{APP}"
out = {"controller": w.guest("cat /etc/felhom-controller-image").strip()}
w.login()
def boxview(tag):
st = w.stack(APP)
ac = st.get("app_config") or {}
v = {"state": st.get("state"), "installed": ac.get("installed_images"), "pinned": ac.get("pinned_images"),
"catalog_images": st.get("catalog_images"), "catalog_digests": st.get("catalog_digests"),
"catalog_tested_at": st.get("catalog_tested_at"), "badges": w.badges(APP),
"compose_redis": w.guest(f"grep -n 'image:' /opt/docker/stacks/{APP}/docker-compose.yml | grep redis").strip(),
"running_redis": w.guest(f"docker inspect -f '{{{{.Config.Image}}}} {{{{.Image}}}}' {SVC}").strip()}
out[tag] = v
w.say(f"[{tag}] " + json.dumps({k: v[k] for k in ("state", "badges", "compose_redis", "running_redis")}, ensure_ascii=False))
w.say(f"[{tag}] installed={json.dumps(v['installed'])} pinned={json.dumps(v['pinned'])}")
return v
w.sync_rescan()
boxview("1-control")
fy = open(f"{CAT}/.felhom.yml").read()
lines = fy.split("\n")
idx = max(i for i, l in enumerate(lines) if l.startswith(" - {") and '"to"' in l)
e = json.loads(lines[idx][4:])
old = e["digest"][SVC]
e["digest"][SVC] = NEW
e["tested_at"] = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
e["note"] = "NIGHT-B2 drill: re-tested at the registry digest"
lines[idx] = " - " + json.dumps(e, ensure_ascii=False)
out["ladder_edit"] = {"old": old, "new": NEW, "tested_at": e["tested_at"]}
def edit():
open(f"{CAT}/.felhom.yml", "w").write("\n".join(lines))
import fcntl
with open(f"{w.SC}/drill.lock", "w") as lk:
fcntl.flock(lk, fcntl.LOCK_EX)
w.sh(["git", "-C", w.DRILL, "pull", "-q", "--rebase", "origin", "main"], timeout=120)
edit()
w.sh(["git", "-C", w.DRILL, "commit", "-qam", "NIGHT-B2 nextcloud: re-tested redis:7-alpine (v0.269.1 proof)"])
w.sh(["git", "-C", w.DRILL, "push", "-q", "origin", "main"], timeout=120)
w.say("drill: ladder head entry digest " + old[:19] + " -> " + NEW[:19])
w.sync_rescan()
for _ in range(20):
v = boxview("2-behind")
if (v.get("catalog_digests") or {}).get(SVC) == NEW:
break
time.sleep(10)
w.sync_rescan()
v2 = out["2-behind"]
out["sync_kept_running_digest"] = ("c35af3bb" in v2["compose_redis"]) and (NEW not in v2["compose_redis"])
w.say(f"CHECK the sync kept the running digest in the compose before Update: {out['sync_kept_running_digest']}")
out["update"] = w.press_update(APP)
w.sync_rescan()
boxview("3-after")
out["pull_log"] = w.guest("docker logs --since 10m felhom-controller 2>&1 | grep nextcloud | grep -E 'pin advanced|digest|pull|UPDATED|done|installed' | grep -v DEBUG | tail -10")
w.say("log:\n" + out["pull_log"])
json.dump(out, open("../B/21-floating-tag-0.269.1.json", "w"), indent=2, ensure_ascii=False, default=str)
open("../B/21-floating-tag-0.269.1.log", "w").write("\n".join(w.LOG) + "\n")