demo: commit the recording harness #8

Merged
claude merged 3 commits from demo/recording-harness into main 2026-09-22 19:42:00 -04:00
2 changed files with 30 additions and 6 deletions
Showing only changes of commit 3e7b777e53 - Show all commits
+17 -4
View File
@@ -16,6 +16,17 @@ CYAN, GREEN, RED, YEL, MAG = "\033[36m", "\033[32m", "\033[31m", "\033[33m", "\0
SPEED = float(os.environ.get("DEMO_SPEED", "1.0"))
def recovered_bytes(rec: dict) -> bytes:
"""zerto_recover_file returns the content now, not a path on the MCP host.
The server may be on another machine, so a path there is of no use here.
"""
import base64
if rec.get("encoding") == "base64":
return base64.b64decode(rec["content"])
return rec["content"].encode()
def w(s=""):
sys.stdout.write(s + "\n"); sys.stdout.flush()
@@ -212,8 +223,8 @@ async def main():
if not rec.get("ok"):
w(f"{RED} FLR failed{RST}"); return 1
beat(1.5)
w(f"{YEL} $ cat {rec['path']}{RST}")
body = Path(rec["path"]).read_text()
w(f"{YEL} recovered {rec['bytes']} bytes, sha256 {rec['sha256'][:16]}...{RST}")
body = recovered_bytes(rec).decode()
for line in body.splitlines():
w(f"{GREEN}{BOLD} | {line}{RST}")
beat(2.5)
@@ -222,11 +233,13 @@ async def main():
step("Copy it back to the guest")
note("This part is scp, not Zerto. Zerto got the bytes back.")
target = f"{CFG['user']}@{CFG['host']}"
local_copy = SP / rec["name"]
local_copy.write_bytes(recovered_bytes(rec))
scp = (["sshpass", "-p", CFG["password"]] if CFG.get("password") else []) + \
["scp", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null",
"-o", "LogLevel=ERROR"] + (["-i", CFG["key"]] if CFG.get("key") else []) + \
[rec["path"], f"{target}:{CFG['guest_path']}"]
w(f"{YEL} $ scp {Path(rec['path']).name} {target}:{CFG['guest_path']}{RST}")
[str(local_copy), f"{target}:{CFG['guest_path']}"]
w(f"{YEL} $ scp {rec['name']} {target}:{CFG['guest_path']}{RST}")
subprocess.run(scp, capture_output=True, text=True, timeout=60)
guest(f"cat {CFG['guest_path']}")
beat(1.5)
+13 -2
View File
@@ -22,6 +22,17 @@ T0 = time.time()
STEP = [0]
def recovered_bytes(rec: dict) -> bytes:
"""zerto_recover_file returns the content now, not a path on the MCP host.
The server may be on another machine, so a path there is of no use here.
"""
import base64
if rec.get("encoding") == "base64":
return base64.b64decode(rec["content"])
return rec["content"].encode()
def w(s=""):
sys.stdout.write(s + "\n"); sys.stdout.flush()
@@ -155,7 +166,7 @@ async def main():
show(rec, keep=["ok", "bytes", "flr_path", "unmount"])
if not rec.get("ok"):
w(f"{RED} FLR failed{RST}"); return 1
body = Path(rec["path"]).read_text()
body = recovered_bytes(rec).decode()
w(f"{YEL} recovered file:{RST}")
for line in body.splitlines():
w(f"{GREEN}{BOLD} | {line}{RST}")
@@ -166,7 +177,7 @@ async def main():
# endings and appends one, which makes the restored file differ
# from what Zerto handed back. WriteAllBytes does not.
import base64
blob = Path(rec["path"]).read_bytes()
blob = recovered_bytes(rec)
b64 = base64.b64encode(blob).decode()
guest_ps(
f"[IO.File]::WriteAllBytes('{CFG['guest_path']}',"