65 lines
4.2 KiB
Python
65 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""h5_live.py seed | prove — R-1256 H5 live proof on scratch 9202 (night 2026-10-28), through the front doors.
|
|
seed : install vikunja, seed project C1 through its API, put a 1 GiB ballast file in its second volume (vikunja_db, so
|
|
the restore's second volume takes seconds — the put-back then comes long after the first volume's refusal).
|
|
The night backup (02:30) then makes the restore point.
|
|
prove: seed project C2 (newer than the backup); a created-only container holds the FIRST volume (vikunja_data) so
|
|
`docker volume rm -f` fails; a watcher removes it as soon as the controller logs the refusal; press the
|
|
household's restore. Want: the first volume is NOT written into (log), the restore fails, the put-back brings the
|
|
live data back (C1 AND C2 read back), the app runs, NO hold.
|
|
State (passwords) stays in the scratchpad, never printed."""
|
|
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
|
|
import upgrade_fixtures_box as fb
|
|
EV = "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0b76c4d7-9b39-4e4e-869d-d0d2c6006331/scratchpad/night/p1/h5"
|
|
STATE = os.path.join(EV, ".state.json")
|
|
fx = fb.FIXTURES["vikunja"]
|
|
SUB = getattr(fx, "sub", "vikunja")
|
|
APP = "vikunja"
|
|
w.login()
|
|
if sys.argv[1] == "seed":
|
|
assert w.deploy(APP, SUB), "deploy failed"
|
|
t1 = fx.seed(w, SUB, w.say)
|
|
assert t1, "seed C1 failed"
|
|
vols = w.guest("docker volume ls --format '{{.Name}}' | grep -E '^vikunja' | sort").split()
|
|
w.say(f"volumes: {vols}")
|
|
dbv = [v for v in vols if v.endswith("_db")][0]
|
|
w.say(w.guest(f"docker run --rm -v {dbv}:/x alpine sh -c 'dd if=/dev/urandom of=/x/r1256-ballast.bin bs=1M count=1024 2>&1 | tail -1; ls -la /x'", timeout=900))
|
|
json.dump({"c1": t1, "vols": vols}, open(STATE, "w")); os.chmod(STATE, 0o600)
|
|
w.say(f"C1 readback: {fx.verify(w, SUB, t1, w.say)}")
|
|
elif sys.argv[1] == "prove":
|
|
st = json.load(open(STATE))
|
|
snaps = w.snapshots(APP)
|
|
w.say(f"snapshots offered: {json.dumps(snaps)[:400]}")
|
|
assert snaps, "no restore point yet"
|
|
t2 = fx.seed(w, SUB, w.say) # C2: newer than the backup — the put-back must bring it back
|
|
assert t2, "seed C2 failed"
|
|
st["c2"] = t2; json.dump(st, open(STATE, "w"))
|
|
datav = [v for v in st["vols"] if v.endswith("_data")][0]
|
|
w.say("blocker: " + w.guest(f"docker rm -f r1256-blocker >/dev/null 2>&1; docker create --name r1256-blocker -v {datav}:/x alpine true"))
|
|
w.say("rm -f with the blocker (premise): " + w.guest(f"docker volume rm -f {datav} 2>&1; echo rc=$?"))
|
|
w.guest("rm -f /root/r1256-watch.log; nohup sh -c 'timeout 1800 docker logs -f --since 1s felhom-controller 2>&1 | "
|
|
f"grep -m1 \"Failed to remove volume {datav} before the restore\" > /root/r1256-watch.log; date -u +%T.%N >> /root/r1256-watch.log; "
|
|
"docker rm -f r1256-blocker >> /root/r1256-watch.log 2>&1; date -u +%T.%N >> /root/r1256-watch.log' >/dev/null 2>&1 &")
|
|
time.sleep(2)
|
|
t0 = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
|
res = w.restore(APP)
|
|
w.say(f"restore result: {json.dumps(res)[:1500]}")
|
|
w.say("watcher: " + w.guest("cat /root/r1256-watch.log"))
|
|
w.say("controller log: " + w.guest(f"docker logs --since {t0} felhom-controller 2>&1 | grep -E 'vikunja|R-1256|put-back|put back|Failed to remove' | tail -40"))
|
|
st_now = w.stack(APP)
|
|
w.say(f"after: state={st_now.get('state')} hold={st_now.get('hold_reason')!r}")
|
|
w.say(f"C1 readback: {fx.verify(w, SUB, st['c1'], w.say)}")
|
|
w.say(f"C2 readback: {fx.verify(w, SUB, t2, w.say)}")
|
|
code, d = w.ctl("GET", "/api/backup/restore-status")
|
|
w.say(f"restore record: {json.dumps(d)[:800]}")
|
|
w.say("blocker left: " + w.guest("docker ps -a --filter name=r1256-blocker --format '{{.Names}}'"))
|
|
w.say("copies: " + w.guest("find /mnt/felhom-drives/scratch_hdd/backups/restore-undo -maxdepth 2"))
|
|
elif sys.argv[1] == "teardown":
|
|
w.guest("docker rm -f r1256-blocker >/dev/null 2>&1; rm -f /root/r1256-watch.log")
|
|
w.remove(APP)
|
|
open(os.path.join(EV, f"{sys.argv[1]}.log"), "a").write("\n".join(w.LOG) + "\n")
|