#!/usr/bin/env python3 """Part A, first half — on controller v0.267.0 (the field's version): vikunja installed, seeded (A), backed up by the product (the update's own `backing-up` leg, then a pull that fails: nothing moves), RESTORED from its own unit — which recreates its volumes WITHOUT compose labels (R-658) — and seeded again (B, after the restore). Evidence only; every act is a product endpoint.""" import json, re, sys, time sys.path.insert(0, ".") import walk as w import fixtures as fx ST = "../partA/state.json" F = fx.Vikunja() SUB = "vikunja-la" out = {"controller": w.guest("cat /etc/felhom-controller-image").strip()} w.login() def drill_set(ref, msg): 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) p = f"{w.DRILL}/templates/vikunja/docker-compose.yml" s = open(p).read() s = re.sub(r"image: vikunja/vikunja:\S+", f"image: vikunja/vikunja:{ref}", s) open(p, "w").write(s) w.sh(["git", "-C", w.DRILL, "commit", "-qam", f"LIVE-A vikunja {ref}: {msg}"]) r = w.sh(["git", "-C", w.DRILL, "push", "-q", "origin", "main"], timeout=120) h = w.sh(["git", "-C", w.DRILL, "rev-parse", "--short=12", "HEAD"]).stdout.strip() w.say(f"drill {h}: vikunja {ref} ({msg}) push rc={r.returncode}") return h def labels(): return w.guest("for v in $(docker volume ls -q | grep '^vikunja_'); do echo \"$v $(docker volume inspect $v --format '{{json .Labels}}')\"; done") out["drill_A"] = drill_set("2.5.0", "the install version") w.sync_rescan() out["deployed"] = w.deploy("vikunja", SUB) w.wait_app(SUB, "/", tries=60, delay=3) A = F.seed(w, SUB, w.say) out["seed_A"] = bool(A) out["labels_after_install"] = labels() w.say("labels after install:\n" + out["labels_after_install"]) out["drill_E"] = drill_set("2.5.99-notag", "a tag that does not exist: backing-up runs, the pull fails, nothing moves") out["badge_wait"] = w.sync_rescan("vikunja", "vikunja/vikunja:2.5.99-notag") out["press_backup"] = w.press_update("vikunja") out["snapshots"] = w.snapshots("vikunja") w.say("snapshots offered: " + json.dumps(out["snapshots"])[:400]) out["drill_back"] = drill_set("2.5.0", "back to the install version") w.sync_rescan() out["restore"] = w.restore("vikunja") out["labels_after_restore_v0267"] = labels() w.say("labels after the v0.267.0 restore:\n" + out["labels_after_restore_v0267"]) w.wait_app(SUB, "/", tries=60, delay=3) out["A_after_restore"] = bool(F.verify(w, SUB, A, w.say)) B = F.seed(w, SUB, w.say) out["seed_B_after_restore"] = bool(B) json.dump({"A": A, "B": B, "sub": SUB}, open(ST, "w")) json.dump(out, open("../partA/01-v0267-install-backup-restore.json", "w"), indent=2, ensure_ascii=False, default=str) open("../partA/01-v0267-install-backup-restore.log", "w").write("\n".join(w.LOG) + "\n")