103 lines
5.3 KiB
Python
103 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""keptprobe.py — R-1271 live, on a throwaway drive-folder app this run installs (never a household's unit).
|
|
|
|
The measured case (catalog sweep 2026-10-24): a copy dated in the future beat the family's own copy. Here the
|
|
future-dated copy is FORGED on 9202 in a scratch place every box looks at — a second-drive copy of the app's own unit
|
|
under the system drive's backups/secondary/<app>/recovery-unit, its data time set to 2026-10-28T06:39:39Z (the
|
|
rehearsal box's clock), the only hand-made change. Then the household's order:
|
|
install, seed, „Mentés most", remove keeping data, install again → the question (expect: the OWN copy named, no
|
|
future flag); the own unit moved aside for a moment → the question again (expect: the forged copy offered, marked
|
|
future, with the sentence, not recommended); the own unit back → „A megőrzött adataimat használom" → the item back.
|
|
Then remove with data (the forged copy goes with the app's second-drive copies).
|
|
|
|
usage: SC=… SWEEP_EV=… TARGET=9202 DRIVE_ROOT=… python3 keptprobe.py <app>
|
|
"""
|
|
import json, os, sys, time
|
|
|
|
TOOLS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../catalog-sweep-2026-10-24/tools")
|
|
sys.path.insert(0, TOOLS)
|
|
import sweep as sw # noqa: E402
|
|
|
|
w, fxm = sw.w, sw.fxm
|
|
FUTURE = "2026-10-28T06:39:39Z"
|
|
|
|
|
|
def ask(app, sub):
|
|
os.environ.pop("KEPT", None)
|
|
c, d = w.ctl("POST", f"/api/stacks/{app}/deploy", {"values": dict(w.deploy_values(app, sub, dict(w.GENERATED.get(app) or {})))})
|
|
data = (d.get("data") or {}) if isinstance(d, dict) else {}
|
|
return c, {k: data.get(k) for k in ("code", "use_offered", "use_desc", "use_future", "use_warn", "use_off")}
|
|
|
|
|
|
def main(app):
|
|
d = os.path.join(sw.EV, "_keptprobe", app)
|
|
os.makedirs(d, exist_ok=True)
|
|
log = open(os.path.join(d, "walk.log"), "a")
|
|
|
|
def say(*a):
|
|
line = time.strftime("%H:%M:%SZ", time.gmtime()) + " " + " ".join(str(x) for x in a)
|
|
print(line, flush=True)
|
|
log.write(sw.scrub(line) + "\n")
|
|
log.flush()
|
|
|
|
w.say = say
|
|
fx = fxm.FIXTURES[app]
|
|
sub = getattr(fx, "sub", app)
|
|
rec = {"app": app}
|
|
forged = f"/mnt/sys_drive/felhom-data/backups/secondary/{app}/recovery-unit"
|
|
t_start = int(time.time())
|
|
unit = ""
|
|
w.login()
|
|
try:
|
|
rec["install"] = w.deploy(app, sub) and w.wait_app(sub, "/", tries=120, delay=5)
|
|
tok = fx.seed(w, sub, say)
|
|
rec["seed"] = bool(tok)
|
|
sw.backup_now(rec, say)
|
|
unit = sw.g(f"for p in /mnt/felhom-drives/*/backups/primary/{app} /mnt/felhom-drives/*/felhom-data/backups/primary/{app}; do [ -f $p/manifest.json ] && echo $p; done | head -1").strip()
|
|
rec["own_unit"] = unit
|
|
if not unit:
|
|
say(" no unit of the app on its drive — stop")
|
|
return
|
|
sw.g(f"rm -rf /mnt/sys_drive/felhom-data/backups/secondary/{app}; mkdir -p /mnt/sys_drive/felhom-data/backups/secondary/{app} && cp -a {unit} {forged} && "
|
|
f"sed -i -E 's/\"at\": \"[^\"]+\"/\"at\": \"{FUTURE}\"/' {forged}/manifest.json")
|
|
rec["forged_at"] = sw.g(f"grep -o '\"at\": \"[^\"]*\"' {forged}/manifest.json | head -2").strip()
|
|
say(f" forged a future-dated second-drive copy: {rec['forged_at']} (own unit: {unit})")
|
|
sw.remove(app, keep=True, say=say)
|
|
rec["q1_code"], rec["q1"] = ask(app, sub)
|
|
say(f" [question, own copy + future copy] {rec['q1_code']} {json.dumps(rec['q1'], ensure_ascii=False)[:400]}")
|
|
sw.g(f"mv {unit} {unit}.r1271-away")
|
|
rec["q2_code"], rec["q2"] = ask(app, sub)
|
|
say(f" [question, the future copy alone] {rec['q2_code']} {json.dumps(rec['q2'], ensure_ascii=False)[:500]}")
|
|
sw.g(f"mv {unit}.r1271-away {unit}")
|
|
os.environ["KEPT"] = "use"
|
|
w.DEPLOYED_THIS_RUN.discard(app)
|
|
rec["use_ok"] = w.deploy(app, sub, dict(w.GENERATED.get(app) or {}))
|
|
os.environ.pop("KEPT", None)
|
|
t0, last = time.time(), None
|
|
while time.time() - t0 < 1200:
|
|
time.sleep(5)
|
|
c, st = w.ctl("GET", "/api/backup/restore-status")
|
|
last = (st.get("data") or {}) if isinstance(st, dict) else {}
|
|
if not last.get("running") and time.time() - t0 > 10:
|
|
break
|
|
rec["load_status"] = json.dumps(last, ensure_ascii=False)[:600]
|
|
say(" load: " + rec["load_status"][:300])
|
|
w.wait_app(sub, "/", want=("200", "301", "302", "303", "307", "308", "401", "403"), tries=90, delay=5)
|
|
rec["item_after_load"] = bool(tok) and bool(fx.verify(w, sub, tok, say))
|
|
say(" item after use-my-kept-data: %s" % rec["item_after_load"])
|
|
finally:
|
|
os.environ.pop("KEPT", None)
|
|
if unit:
|
|
sw.g(f"[ -d {unit}.r1271-away ] && [ ! -e {unit} ] && mv {unit}.r1271-away {unit}")
|
|
rec["controller_lines"] = sw.scrub(sw.g(
|
|
f"docker logs --since {t_start} felhom-controller 2>&1 | grep -E '{app}' | grep -iE 'kept|USE MY|asking|future|restor' | cut -c1-300"))
|
|
if w.stack(app).get("deployed"):
|
|
sw.remove(app, keep=False, say=say)
|
|
rec["after_remove"] = sw.leftovers(app, sub)
|
|
rec["forged_left"] = sw.g(f"ls -d /mnt/sys_drive/felhom-data/backups/secondary/{app} 2>&1").strip()
|
|
json.dump(rec, open(os.path.join(d, "record.json"), "w"), ensure_ascii=False, indent=1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1])
|