From 6bf5c86333f86234dd01440539f5d7a295e8c33e Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Mon, 21 Sep 2026 21:06:15 +0000 Subject: [PATCH] runtime: publish SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1 --- ...DEWORKER-CONTRACT-RCA-READONLY-1104R1.json | 38 +++++++++++++++ ...ODEWORKER-CONTRACT-RCA-READONLY-1104R1.txt | 48 +++++++++++++++++++ runtime/latest.json | 16 +++---- runtime/latest.txt | 39 ++++++++------- 4 files changed, 113 insertions(+), 28 deletions(-) create mode 100644 runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.json create mode 100644 runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.txt diff --git a/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.json b/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.json new file mode 100644 index 00000000..a3628369 --- /dev/null +++ b/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "homelab-backup-nodeworker-contract-rca", + "started_at_utc": "2026-09-21T21:06:14Z", + "finished_at_utc": "2026-09-21T21:06:14Z", + "reference_register_checked": true, + "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", + "error_register_checked": true, + "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", + "command_sha256": "476f69ce1ba9062cf703c5b1de5f81404fc50b1b31240c36e2e6ecdcd7aebecc", + "duplicate_failed_command_blocked": false, + "block_reason": null, + "execution_started": true, + "change_declared": false, + "result_contract_valid": true, + "result_contract_status": null, + "result_contract_error": null, + "command_rc": 0, + "changes_made": false, + "rollback_started": false, + "rollback_restored": null, + "mutation_outcome": "NO_MUTATION", + "sanitized": true, + "secrets_included": false, + "private_addresses_included": false, + "raw_evidence_retained_locally": true, + "raw_evidence_sha256": "6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052", + "sanitized_output_sha256": "6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "WORKERS2_NODEWORKER_CONTRACT_RCA_BEGIN=1\nCOMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1\nMODE=read-only\nCOMPONENT=homelab-backup-nodeworker-contract-rca\nMUTATION_BOUNDARY=READ_ONLY_NO_EXECUTION_OF_BACKUP_WORKERS_NO_SERVICE_START_NO_TIMER_CHANGE_NO_LOCK_BREAK_NO_GIT_WRITE\nWRAPPER_INFO={\"logic\":[{\"line\":4,\"text\":\"ACCEPTED=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b')\"},{\"line\":5,\"text\":\"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}\"}],\"path\":\"/usr/local/sbin/homelab-backup-v2\",\"sha256\":\"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2\",\"size\":1656}\nHASH_MATCHED_HELPERS={\"entry504.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"sha256\":\"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\",\"size\":10566},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"sha256\":\"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\",\"size\":10566}],\"fresh_lxc_helper.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320}],\"lxc_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825}],\"producer_exec_helper.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449}],\"qemu_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627}],\"scheduler_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"sha256\":\"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\",\"size\":4097},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"sha256\":\"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\",\"size\":4097}]}\nHELPER_LOGIC_HITS={\"entry504.py\":[{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\"},{\"line\":64,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"'choose_due_target','write_state','epoch')\"},{\"line\":78,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\"},{\"line\":79,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\"},{\"line\":80,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced.\"},{\"line\":89,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper.selftest()\"},{\"line\":93,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_adapter=importlib.import_module('scheduler_adapter')\"},{\"line\":96,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\"},{\"line\":97,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\"},{\"line\":99,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _target(wrapper,lid):\"},{\"line\":100,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\"},{\"line\":101,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\"},{\"line\":104,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def selftest():\"},{\"line\":105,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":108,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\"},{\"line\":109,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\"},{\"line\":110,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\"},{\"line\":111,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_WRITE_BINDING')\"},{\"line\":112,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\"},{\"line\":113,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\"},{\"line\":114,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\"},{\"line\":116,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SELFTEST_OVERLAY504=PASS',flush=True)\"},{\"line\":120,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"argv=list(sys.argv[1:] if argv is None else argv)\"},{\"line\":121,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['selftest']:\"},{\"line\":122,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return selftest()\"},{\"line\":123,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":125,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-proof']:\"},{\"line\":129,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\"},{\"line\":132,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\"},{\"line\":141,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\"},{\"line\":142,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"first=legacy.choose_due_target(targets,state,now[0])\"},{\"line\":143,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\"},{\"line\":146,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\"},{\"line\":148,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\"},{\"line\":149,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\"},{\"line\":153,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\"},{\"line\":154,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}\"},{\"line\":155,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":159,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-select-live']:\"},{\"line\":160,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"state=legacy.load_state_all(); targets=wrapper.load_targets()\"},{\"line\":161,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"chosen=legacy.choose_due_target(targets,state)\"},{\"line\":163,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\"},{\"line\":165,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":167,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='plan-lxc':\"},{\"line\":168,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":169,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":170,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\"},{\"line\":172,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":174,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='verify-target':\"},{\"line\":175,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":176,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":179,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"out=wrapper.backup_target(t,True)\"},{\"line\":180,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"except legacy.BackupError as e:\"},{\"line\":181,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT=FAIL',flush=True)\"},{\"line\":182,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\"},{\"line\":184,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":186,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper.main([sys.argv[0],*argv])\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\"},{\"line\":64,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"'choose_due_target','write_state','epoch')\"},{\"line\":78,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\"},{\"line\":79,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\"},{\"line\":80,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced.\"},{\"line\":89,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper.selftest()\"},{\"line\":93,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_adapter=importlib.import_module('scheduler_adapter')\"},{\"line\":96,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\"},{\"line\":97,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\"},{\"line\":99,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _target(wrapper,lid):\"},{\"line\":100,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\"},{\"line\":101,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\"},{\"line\":104,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def selftest():\"},{\"line\":105,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":108,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\"},{\"line\":109,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\"},{\"line\":110,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\"},{\"line\":111,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_WRITE_BINDING')\"},{\"line\":112,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\"},{\"line\":113,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\"},{\"line\":114,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\"},{\"line\":116,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SELFTEST_OVERLAY504=PASS',flush=True)\"},{\"line\":120,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"argv=list(sys.argv[1:] if argv is None else argv)\"},{\"line\":121,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['selftest']:\"},{\"line\":122,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return selftest()\"},{\"line\":123,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":125,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-proof']:\"},{\"line\":129,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\"},{\"line\":132,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\"},{\"line\":141,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\"},{\"line\":142,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"first=legacy.choose_due_target(targets,state,now[0])\"},{\"line\":143,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\"},{\"line\":146,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\"},{\"line\":148,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\"},{\"line\":149,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\"},{\"line\":153,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\"},{\"line\":154,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}\"},{\"line\":155,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":159,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-select-live']:\"},{\"line\":160,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"state=legacy.load_state_all(); targets=wrapper.load_targets()\"},{\"line\":161,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"chosen=legacy.choose_due_target(targets,state)\"},{\"line\":163,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\"},{\"line\":165,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":167,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='plan-lxc':\"},{\"line\":168,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":169,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":170,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\"},{\"line\":172,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":174,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='verify-target':\"},{\"line\":175,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":176,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":179,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"out=wrapper.backup_target(t,True)\"},{\"line\":180,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"except legacy.BackupError as e:\"},{\"line\":181,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT=FAIL',flush=True)\"},{\"line\":182,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\"},{\"line\":184,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":186,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper.main([sys.argv[0],*argv])\"}],\"fresh_lxc_helper.py\":[{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"}],\"lxc_adapter.py\":[{\"line\":2,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"import base64, hashlib, json, os, pathlib, re, selectors, shlex, signal, stat, subprocess, sys, time\"},{\"line\":6,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"HELPER=pathlib.Path(__file__).resolve().parent/'fresh_lxc_helper.py'\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"def _live_inputs(legacy,node,vmid,scratch):\"},{\"line\":42,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue\"},{\"line\":50,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"try: rid=int(r.get('vmid'))\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"except Exception: raise AdapterError('RESOURCE_VMID')\"},{\"line\":52,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\\\"type\\\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(0int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"def selftest()->int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"def selftest()->int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"}],\"qemu_adapter.py\":[{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"},{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"},{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"}],\"scheduler_adapter.py\":[{\"line\":7,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"class SchedulerAdapterError(RuntimeError): pass\"},{\"line\":10,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not ok: raise SchedulerAdapterError(code)\"},{\"line\":23,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def _read_prior(legacy,logical_id):\"},{\"line\":25,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"p=root/(str(logical_id)+'.json')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def choose_due_target(targets,state,now=None):\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due=[]\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"for order,t in enumerate(targets):\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\"},{\"line\":70,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"overdue=age-seconds\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due.append((overdue,-order,t))\"},{\"line\":72,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not due: return None\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return max(due,key=lambda x:(x[0],x[1]))[2]\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def write_state(logical_id,result,**kw):\"},{\"line\":77,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"prior=_read_prior(legacy,logical_id)\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":90,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"legacy.choose_due_target=choose_due_target\"},{\"line\":92,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return {'choose_due_target':choose_due_target,'write_state':write_state,\"},{\"line\":7,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"class SchedulerAdapterError(RuntimeError): pass\"},{\"line\":10,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not ok: raise SchedulerAdapterError(code)\"},{\"line\":23,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def _read_prior(legacy,logical_id):\"},{\"line\":25,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"p=root/(str(logical_id)+'.json')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def choose_due_target(targets,state,now=None):\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due=[]\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"for order,t in enumerate(targets):\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\"},{\"line\":70,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"overdue=age-seconds\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due.append((overdue,-order,t))\"},{\"line\":72,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not due: return None\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return max(due,key=lambda x:(x[0],x[1]))[2]\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def write_state(logical_id,result,**kw):\"},{\"line\":77,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"prior=_read_prior(legacy,logical_id)\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":90,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"legacy.choose_due_target=choose_due_target\"},{\"line\":92,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return {'choose_due_target':choose_due_target,'write_state':write_state,\"}]}\nNODEWORKER_INFO={\"path\":\"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker\",\"sha256\":\"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1\",\"size\":17702}\nNODEWORKER_LOGIC_HITS=[{\"line\":6,\"text\":\"STATE_ROOT=/var/lib/homelab-backup/cloud-quorum\"},{\"line\":8,\"text\":\"RESTORE_STATE_ROOT=/var/lib/homelab-backup/vm-restore-validation\"},{\"line\":9,\"text\":\"RESTORE_WORK_ROOT=/mnt/staging/homelab-vm-restore-validation\"},{\"line\":11,\"text\":\"REMOTE_A='pve01-mail-01-crypt:homelab-backups'\"},{\"line\":12,\"text\":\"REMOTE_B='pve01-mail-02-crypt:homelab-backups'\"},{\"line\":18,\"text\":\"ACTIVE_RESTORE_STAGE=\\\"\\\"\"},{\"line\":19,\"text\":\"cleanup_restore_stage(){ if [[ -n \\\"$ACTIVE_RESTORE_STAGE\\\" && \\\"$ACTIVE_RESTORE_STAGE\\\" == \\\"$RESTORE_WORK_ROOT\\\"/* && -d \\\"$ACTIVE_RESTORE_STAGE\\\" ]]; then rm -rf --one-file-system \\\"$ACTIVE_RESTORE_STAGE\\\"; fi; }\"},{\"line\":20,\"text\":\"trap cleanup_restore_stage EXIT\"},{\"line\":21,\"text\":\"active_backup_restore(){ local rc; if pgrep -af '(^|/)(vzdump|qmrestore|pctrestore|vma|zstd|rclone)([[:space:]]|$)'; then return 0; else rc=$?; [[ \\\"$rc\\\" == 1 ]] && return 0; die \\\"PGREP_FAILED_$rc\\\" 69; fi; }\"},{\"line\":24,\"text\":\"expected_owner(){\"},{\"line\":25,\"text\":\"case \\\"$1\\\" in\"},{\"line\":29,\"text\":\"*) die \\\"VMID_NOT_ALLOWED_$1\\\" 64 ;;\"},{\"line\":33,\"text\":\"case \\\"$1\\\" in\"},{\"line\":36,\"text\":\"*) die \\\"VMID_NOT_ALLOWED_$1\\\" 64 ;;\"},{\"line\":43,\"text\":\"local vmid=\\\"$1\\\" type=\\\"$2\\\"\"},{\"line\":44,\"text\":\"if [[ \\\"$type\\\" == \\\"qemu\\\" ]]; then qm status \\\"$vmid\\\" | awk '{print $2}'; else pct status \\\"$vmid\\\" | awk '{print $2}'; fi\"},{\"line\":47,\"text\":\"local vmid=\\\"$1\\\" owner type status expect_status\"},{\"line\":48,\"text\":\"owner=\\\"$(expected_owner \\\"$vmid\\\")\\\"\"},{\"line\":49,\"text\":\"type=\\\"$(expected_type \\\"$vmid\\\")\\\"\"},{\"line\":50,\"text\":\"[[ \\\"$HOST\\\" == \\\"$owner\\\" ]] || die \\\"OWNER_MISMATCH_${vmid}_${HOST}_EXPECTED_${owner}\\\" 65\"},{\"line\":52,\"text\":\"[[ -s \\\"/etc/pve/qemu-server/${vmid}.conf\\\" ]] || die \\\"QEMU_CONFIG_MISSING_$vmid\\\" 66\"},{\"line\":54,\"text\":\"[[ -s \\\"/etc/pve/lxc/${vmid}.conf\\\" ]] || die \\\"LXC_CONFIG_MISSING_$vmid\\\" 66\"},{\"line\":56,\"text\":\"status=\\\"$(current_status \\\"$vmid\\\" \\\"$type\\\")\\\"\"},{\"line\":57,\"text\":\"expect_status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":58,\"text\":\"[[ \\\"$status\\\" == \\\"$expect_status\\\" ]] || die \\\"STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\\\" 66\"},{\"line\":59,\"text\":\"if [[ \\\"$vmid\\\" == \\\"160\\\" ]]; then [[ \\\"$(snapshot_count_160)\\\" == \\\"0\\\" ]] || die \\\"VM160_SNAPSHOT_COUNT_CHANGED\\\" 66; fi\"},{\"line\":60,\"text\":\"if [[ \\\"$vmid\\\" == \\\"9130\\\" ]]; then [[ \\\"$(vm_lock 9130)\\\" == \\\"none\\\" ]] || die \\\"VM9130_LOCK_PRESENT\\\" 66; fi\"},{\"line\":65,\"text\":\"local vmid=\\\"$1\\\" type=\\\"$2\\\" status expect_status\"},{\"line\":66,\"text\":\"status=\\\"$(current_status \\\"$vmid\\\" \\\"$type\\\")\\\"\"},{\"line\":67,\"text\":\"expect_status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":68,\"text\":\"[[ \\\"$status\\\" == \\\"$expect_status\\\" ]] || die \\\"POST_STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\\\" 66\"},{\"line\":69,\"text\":\"if [[ \\\"$vmid\\\" == \\\"160\\\" ]]; then [[ \\\"$(snapshot_count_160)\\\" == \\\"0\\\" ]] || die \\\"VM160_SNAPSHOT_COUNT_CHANGED_POST\\\" 66; fi\"},{\"line\":70,\"text\":\"if [[ \\\"$vmid\\\" == \\\"9130\\\" ]]; then [[ \\\"$(vm_lock 9130)\\\" == \\\"none\\\" ]] || die \\\"VM9130_LOCK_PRESENT_POST\\\" 66; fi\"},{\"line\":73,\"text\":\"local vmid=\\\"$1\\\" dir=\\\"$STATE_ROOT/vm${vmid}\\\" f\"},{\"line\":79,\"text\":\"restore_dir(){ printf '%s\\\\n' \\\"$RESTORE_STATE_ROOT/vm$1\\\"; }\"},{\"line\":80,\"text\":\"restore_ok(){\"},{\"line\":81,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" f state sha\"},{\"line\":82,\"text\":\"f=\\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; state=\\\"$STATE_ROOT/vm${vmid}/$gen.json\\\"\"},{\"line\":85,\"text\":\"jq -e --arg l \\\"vm${vmid}\\\" --arg g \\\"$gen\\\" --arg s \\\"$state\\\" --arg sha \\\"$sha\\\" '.schema==\\\"homelab-vm-restore-validation-v1\\\" and .logical_id==$l and .generation==$g and .transport_state==\\\"SEALED\\\" and .transport_state_file==$s and .restore_source==\\\"Cloud A\\\" and .parts_manifest_verified==true and .payload_sha256==$sha and .payload_sha256_verified==true and .payload_decompression_verified==true and .proxmox_config_extract_verified==true and .archive_recovery_readback_verified==true and .bounded_staging==true and .full_local_payload_written==false and .full_restore_proven==false and .result==\\\"OK\\\"' \\\"$f\\\" >/dev/null\"},{\"line\":88,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" state=\\\"$3\\\" work=\\\"$4\\\" base manifest expected_msha got_msha expected_count expected_size idx name size psha count total\"},{\"line\":90,\"text\":\"[[ \\\"$base\\\" == \\\"${REMOTE_A%/}/vm${vmid}/$gen\\\" ]] || die \\\"RESTORE_A_BASE_MISMATCH_$vmid\\\" 70\"},{\"line\":92,\"text\":\"got_msha=\\\"$(sha256sum \\\"$manifest\\\"|awk '{print $1}')\\\"; [[ \\\"$got_msha\\\" == \\\"$expected_msha\\\" ]] || die \\\"RESTORE_A_MANIFEST_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":95,\"text\":\"[[ \\\"$idx\\\" =~ ^[0-9]{8}$ && \\\"$name\\\" == part-????????.bin && \\\"$size\\\" =~ ^[1-9][0-9]*$ && \\\"$psha\\\" =~ ^[0-9a-f]{64}$ ]] || die \\\"RESTORE_A_MANIFEST_ROW_INVALID_$vmid\\\" 70\"},{\"line\":96,\"text\":\"(( size <= 536870912 )) || die \\\"RESTORE_A_PART_EXCEEDS_BOUND_$vmid\\\" 70\"},{\"line\":97,\"text\":\"[[ \\\"$idx\\\" == \\\"$(printf '%08d' \\\"$count\\\")\\\" ]] || die \\\"RESTORE_A_MANIFEST_INDEX_INVALID_$vmid\\\" 70\"},{\"line\":100,\"text\":\"[[ \\\"$count\\\" == \\\"$expected_count\\\" ]] || die \\\"RESTORE_A_PART_COUNT_MISMATCH_$vmid\\\" 70\"},{\"line\":101,\"text\":\"[[ \\\"$total\\\" == \\\"$expected_size\\\" ]] || die \\\"RESTORE_A_MANIFEST_TOTAL_SIZE_MISMATCH_$vmid\\\" 70\"},{\"line\":105,\"text\":\"local vmid=\\\"$1\\\" base=\\\"$2\\\" manifest=\\\"$3\\\" work=\\\"$4\\\" idx name size psha part actual count\"},{\"line\":109,\"text\":\"[[ -s \\\"$part\\\" && ! -L \\\"$part\\\" && \\\"$(stat -c %s \\\"$part\\\")\\\" == \\\"$size\\\" ]] || die \\\"RESTORE_A_PART_SIZE_MISMATCH_$vmid\\\" 70\"},{\"line\":110,\"text\":\"actual=\\\"$(sha256sum \\\"$part\\\"|awk '{print $1}')\\\"; [[ \\\"$actual\\\" == \\\"$psha\\\" ]] || die \\\"RESTORE_A_PART_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":114,\"text\":\"restore_validate(){\"},{\"line\":115,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" logical state work payload_name expected_sha expected_size base manifest fifo sha_out sha_pid pipe_rc sha_rc actual_sha config config_sha members member_count cfg_member level out tmp\"},{\"line\":116,\"text\":\"assert_local_identity \\\"$vmid\\\"; logical=\\\"vm${vmid}\\\"; state=\\\"$STATE_ROOT/$logical/$gen.json\\\"\"},{\"line\":117,\"text\":\"[[ -s \\\"$state\\\" && ! -L \\\"$state\\\" ]] || die \\\"RESTORE_STATE_MISSING_$vmid\\\" 65\"},{\"line\":118,\"text\":\"jq -e '.schema==\\\"homelab-cloud-quorum-payload-v1\\\" and .status==\\\"SEALED\\\" and .cloud_quorum==2 and .cloud_a_verified==true and .cloud_b_verified==true and .part_hashes_verified==true and .seal_written==true and .cloud_a_seal_verified==true and .cloud_b_seal_verified==true and .local_payload_present==false and .local_cleanup==\\\"OK\\\"' \\\"$state\\\" >/dev/null || die \\\"RESTORE_REQUIRES_STRICT_SEALED_$vmid\\\" 65\"},{\"line\":119,\"text\":\"if restore_ok \\\"$vmid\\\" \\\"$gen\\\"; then printf 'RESTORE_VALIDATION_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESULT=ALREADY_VALIDATED\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; return 0; fi\"},{\"line\":120,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die ACTIVE_BACKUP_RESTORE_PRESENT 75\"},{\"line\":122,\"text\":\"[[ \\\"$payload_name\\\" == \\\"vzdump-lxc-${vmid}-\\\"*.tar.zst || \\\"$payload_name\\\" == \\\"vzdump-qemu-${vmid}-\\\"*.vma.zst ]] || die \\\"RESTORE_PAYLOAD_NAME_INVALID_$vmid\\\" 70\"},{\"line\":123,\"text\":\"work=\\\"$RESTORE_WORK_ROOT/$logical/$gen\\\"; if [[ -e \\\"$work\\\" ]]; then [[ -d \\\"$work\\\" && ! -L \\\"$work\\\" ]] || die \\\"RESTORE_WORK_UNSAFE_$vmid\\\" 70; rm -rf --one-file-system \\\"$work\\\"; fi; mkdir -p \\\"$work\\\"; chmod 0700 \\\"$RESTORE_WORK_ROOT\\\" \\\"$RESTORE_WORK_ROOT/$logical\\\" \\\"$work\\\"; ACTIVE_RESTORE_STAGE=\\\"$work\\\"\"},{\"line\":124,\"text\":\"base=\\\"$(prepare_cloud_a_manifest \\\"$vmid\\\" \\\"$gen\\\" \\\"$state\\\" \\\"$work\\\")\\\"; manifest=\\\"$work/PARTS.tsv\\\"; fifo=\\\"$work/archive.sha.fifo\\\"; sha_out=\\\"$work/archive.sha256\\\"; mkfifo -m 0600 \\\"$fifo\\\"\"},{\"line\":127,\"text\":\"members=\\\"$work/members.txt\\\"; if stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | tee \\\"$fifo\\\" | zstd -dc | tar -tf - >\\\"$members\\\"; then pipe_rc=0; else pipe_rc=$?; fi\"},{\"line\":129,\"text\":\"if stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | tee \\\"$fifo\\\" | zstd -t - >/dev/null; then pipe_rc=0; else pipe_rc=$?; fi\"},{\"line\":132,\"text\":\"(( pipe_rc == 0 && sha_rc == 0 )) || die \\\"RESTORE_A_STREAM_VALIDATION_FAILED_${vmid}_${pipe_rc}_${sha_rc}\\\" 70\"},{\"line\":133,\"text\":\"actual_sha=\\\"$(awk 'NR==1{print $1}' \\\"$sha_out\\\")\\\"; [[ \\\"$actual_sha\\\" == \\\"$expected_sha\\\" ]] || die \\\"RESTORE_A_PAYLOAD_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":136,\"text\":\"[[ -s \\\"$members\\\" ]] || die \\\"RESTORE_LXC_ARCHIVE_EMPTY_$vmid\\\" 70\"},{\"line\":137,\"text\":\"awk '$0 ~ /^\\\\// || $0 ~ /(^|\\\\/)\\\\.\\\\.(\\\\/|$)/ {bad=1} END{exit bad}' \\\"$members\\\" || die \\\"RESTORE_LXC_MEMBER_UNSAFE_$vmid\\\" 70\"},{\"line\":138,\"text\":\"member_count=\\\"$(wc -l <\\\"$members\\\")\\\"; [[ \\\"$member_count\\\" =~ ^[1-9][0-9]*$ ]] || die \\\"RESTORE_LXC_MEMBER_COUNT_INVALID_$vmid\\\" 70\"},{\"line\":139,\"text\":\"cfg_member=\\\"$(awk '$0==\\\"./etc/vzdump/pct.conf\\\" || $0==\\\"etc/vzdump/pct.conf\\\" {print; exit}' \\\"$members\\\")\\\"; [[ -n \\\"$cfg_member\\\" ]] || die \\\"RESTORE_LXC_CONFIG_MEMBER_MISSING_$vmid\\\" 70\"},{\"line\":140,\"text\":\"if ( set +o pipefail; stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | zstd -dc | tar -xOf - \\\"$cfg_member\\\" >\\\"$config\\\" ); then :; else die \\\"RESTORE_LXC_CONFIG_EXTRACT_FAILED_$vmid\\\" 70; fi\"},{\"line\":143,\"text\":\"if ( set +o pipefail; stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | zstd -dc | vma config - >\\\"$config\\\" ); then :; else die \\\"RESTORE_QEMU_CONFIG_EXTRACT_FAILED_$vmid\\\" 70; fi\"},{\"line\":146,\"text\":\"[[ -s \\\"$config\\\" && ! -L \\\"$config\\\" ]] || die \\\"RESTORE_CONFIG_EMPTY_$vmid\\\" 70; config_sha=\\\"$(sha256sum \\\"$config\\\"|awk '{print $1}')\\\"\"},{\"line\":147,\"text\":\"out=\\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; mkdir -p \\\"$(dirname \\\"$out\\\")\\\"; chmod 0700 \\\"$RESTORE_STATE_ROOT\\\" \\\"$(dirname \\\"$out\\\")\\\"; tmp=\\\"${out}.new.$$\\\"\"},{\"line\":148,\"text\":\"jq -n --arg logical \\\"$logical\\\" --arg generation \\\"$gen\\\" --argjson vmid \\\"$vmid\\\" --arg vm_type \\\"$VM_TYPE\\\" --arg state \\\"$state\\\" --arg sha \\\"$expected_sha\\\" --arg config_sha \\\"$config_sha\\\" --arg level \\\"$level\\\" --argjson member_count \\\"$member_count\\\" --arg at \\\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\\" '{schema:\\\"homelab-vm-restore-validation-v1\\\",logical_id:$logical,generation:$generation,vmid:$vmid,vm_type:$vm_type,transport_state:\\\"SEALED\\\",transport_state_file:$state,restore_source:\\\"Cloud A\\\",parts_manifest_verified:true,payload_sha256:$sha,payload_sha256_verified:true,payload_decompression_verified:true,proxmox_config_extract_verified:true,proxmox_config_sha256:$config_sha,lxc_member_count:$member_count,archive_recovery_readback_verified:true,bounded_staging:true,max_staged_part_bytes:536870912,full_local_payload_written:false,full_restore_proven:false,validation_level:$level,result:\\\"OK\\\",validated_at_utc:$at}' >\\\"$tmp\\\"\"},{\"line\":149,\"text\":\"chmod 0600 \\\"$tmp\\\"; mv -f -- \\\"$tmp\\\" \\\"$out\\\"; rm -rf --one-file-system \\\"$work\\\"; ACTIVE_RESTORE_STAGE=\\\"\\\"\"},{\"line\":150,\"text\":\"restore_ok \\\"$vmid\\\" \\\"$gen\\\" || die \\\"RESTORE_EVIDENCE_POSTWRITE_INVALID_$vmid\\\" 70\"},{\"line\":151,\"text\":\"printf 'RESTORE_VALIDATION_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$out\\\"\"},{\"line\":154,\"text\":\"local vmid=\\\"$1\\\" owner type status\"},{\"line\":155,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":156,\"text\":\"owner=\\\"$(expected_owner \\\"$vmid\\\")\\\"\"},{\"line\":157,\"text\":\"type=\\\"$(expected_type \\\"$vmid\\\")\\\"\"},{\"line\":158,\"text\":\"status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":159,\"text\":\"printf 'PLAN_STATUS=OK\\\\nVMID=%s\\\\nOWNER=%s\\\\nTYPE=%s\\\\nEXPECTED_STATUS=%s\\\\n' \\\"$vmid\\\" \\\"$owner\\\" \\\"$type\\\" \\\"$status\\\"\"},{\"line\":162,\"text\":\"local vmid=\\\"$1\\\" generation=\\\"$2\\\"\"},{\"line\":163,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":164,\"text\":\"restore_validate \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":165,\"text\":\"assert_post_identity \\\"$vmid\\\" \\\"$VM_TYPE\\\"\"},{\"line\":166,\"text\":\"printf 'VERIFY_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$(restore_dir \\\"$vmid\\\")/$generation.json\\\"\"},{\"line\":168,\"text\":\"backup_one(){\"},{\"line\":169,\"text\":\"local vmid=\\\"$1\\\" pending_count pending state generation payload gen_dir archive_count archive log_file before_status\"},{\"line\":171,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":176,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die \\\"ACTIVE_BACKUP_RESTORE_PRESENT\\\" 75\"},{\"line\":179,\"text\":\"mapfile -t pending < <(latest_incomplete_state \\\"$vmid\\\")\"},{\"line\":181,\"text\":\"(( pending_count <= 1 )) || die \\\"MULTIPLE_INCOMPLETE_GENERATIONS_$vmid\\\" 65\"},{\"line\":186,\"text\":\"printf 'RESUME=YES\\\\nVMID=%s\\\\nGENERATION=%s\\\\nSTATE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$state\\\"\"},{\"line\":187,\"text\":\"\\\"$TRANSPORT\\\" backup-delete \\\"vm${vmid}\\\" \\\"$generation\\\" \\\"$payload\\\" \\\"$REMOTE_A\\\" \\\"$REMOTE_B\\\" \\\"$STATE_ROOT\\\"\"},{\"line\":189,\"text\":\"generation=\\\"vm${vmid}-${HOST}-$(date -u +%Y%m%dT%H%M%SZ)\\\"\"},{\"line\":190,\"text\":\"gen_dir=\\\"$STAGE_ROOT/vm${vmid}/$generation\\\"\"},{\"line\":195,\"text\":\"printf 'RESUME=NO\\\\nVMID=%s\\\\nGENERATION=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":202,\"text\":\"if ! ( umask 0022; exec vzdump \\\"$vmid\\\" \\\"${vzdump_args[@]}\\\" ) >\\\"$log_file\\\" 2>&1; then\"},{\"line\":204,\"text\":\"die \\\"VZDUMP_FAILED_$vmid\\\" 70\"},{\"line\":206,\"text\":\"mapfile -t archives < <(find \\\"$gen_dir\\\" -maxdepth 1 -type f -name \\\"vzdump-*-${vmid}-*.zst\\\" -print)\"},{\"line\":208,\"text\":\"[[ \\\"$archive_count\\\" == \\\"1\\\" ]] || { rm -rf -- \\\"$gen_dir\\\"; die \\\"VZDUMP_ARCHIVE_COUNT_${vmid}_${archive_count}\\\" 70; }\"},{\"line\":210,\"text\":\"[[ -s \\\"$archive\\\" && ! -L \\\"$archive\\\" ]] || die \\\"VZDUMP_ARCHIVE_UNSAFE_$vmid\\\" 70\"},{\"line\":212,\"text\":\"\\\"$TRANSPORT\\\" backup-delete \\\"vm${vmid}\\\" \\\"$generation\\\" \\\"$archive\\\" \\\"$REMOTE_A\\\" \\\"$REMOTE_B\\\" \\\"$STATE_ROOT\\\"\"},{\"line\":215,\"text\":\"rmdir -- \\\"$STAGE_ROOT/vm${vmid}\\\" 2>/dev/null || true\"},{\"line\":217,\"text\":\"assert_post_identity \\\"$vmid\\\" \\\"$VM_TYPE\\\"\"},{\"line\":218,\"text\":\"state=\\\"$STATE_ROOT/vm${vmid}/$generation.json\\\"\"},{\"line\":220,\"text\":\"restore_validate \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":221,\"text\":\"printf 'BACKUP_STATUS=SEALED\\\\nVMID=%s\\\\nGENERATION=%s\\\\nOWNER=%s\\\\nTYPE=%s\\\\nPOST_STATUS=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$HOST\\\" \\\"$VM_TYPE\\\" \\\"$(expected_status \\\"$vmid\\\")\\\" \\\"$(restore_dir \\\"$vmid\\\")/$generation.json\\\"\"},{\"line\":226,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die \\\"ACTIVE_BACKUP_RESTORE_PRESENT\\\" 75\"},{\"line\":231,\"text\":\"printf 'HOST_PREFLIGHT_STATUS=OK\\\\nHOST=%s\\\\nSTAGING_FREE_BYTES=%s\\\\nREMOTE_A_FREE_BYTES=%s\\\\nREMOTE_B_FREE_BYTES=%s\\\\nACTIVE_BACKUP_RESTORE=0\\\\n' \\\"$HOST\\\" \\\"$free\\\" \\\"$a_free\\\" \\\"$b_free\\\"\"},{\"line\":234,\"text\":\"local vmid=\\\"$1\\\" dir latest gen\"},{\"line\":235,\"text\":\"assert_local_identity \\\"$vmid\\\"; dir=\\\"$STATE_ROOT/vm${vmid}\\\"\"},{\"line\":236,\"text\":\"[[ -d \\\"$dir\\\" ]] || die \\\"STATE_DIR_MISSING_$vmid\\\" 65\"},{\"line\":238,\"text\":\"[[ -n \\\"$latest\\\" && -s \\\"$latest\\\" && ! -L \\\"$latest\\\" ]] || die \\\"LATEST_STATE_MISSING_$vmid\\\" 65\"},{\"line\":239,\"text\":\"jq -e '.status==\\\"SEALED\\\" and .cloud_quorum==2 and .local_payload_present==false and .local_cleanup==\\\"OK\\\" and .seal_written==true' \\\"$latest\\\" >/dev/null || die \\\"LATEST_STATE_NOT_SEALED_$vmid\\\" 65\"},{\"line\":240,\"text\":\"gen=\\\"$(jq -er '.generation' \\\"$latest\\\")\\\"; restore_ok \\\"$vmid\\\" \\\"$gen\\\" || die \\\"LATEST_RESTORE_NOT_OK_$vmid\\\" 65\"},{\"line\":241,\"text\":\"printf 'LATEST_SEALED_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nSTATE_FILE=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$latest\\\" \\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"\"},{\"line\":244,\"text\":\"case \\\"$ACTION\\\" in\"},{\"line\":246,\"text\":\"[[ \\\"$#\\\" == 1 ]] || die \\\"USAGE_HOST_PREFLIGHT\\\" 64\"},{\"line\":249,\"text\":\"latest-sealed)\"},{\"line\":250,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_LATEST_SEALED\\\" 64\"},{\"line\":254,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_PLAN\\\" 64\"},{\"line\":257,\"text\":\"backup)\"},{\"line\":258,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_BACKUP\\\" 64\"},{\"line\":259,\"text\":\"backup_one \\\"$2\\\"\"},{\"line\":261,\"text\":\"restore-validate)\"},{\"line\":262,\"text\":\"[[ \\\"$#\\\" == 3 ]] || die \\\"USAGE_RESTORE_VALIDATE\\\" 64\"},{\"line\":263,\"text\":\"restore_validate \\\"$2\\\" \\\"$3\\\"\"},{\"line\":266,\"text\":\"[[ \\\"$#\\\" == 3 ]] || die \\\"USAGE_VERIFY\\\" 64\"}]\nNODEWORKER_CLI_CANDIDATES=[{\"kind\":\"dispatch\",\"text\":\"case \\\"$1\\\" in\"},{\"kind\":\"subcommand-token\",\"text\":\"backup\"},{\"kind\":\"subcommand-token\",\"text\":\"restore\"},{\"kind\":\"subcommand-token\",\"text\":\"latest-sealed\"}]\nDECISION=DIRECT_NODEWORKER_TARGETED_BACKUP_CLI_DISCOVERED\nNO_MUTATION=true\nTASK_RESULT=PASS_HOMELAB_BACKUP_NODEWORKER_CONTRACT_RCA_READONLY\nHOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\nWORKERS2_NODEWORKER_CONTRACT_RCA_END=1\n" +} diff --git a/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.txt b/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.txt new file mode 100644 index 00000000..7f5a9a3d --- /dev/null +++ b/runtime/history/SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1.txt @@ -0,0 +1,48 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1 +STATUS=OK +RC=0 +HOST=pve01 +MODE=read-only +COMPONENT=homelab-backup-nodeworker-contract-rca +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 +COMMAND_SHA256=476f69ce1ba9062cf703c5b1de5f81404fc50b1b31240c36e2e6ecdcd7aebecc +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGE_DECLARED=false +RESULT_CONTRACT_VALID=true +RESULT_CONTRACT_STATUS=NOT_APPLICABLE +RESULT_CONTRACT_ERROR=NONE +COMMAND_RC=0 +CHANGES_MADE=false +ROLLBACK_STARTED=false +ROLLBACK_RESTORED=null +MUTATION_OUTCOME=NO_MUTATION +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052 +SANITIZED_OUTPUT_SHA256=6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052 +OUTPUT_BEGIN +WORKERS2_NODEWORKER_CONTRACT_RCA_BEGIN=1 +COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1 +MODE=read-only +COMPONENT=homelab-backup-nodeworker-contract-rca +MUTATION_BOUNDARY=READ_ONLY_NO_EXECUTION_OF_BACKUP_WORKERS_NO_SERVICE_START_NO_TIMER_CHANGE_NO_LOCK_BREAK_NO_GIT_WRITE +WRAPPER_INFO={"logic":[{"line":4,"text":"ACCEPTED=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b')"},{"line":5,"text":"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}"}],"path":"/usr/local/sbin/homelab-backup-v2","sha256":"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2","size":1656} +HASH_MATCHED_HELPERS={"entry504.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","sha256":"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793","size":10566},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","sha256":"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793","size":10566}],"fresh_lxc_helper.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320}],"lxc_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825}],"producer_exec_helper.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449}],"qemu_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627}],"scheduler_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","sha256":"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96","size":4097},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","sha256":"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96","size":4097}]} +HELPER_LOGIC_HITS={"entry504.py":[{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',"},{"line":64,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"'choose_due_target','write_state','epoch')"},{"line":78,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])"},{"line":79,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:"},{"line":80,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced."},{"line":89,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper.selftest()"},{"line":93,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_adapter=importlib.import_module('scheduler_adapter')"},{"line":96,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)"},{"line":97,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired"},{"line":99,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _target(wrapper,lid):"},{"line":100,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]"},{"line":101,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')"},{"line":104,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def selftest():"},{"line":105,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":108,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:"},{"line":109,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')"},{"line":110,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:"},{"line":111,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_WRITE_BINDING')"},{"line":112,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:"},{"line":113,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')"},{"line":114,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):"},{"line":116,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SELFTEST_OVERLAY504=PASS',flush=True)"},{"line":120,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"argv=list(sys.argv[1:] if argv is None else argv)"},{"line":121,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['selftest']:"},{"line":122,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return selftest()"},{"line":123,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":125,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-proof']:"},{"line":129,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')"},{"line":132,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:"},{"line":141,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]"},{"line":142,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"first=legacy.choose_due_target(targets,state,now[0])"},{"line":143,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')"},{"line":146,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')"},{"line":148,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])"},{"line":149,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')"},{"line":153,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')"},{"line":154,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}"},{"line":155,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)"},{"line":159,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-select-live']:"},{"line":160,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"state=legacy.load_state_all(); targets=wrapper.load_targets()"},{"line":161,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"chosen=legacy.choose_due_target(targets,state)"},{"line":163,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)"},{"line":165,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)"},{"line":167,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='plan-lxc':"},{"line":168,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":169,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":170,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')"},{"line":172,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)"},{"line":174,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='verify-target':"},{"line":175,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":176,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":179,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"out=wrapper.backup_target(t,True)"},{"line":180,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"except legacy.BackupError as e:"},{"line":181,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT=FAIL',flush=True)"},{"line":182,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)"},{"line":184,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)"},{"line":186,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper.main([sys.argv[0],*argv])"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',"},{"line":64,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"'choose_due_target','write_state','epoch')"},{"line":78,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])"},{"line":79,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:"},{"line":80,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced."},{"line":89,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper.selftest()"},{"line":93,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_adapter=importlib.import_module('scheduler_adapter')"},{"line":96,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)"},{"line":97,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired"},{"line":99,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _target(wrapper,lid):"},{"line":100,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]"},{"line":101,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')"},{"line":104,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def selftest():"},{"line":105,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":108,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:"},{"line":109,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')"},{"line":110,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:"},{"line":111,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_WRITE_BINDING')"},{"line":112,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:"},{"line":113,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')"},{"line":114,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):"},{"line":116,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SELFTEST_OVERLAY504=PASS',flush=True)"},{"line":120,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"argv=list(sys.argv[1:] if argv is None else argv)"},{"line":121,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['selftest']:"},{"line":122,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return selftest()"},{"line":123,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":125,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-proof']:"},{"line":129,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')"},{"line":132,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:"},{"line":141,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]"},{"line":142,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"first=legacy.choose_due_target(targets,state,now[0])"},{"line":143,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')"},{"line":146,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')"},{"line":148,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])"},{"line":149,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')"},{"line":153,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')"},{"line":154,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}"},{"line":155,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)"},{"line":159,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-select-live']:"},{"line":160,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"state=legacy.load_state_all(); targets=wrapper.load_targets()"},{"line":161,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"chosen=legacy.choose_due_target(targets,state)"},{"line":163,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)"},{"line":165,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)"},{"line":167,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='plan-lxc':"},{"line":168,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":169,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":170,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')"},{"line":172,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)"},{"line":174,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='verify-target':"},{"line":175,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":176,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":179,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"out=wrapper.backup_target(t,True)"},{"line":180,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"except legacy.BackupError as e:"},{"line":181,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT=FAIL',flush=True)"},{"line":182,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)"},{"line":184,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)"},{"line":186,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper.main([sys.argv[0],*argv])"}],"fresh_lxc_helper.py":[{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"}],"lxc_adapter.py":[{"line":2,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"import base64, hashlib, json, os, pathlib, re, selectors, shlex, signal, stat, subprocess, sys, time"},{"line":6,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"HELPER=pathlib.Path(__file__).resolve().parent/'fresh_lxc_helper.py'"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"def _live_inputs(legacy,node,vmid,scratch):"},{"line":42,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue"},{"line":50,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"try: rid=int(r.get('vmid'))"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"except Exception: raise AdapterError('RESOURCE_VMID')"},{"line":52,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\"type\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(0int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"def selftest()->int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"def selftest()->int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"}],"qemu_adapter.py":[{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"},{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"},{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"}],"scheduler_adapter.py":[{"line":7,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"class SchedulerAdapterError(RuntimeError): pass"},{"line":10,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not ok: raise SchedulerAdapterError(code)"},{"line":23,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def _read_prior(legacy,logical_id):"},{"line":25,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"p=root/(str(logical_id)+'.json')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def choose_due_target(targets,state,now=None):"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due=[]"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"for order,t in enumerate(targets):"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')"},{"line":70,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"overdue=age-seconds"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due.append((overdue,-order,t))"},{"line":72,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not due: return None"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return max(due,key=lambda x:(x[0],x[1]))[2]"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def write_state(logical_id,result,**kw):"},{"line":77,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"prior=_read_prior(legacy,logical_id)"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":90,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"legacy.choose_due_target=choose_due_target"},{"line":92,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return {'choose_due_target':choose_due_target,'write_state':write_state,"},{"line":7,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"class SchedulerAdapterError(RuntimeError): pass"},{"line":10,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not ok: raise SchedulerAdapterError(code)"},{"line":23,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def _read_prior(legacy,logical_id):"},{"line":25,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"p=root/(str(logical_id)+'.json')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def choose_due_target(targets,state,now=None):"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due=[]"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"for order,t in enumerate(targets):"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')"},{"line":70,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"overdue=age-seconds"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due.append((overdue,-order,t))"},{"line":72,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not due: return None"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return max(due,key=lambda x:(x[0],x[1]))[2]"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def write_state(logical_id,result,**kw):"},{"line":77,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"prior=_read_prior(legacy,logical_id)"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":90,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"legacy.choose_due_target=choose_due_target"},{"line":92,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return {'choose_due_target':choose_due_target,'write_state':write_state,"}]} +NODEWORKER_INFO={"path":"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker","sha256":"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1","size":17702} +NODEWORKER_LOGIC_HITS=[{"line":6,"text":"STATE_ROOT=/var/lib/homelab-backup/cloud-quorum"},{"line":8,"text":"RESTORE_STATE_ROOT=/var/lib/homelab-backup/vm-restore-validation"},{"line":9,"text":"RESTORE_WORK_ROOT=/mnt/staging/homelab-vm-restore-validation"},{"line":11,"text":"REMOTE_A='pve01-mail-01-crypt:homelab-backups'"},{"line":12,"text":"REMOTE_B='pve01-mail-02-crypt:homelab-backups'"},{"line":18,"text":"ACTIVE_RESTORE_STAGE=\"\""},{"line":19,"text":"cleanup_restore_stage(){ if [[ -n \"$ACTIVE_RESTORE_STAGE\" && \"$ACTIVE_RESTORE_STAGE\" == \"$RESTORE_WORK_ROOT\"/* && -d \"$ACTIVE_RESTORE_STAGE\" ]]; then rm -rf --one-file-system \"$ACTIVE_RESTORE_STAGE\"; fi; }"},{"line":20,"text":"trap cleanup_restore_stage EXIT"},{"line":21,"text":"active_backup_restore(){ local rc; if pgrep -af '(^|/)(vzdump|qmrestore|pctrestore|vma|zstd|rclone)([[:space:]]|$)'; then return 0; else rc=$?; [[ \"$rc\" == 1 ]] && return 0; die \"PGREP_FAILED_$rc\" 69; fi; }"},{"line":24,"text":"expected_owner(){"},{"line":25,"text":"case \"$1\" in"},{"line":29,"text":"*) die \"VMID_NOT_ALLOWED_$1\" 64 ;;"},{"line":33,"text":"case \"$1\" in"},{"line":36,"text":"*) die \"VMID_NOT_ALLOWED_$1\" 64 ;;"},{"line":43,"text":"local vmid=\"$1\" type=\"$2\""},{"line":44,"text":"if [[ \"$type\" == \"qemu\" ]]; then qm status \"$vmid\" | awk '{print $2}'; else pct status \"$vmid\" | awk '{print $2}'; fi"},{"line":47,"text":"local vmid=\"$1\" owner type status expect_status"},{"line":48,"text":"owner=\"$(expected_owner \"$vmid\")\""},{"line":49,"text":"type=\"$(expected_type \"$vmid\")\""},{"line":50,"text":"[[ \"$HOST\" == \"$owner\" ]] || die \"OWNER_MISMATCH_${vmid}_${HOST}_EXPECTED_${owner}\" 65"},{"line":52,"text":"[[ -s \"/etc/pve/qemu-server/${vmid}.conf\" ]] || die \"QEMU_CONFIG_MISSING_$vmid\" 66"},{"line":54,"text":"[[ -s \"/etc/pve/lxc/${vmid}.conf\" ]] || die \"LXC_CONFIG_MISSING_$vmid\" 66"},{"line":56,"text":"status=\"$(current_status \"$vmid\" \"$type\")\""},{"line":57,"text":"expect_status=\"$(expected_status \"$vmid\")\""},{"line":58,"text":"[[ \"$status\" == \"$expect_status\" ]] || die \"STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\" 66"},{"line":59,"text":"if [[ \"$vmid\" == \"160\" ]]; then [[ \"$(snapshot_count_160)\" == \"0\" ]] || die \"VM160_SNAPSHOT_COUNT_CHANGED\" 66; fi"},{"line":60,"text":"if [[ \"$vmid\" == \"9130\" ]]; then [[ \"$(vm_lock 9130)\" == \"none\" ]] || die \"VM9130_LOCK_PRESENT\" 66; fi"},{"line":65,"text":"local vmid=\"$1\" type=\"$2\" status expect_status"},{"line":66,"text":"status=\"$(current_status \"$vmid\" \"$type\")\""},{"line":67,"text":"expect_status=\"$(expected_status \"$vmid\")\""},{"line":68,"text":"[[ \"$status\" == \"$expect_status\" ]] || die \"POST_STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\" 66"},{"line":69,"text":"if [[ \"$vmid\" == \"160\" ]]; then [[ \"$(snapshot_count_160)\" == \"0\" ]] || die \"VM160_SNAPSHOT_COUNT_CHANGED_POST\" 66; fi"},{"line":70,"text":"if [[ \"$vmid\" == \"9130\" ]]; then [[ \"$(vm_lock 9130)\" == \"none\" ]] || die \"VM9130_LOCK_PRESENT_POST\" 66; fi"},{"line":73,"text":"local vmid=\"$1\" dir=\"$STATE_ROOT/vm${vmid}\" f"},{"line":79,"text":"restore_dir(){ printf '%s\\n' \"$RESTORE_STATE_ROOT/vm$1\"; }"},{"line":80,"text":"restore_ok(){"},{"line":81,"text":"local vmid=\"$1\" gen=\"$2\" f state sha"},{"line":82,"text":"f=\"$(restore_dir \"$vmid\")/$gen.json\"; state=\"$STATE_ROOT/vm${vmid}/$gen.json\""},{"line":85,"text":"jq -e --arg l \"vm${vmid}\" --arg g \"$gen\" --arg s \"$state\" --arg sha \"$sha\" '.schema==\"homelab-vm-restore-validation-v1\" and .logical_id==$l and .generation==$g and .transport_state==\"SEALED\" and .transport_state_file==$s and .restore_source==\"Cloud A\" and .parts_manifest_verified==true and .payload_sha256==$sha and .payload_sha256_verified==true and .payload_decompression_verified==true and .proxmox_config_extract_verified==true and .archive_recovery_readback_verified==true and .bounded_staging==true and .full_local_payload_written==false and .full_restore_proven==false and .result==\"OK\"' \"$f\" >/dev/null"},{"line":88,"text":"local vmid=\"$1\" gen=\"$2\" state=\"$3\" work=\"$4\" base manifest expected_msha got_msha expected_count expected_size idx name size psha count total"},{"line":90,"text":"[[ \"$base\" == \"${REMOTE_A%/}/vm${vmid}/$gen\" ]] || die \"RESTORE_A_BASE_MISMATCH_$vmid\" 70"},{"line":92,"text":"got_msha=\"$(sha256sum \"$manifest\"|awk '{print $1}')\"; [[ \"$got_msha\" == \"$expected_msha\" ]] || die \"RESTORE_A_MANIFEST_SHA_MISMATCH_$vmid\" 70"},{"line":95,"text":"[[ \"$idx\" =~ ^[0-9]{8}$ && \"$name\" == part-????????.bin && \"$size\" =~ ^[1-9][0-9]*$ && \"$psha\" =~ ^[0-9a-f]{64}$ ]] || die \"RESTORE_A_MANIFEST_ROW_INVALID_$vmid\" 70"},{"line":96,"text":"(( size <= 536870912 )) || die \"RESTORE_A_PART_EXCEEDS_BOUND_$vmid\" 70"},{"line":97,"text":"[[ \"$idx\" == \"$(printf '%08d' \"$count\")\" ]] || die \"RESTORE_A_MANIFEST_INDEX_INVALID_$vmid\" 70"},{"line":100,"text":"[[ \"$count\" == \"$expected_count\" ]] || die \"RESTORE_A_PART_COUNT_MISMATCH_$vmid\" 70"},{"line":101,"text":"[[ \"$total\" == \"$expected_size\" ]] || die \"RESTORE_A_MANIFEST_TOTAL_SIZE_MISMATCH_$vmid\" 70"},{"line":105,"text":"local vmid=\"$1\" base=\"$2\" manifest=\"$3\" work=\"$4\" idx name size psha part actual count"},{"line":109,"text":"[[ -s \"$part\" && ! -L \"$part\" && \"$(stat -c %s \"$part\")\" == \"$size\" ]] || die \"RESTORE_A_PART_SIZE_MISMATCH_$vmid\" 70"},{"line":110,"text":"actual=\"$(sha256sum \"$part\"|awk '{print $1}')\"; [[ \"$actual\" == \"$psha\" ]] || die \"RESTORE_A_PART_SHA_MISMATCH_$vmid\" 70"},{"line":114,"text":"restore_validate(){"},{"line":115,"text":"local vmid=\"$1\" gen=\"$2\" logical state work payload_name expected_sha expected_size base manifest fifo sha_out sha_pid pipe_rc sha_rc actual_sha config config_sha members member_count cfg_member level out tmp"},{"line":116,"text":"assert_local_identity \"$vmid\"; logical=\"vm${vmid}\"; state=\"$STATE_ROOT/$logical/$gen.json\""},{"line":117,"text":"[[ -s \"$state\" && ! -L \"$state\" ]] || die \"RESTORE_STATE_MISSING_$vmid\" 65"},{"line":118,"text":"jq -e '.schema==\"homelab-cloud-quorum-payload-v1\" and .status==\"SEALED\" and .cloud_quorum==2 and .cloud_a_verified==true and .cloud_b_verified==true and .part_hashes_verified==true and .seal_written==true and .cloud_a_seal_verified==true and .cloud_b_seal_verified==true and .local_payload_present==false and .local_cleanup==\"OK\"' \"$state\" >/dev/null || die \"RESTORE_REQUIRES_STRICT_SEALED_$vmid\" 65"},{"line":119,"text":"if restore_ok \"$vmid\" \"$gen\"; then printf 'RESTORE_VALIDATION_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESULT=ALREADY_VALIDATED\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$(restore_dir \"$vmid\")/$gen.json\"; return 0; fi"},{"line":120,"text":"[[ -z \"$(active_backup_restore)\" ]] || die ACTIVE_BACKUP_RESTORE_PRESENT 75"},{"line":122,"text":"[[ \"$payload_name\" == \"vzdump-lxc-${vmid}-\"*.tar.zst || \"$payload_name\" == \"vzdump-qemu-${vmid}-\"*.vma.zst ]] || die \"RESTORE_PAYLOAD_NAME_INVALID_$vmid\" 70"},{"line":123,"text":"work=\"$RESTORE_WORK_ROOT/$logical/$gen\"; if [[ -e \"$work\" ]]; then [[ -d \"$work\" && ! -L \"$work\" ]] || die \"RESTORE_WORK_UNSAFE_$vmid\" 70; rm -rf --one-file-system \"$work\"; fi; mkdir -p \"$work\"; chmod 0700 \"$RESTORE_WORK_ROOT\" \"$RESTORE_WORK_ROOT/$logical\" \"$work\"; ACTIVE_RESTORE_STAGE=\"$work\""},{"line":124,"text":"base=\"$(prepare_cloud_a_manifest \"$vmid\" \"$gen\" \"$state\" \"$work\")\"; manifest=\"$work/PARTS.tsv\"; fifo=\"$work/archive.sha.fifo\"; sha_out=\"$work/archive.sha256\"; mkfifo -m 0600 \"$fifo\""},{"line":127,"text":"members=\"$work/members.txt\"; if stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | tee \"$fifo\" | zstd -dc | tar -tf - >\"$members\"; then pipe_rc=0; else pipe_rc=$?; fi"},{"line":129,"text":"if stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | tee \"$fifo\" | zstd -t - >/dev/null; then pipe_rc=0; else pipe_rc=$?; fi"},{"line":132,"text":"(( pipe_rc == 0 && sha_rc == 0 )) || die \"RESTORE_A_STREAM_VALIDATION_FAILED_${vmid}_${pipe_rc}_${sha_rc}\" 70"},{"line":133,"text":"actual_sha=\"$(awk 'NR==1{print $1}' \"$sha_out\")\"; [[ \"$actual_sha\" == \"$expected_sha\" ]] || die \"RESTORE_A_PAYLOAD_SHA_MISMATCH_$vmid\" 70"},{"line":136,"text":"[[ -s \"$members\" ]] || die \"RESTORE_LXC_ARCHIVE_EMPTY_$vmid\" 70"},{"line":137,"text":"awk '$0 ~ /^\\// || $0 ~ /(^|\\/)\\.\\.(\\/|$)/ {bad=1} END{exit bad}' \"$members\" || die \"RESTORE_LXC_MEMBER_UNSAFE_$vmid\" 70"},{"line":138,"text":"member_count=\"$(wc -l <\"$members\")\"; [[ \"$member_count\" =~ ^[1-9][0-9]*$ ]] || die \"RESTORE_LXC_MEMBER_COUNT_INVALID_$vmid\" 70"},{"line":139,"text":"cfg_member=\"$(awk '$0==\"./etc/vzdump/pct.conf\" || $0==\"etc/vzdump/pct.conf\" {print; exit}' \"$members\")\"; [[ -n \"$cfg_member\" ]] || die \"RESTORE_LXC_CONFIG_MEMBER_MISSING_$vmid\" 70"},{"line":140,"text":"if ( set +o pipefail; stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | zstd -dc | tar -xOf - \"$cfg_member\" >\"$config\" ); then :; else die \"RESTORE_LXC_CONFIG_EXTRACT_FAILED_$vmid\" 70; fi"},{"line":143,"text":"if ( set +o pipefail; stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | zstd -dc | vma config - >\"$config\" ); then :; else die \"RESTORE_QEMU_CONFIG_EXTRACT_FAILED_$vmid\" 70; fi"},{"line":146,"text":"[[ -s \"$config\" && ! -L \"$config\" ]] || die \"RESTORE_CONFIG_EMPTY_$vmid\" 70; config_sha=\"$(sha256sum \"$config\"|awk '{print $1}')\""},{"line":147,"text":"out=\"$(restore_dir \"$vmid\")/$gen.json\"; mkdir -p \"$(dirname \"$out\")\"; chmod 0700 \"$RESTORE_STATE_ROOT\" \"$(dirname \"$out\")\"; tmp=\"${out}.new.$$\""},{"line":148,"text":"jq -n --arg logical \"$logical\" --arg generation \"$gen\" --argjson vmid \"$vmid\" --arg vm_type \"$VM_TYPE\" --arg state \"$state\" --arg sha \"$expected_sha\" --arg config_sha \"$config_sha\" --arg level \"$level\" --argjson member_count \"$member_count\" --arg at \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" '{schema:\"homelab-vm-restore-validation-v1\",logical_id:$logical,generation:$generation,vmid:$vmid,vm_type:$vm_type,transport_state:\"SEALED\",transport_state_file:$state,restore_source:\"Cloud A\",parts_manifest_verified:true,payload_sha256:$sha,payload_sha256_verified:true,payload_decompression_verified:true,proxmox_config_extract_verified:true,proxmox_config_sha256:$config_sha,lxc_member_count:$member_count,archive_recovery_readback_verified:true,bounded_staging:true,max_staged_part_bytes:536870912,full_local_payload_written:false,full_restore_proven:false,validation_level:$level,result:\"OK\",validated_at_utc:$at}' >\"$tmp\""},{"line":149,"text":"chmod 0600 \"$tmp\"; mv -f -- \"$tmp\" \"$out\"; rm -rf --one-file-system \"$work\"; ACTIVE_RESTORE_STAGE=\"\""},{"line":150,"text":"restore_ok \"$vmid\" \"$gen\" || die \"RESTORE_EVIDENCE_POSTWRITE_INVALID_$vmid\" 70"},{"line":151,"text":"printf 'RESTORE_VALIDATION_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$out\""},{"line":154,"text":"local vmid=\"$1\" owner type status"},{"line":155,"text":"assert_local_identity \"$vmid\""},{"line":156,"text":"owner=\"$(expected_owner \"$vmid\")\""},{"line":157,"text":"type=\"$(expected_type \"$vmid\")\""},{"line":158,"text":"status=\"$(expected_status \"$vmid\")\""},{"line":159,"text":"printf 'PLAN_STATUS=OK\\nVMID=%s\\nOWNER=%s\\nTYPE=%s\\nEXPECTED_STATUS=%s\\n' \"$vmid\" \"$owner\" \"$type\" \"$status\""},{"line":162,"text":"local vmid=\"$1\" generation=\"$2\""},{"line":163,"text":"assert_local_identity \"$vmid\""},{"line":164,"text":"restore_validate \"$vmid\" \"$generation\""},{"line":165,"text":"assert_post_identity \"$vmid\" \"$VM_TYPE\""},{"line":166,"text":"printf 'VERIFY_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$generation\" \"$(restore_dir \"$vmid\")/$generation.json\""},{"line":168,"text":"backup_one(){"},{"line":169,"text":"local vmid=\"$1\" pending_count pending state generation payload gen_dir archive_count archive log_file before_status"},{"line":171,"text":"assert_local_identity \"$vmid\""},{"line":176,"text":"[[ -z \"$(active_backup_restore)\" ]] || die \"ACTIVE_BACKUP_RESTORE_PRESENT\" 75"},{"line":179,"text":"mapfile -t pending < <(latest_incomplete_state \"$vmid\")"},{"line":181,"text":"(( pending_count <= 1 )) || die \"MULTIPLE_INCOMPLETE_GENERATIONS_$vmid\" 65"},{"line":186,"text":"printf 'RESUME=YES\\nVMID=%s\\nGENERATION=%s\\nSTATE=%s\\n' \"$vmid\" \"$generation\" \"$state\""},{"line":187,"text":"\"$TRANSPORT\" backup-delete \"vm${vmid}\" \"$generation\" \"$payload\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\""},{"line":189,"text":"generation=\"vm${vmid}-${HOST}-$(date -u +%Y%m%dT%H%M%SZ)\""},{"line":190,"text":"gen_dir=\"$STAGE_ROOT/vm${vmid}/$generation\""},{"line":195,"text":"printf 'RESUME=NO\\nVMID=%s\\nGENERATION=%s\\n' \"$vmid\" \"$generation\""},{"line":202,"text":"if ! ( umask 0022; exec vzdump \"$vmid\" \"${vzdump_args[@]}\" ) >\"$log_file\" 2>&1; then"},{"line":204,"text":"die \"VZDUMP_FAILED_$vmid\" 70"},{"line":206,"text":"mapfile -t archives < <(find \"$gen_dir\" -maxdepth 1 -type f -name \"vzdump-*-${vmid}-*.zst\" -print)"},{"line":208,"text":"[[ \"$archive_count\" == \"1\" ]] || { rm -rf -- \"$gen_dir\"; die \"VZDUMP_ARCHIVE_COUNT_${vmid}_${archive_count}\" 70; }"},{"line":210,"text":"[[ -s \"$archive\" && ! -L \"$archive\" ]] || die \"VZDUMP_ARCHIVE_UNSAFE_$vmid\" 70"},{"line":212,"text":"\"$TRANSPORT\" backup-delete \"vm${vmid}\" \"$generation\" \"$archive\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\""},{"line":215,"text":"rmdir -- \"$STAGE_ROOT/vm${vmid}\" 2>/dev/null || true"},{"line":217,"text":"assert_post_identity \"$vmid\" \"$VM_TYPE\""},{"line":218,"text":"state=\"$STATE_ROOT/vm${vmid}/$generation.json\""},{"line":220,"text":"restore_validate \"$vmid\" \"$generation\""},{"line":221,"text":"printf 'BACKUP_STATUS=SEALED\\nVMID=%s\\nGENERATION=%s\\nOWNER=%s\\nTYPE=%s\\nPOST_STATUS=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$generation\" \"$HOST\" \"$VM_TYPE\" \"$(expected_status \"$vmid\")\" \"$(restore_dir \"$vmid\")/$generation.json\""},{"line":226,"text":"[[ -z \"$(active_backup_restore)\" ]] || die \"ACTIVE_BACKUP_RESTORE_PRESENT\" 75"},{"line":231,"text":"printf 'HOST_PREFLIGHT_STATUS=OK\\nHOST=%s\\nSTAGING_FREE_BYTES=%s\\nREMOTE_A_FREE_BYTES=%s\\nREMOTE_B_FREE_BYTES=%s\\nACTIVE_BACKUP_RESTORE=0\\n' \"$HOST\" \"$free\" \"$a_free\" \"$b_free\""},{"line":234,"text":"local vmid=\"$1\" dir latest gen"},{"line":235,"text":"assert_local_identity \"$vmid\"; dir=\"$STATE_ROOT/vm${vmid}\""},{"line":236,"text":"[[ -d \"$dir\" ]] || die \"STATE_DIR_MISSING_$vmid\" 65"},{"line":238,"text":"[[ -n \"$latest\" && -s \"$latest\" && ! -L \"$latest\" ]] || die \"LATEST_STATE_MISSING_$vmid\" 65"},{"line":239,"text":"jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .local_payload_present==false and .local_cleanup==\"OK\" and .seal_written==true' \"$latest\" >/dev/null || die \"LATEST_STATE_NOT_SEALED_$vmid\" 65"},{"line":240,"text":"gen=\"$(jq -er '.generation' \"$latest\")\"; restore_ok \"$vmid\" \"$gen\" || die \"LATEST_RESTORE_NOT_OK_$vmid\" 65"},{"line":241,"text":"printf 'LATEST_SEALED_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nSTATE_FILE=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$latest\" \"$(restore_dir \"$vmid\")/$gen.json\""},{"line":244,"text":"case \"$ACTION\" in"},{"line":246,"text":"[[ \"$#\" == 1 ]] || die \"USAGE_HOST_PREFLIGHT\" 64"},{"line":249,"text":"latest-sealed)"},{"line":250,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_LATEST_SEALED\" 64"},{"line":254,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_PLAN\" 64"},{"line":257,"text":"backup)"},{"line":258,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_BACKUP\" 64"},{"line":259,"text":"backup_one \"$2\""},{"line":261,"text":"restore-validate)"},{"line":262,"text":"[[ \"$#\" == 3 ]] || die \"USAGE_RESTORE_VALIDATE\" 64"},{"line":263,"text":"restore_validate \"$2\" \"$3\""},{"line":266,"text":"[[ \"$#\" == 3 ]] || die \"USAGE_VERIFY\" 64"}] +NODEWORKER_CLI_CANDIDATES=[{"kind":"dispatch","text":"case \"$1\" in"},{"kind":"subcommand-token","text":"backup"},{"kind":"subcommand-token","text":"restore"},{"kind":"subcommand-token","text":"latest-sealed"}] +DECISION=DIRECT_NODEWORKER_TARGETED_BACKUP_CLI_DISCOVERED +NO_MUTATION=true +TASK_RESULT=PASS_HOMELAB_BACKUP_NODEWORKER_CONTRACT_RCA_READONLY +HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} +WORKERS2_NODEWORKER_CONTRACT_RCA_END=1 + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index 5c2abfc8..a3628369 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1", + "command_id": "SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", - "component": "homelab-backup-scheduler-contract-rca", - "started_at_utc": "2026-09-21T20:58:11Z", - "finished_at_utc": "2026-09-21T20:58:11Z", + "component": "homelab-backup-nodeworker-contract-rca", + "started_at_utc": "2026-09-21T21:06:14Z", + "finished_at_utc": "2026-09-21T21:06:14Z", "reference_register_checked": true, "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", "error_register_checked": true, "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", - "command_sha256": "03f74f4f55da06e3cb0f9a99977974ef5f7a54cf444a6d81d92957823f7e8f08", + "command_sha256": "476f69ce1ba9062cf703c5b1de5f81404fc50b1b31240c36e2e6ecdcd7aebecc", "duplicate_failed_command_blocked": false, "block_reason": null, "execution_started": true, @@ -30,9 +30,9 @@ "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "a0a1f31643f6b251d01109ba03b14ffd330a1bb432b6481e2854ccd40bf40b83", - "sanitized_output_sha256": "a0a1f31643f6b251d01109ba03b14ffd330a1bb432b6481e2854ccd40bf40b83", + "raw_evidence_sha256": "6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052", + "sanitized_output_sha256": "6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "WORKERS2_SCHEDULER_CONTRACT_RCA_BEGIN=1\nCOMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1\nMODE=read-only\nCOMPONENT=homelab-backup-scheduler-contract-rca\nMUTATION_BOUNDARY=READ_ONLY_NO_SERVICE_START_NO_TIMER_CHANGE_NO_KILL_NO_SIGNAL_NO_LOCK_BREAK_NO_BACKUP_NO_GC_NO_MAIL_NO_GIT_WRITE\nSOURCE_FILES=[{\"path\":\"/etc/systemd/system/homelab-backup-v2.service\",\"sha256\":\"1ef3e6bc660767a1f29a6a0bfa8d1b7a2419370b2250764ca181c34c93188565\",\"size\":309},{\"path\":\"/usr/local/sbin/homelab-backup-v2\",\"sha256\":\"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2\",\"size\":1656},{\"path\":\"/usr/local/libexec/homelab-backup-target-registry\",\"sha256\":\"c681c44be7557d192d7b453b67e31164237874596168f1d4c78e1e926e2e9cb4\",\"size\":4406},{\"path\":\"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker\",\"sha256\":\"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1\",\"size\":17702},{\"path\":\"/usr/local/libexec/homelab-cloud-quorum-payload\",\"sha256\":\"df9e19485e5d87112bf58bf77bdddf3b9b896418dd85ff945a31cd5b6817f352\",\"size\":38039}]\nSCHEDULER_LOGIC_HITS=[{\"file\":\"/etc/systemd/system/homelab-backup-v2.service\",\"line\":2,\"text\":\"Description=Homelab Backup V2 manifest-driven scheduler\"},{\"file\":\"/etc/systemd/system/homelab-backup-v2.service\",\"line\":3,\"text\":\"After=network-online.target\"},{\"file\":\"/etc/systemd/system/homelab-backup-v2.service\",\"line\":4,\"text\":\"Wants=network-online.target\"},{\"file\":\"/etc/systemd/system/homelab-backup-v2.service\",\"line\":11,\"text\":\"ExecStart=/usr/local/sbin/homelab-backup-v2 scheduled\"},{\"file\":\"/etc/systemd/system/homelab-backup-v2.service\",\"line\":14,\"text\":\"IOSchedulingPriority=7\"},{\"file\":\"/usr/local/sbin/homelab-backup-v2\",\"line\":5,\"text\":\"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":4,\"text\":\"REGISTRY=\\\"${HOMELAB_BACKUP_TARGET_REGISTRY:-/etc/homelab-backup/targets.json}\\\"\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":5,\"text\":\"die(){ printf 'TARGET_REGISTRY_ERROR=%s\\\\n' \\\"$1\\\" >&2; exit \\\"${2:-65}\\\"; }\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":10,\"text\":\".schema==\\\"homelab-backup-target-registry-v1\\\" and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":13,\"text\":\".policies.freshness_seconds.VM==72000 and .policies.freshness_seconds.APP==72000 and .policies.freshness_seconds.CONTROL==86400 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":14,\"text\":\"(.targets|type)==\\\"array\\\" and (.targets|length)==21 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":15,\"text\":\"([.targets[].id]|length)==([.targets[].id]|unique|length) and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":16,\"text\":\"([.targets[].logical_id]|length)==([.targets[].logical_id]|unique|length) and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":17,\"text\":\"([.targets[]|select(.kind==\\\"VM\\\" and .lifecycle==\\\"ACTIVE\\\")]|length)==11 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":18,\"text\":\"([.targets[]|select(.kind==\\\"APP\\\" and .lifecycle==\\\"ACTIVE\\\")]|length)==4 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":19,\"text\":\"([.targets[]|select(.kind==\\\"APP\\\" and .lifecycle==\\\"RETIRED_PRESERVE\\\")]|length)==3 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":20,\"text\":\"([.targets[]|select(.kind==\\\"CONTROL\\\" and .lifecycle==\\\"ACTIVE\\\")]|length)==1 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":21,\"text\":\"([.targets[]|select((.kind!=\\\"VM\\\" and .kind!=\\\"APP\\\" and .kind!=\\\"CONTROL\\\") or (.lifecycle!=\\\"ACTIVE\\\" and .lifecycle!=\\\"RETIRED_PRESERVE\\\"))]|length)==0 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":22,\"text\":\"([.targets[]|select(.kind==\\\"VM\\\")|select(.owner!=\\\"pve01\\\" and .owner!=\\\"pve02\\\" and .owner!=\\\"pve03\\\")]|length)==0 and\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":27,\"text\":\"rows(){ validate; jq -r '.targets[]|[.kind,.id,.logical_id,.owner,.lifecycle,(.source_host//\\\"\\\"),((.migrate//false)|tostring)]|@tsv' \\\"$REGISTRY\\\"; }\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":28,\"text\":\"find_by_id(){ local kind=\\\"$1\\\" id=\\\"$2\\\"; validate; jq -er --arg k \\\"$kind\\\" --arg i \\\"$id\\\" '.targets[]|select(.kind==$k and .id==$i)' \\\"$REGISTRY\\\"; }\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":29,\"text\":\"find_by_logical(){ local logical=\\\"$1\\\"; validate; jq -er --arg l \\\"$logical\\\" '.targets[]|select(.logical_id==$l)' \\\"$REGISTRY\\\"; }\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":31,\"text\":\"validate) [[ \\\"$#\\\" == 1 ]] || die USAGE 64; validate; printf 'TARGET_REGISTRY=OK\\\\n' ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":32,\"text\":\"active-vm-ids) [[ \\\"$#\\\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\\\"VM\\\" and .lifecycle==\\\"ACTIVE\\\")|.id' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":33,\"text\":\"active-app-ids) [[ \\\"$#\\\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\\\"APP\\\" and .lifecycle==\\\"ACTIVE\\\")|.id' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":34,\"text\":\"migrate-app-ids) [[ \\\"$#\\\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\\\"APP\\\" and .lifecycle==\\\"ACTIVE\\\" and .migrate==true)|.id' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":35,\"text\":\"app-active) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; find_by_id APP \\\"$2\\\" | jq -e '.lifecycle==\\\"ACTIVE\\\"' >/dev/null ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":36,\"text\":\"app-logical) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; find_by_id APP \\\"$2\\\" | jq -er 'select(.lifecycle==\\\"ACTIVE\\\")|.logical_id' ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":37,\"text\":\"app-source-host) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; find_by_id APP \\\"$2\\\" | jq -er 'select(.lifecycle==\\\"ACTIVE\\\")|.source_host' ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":39,\"text\":\"lifecycle) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; find_by_logical \\\"$2\\\" | jq -er '.lifecycle' ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":40,\"text\":\"retention-logicals) [[ \\\"$#\\\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.lifecycle==\\\"ACTIVE\\\" or .lifecycle==\\\"RETIRED_PRESERVE\\\")|.logical_id' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":41,\"text\":\"retention-keep) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; rec=\\\"$(find_by_logical \\\"$2\\\")\\\"; life=\\\"$(jq -r '.lifecycle' <<<\\\"$rec\\\")\\\"; [[ \\\"$life\\\" == ACTIVE ]] || die RETENTION_KEEP_NOT_ACTIVE 64; kind=\\\"$(jq -r '.kind' <<<\\\"$rec\\\")\\\"; jq -er --arg k \\\"$kind\\\" '.policies.retention_keep[$k]' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":43,\"text\":\"freshness-seconds) [[ \\\"$#\\\" == 2 ]] || die USAGE 64; validate; jq -er --arg k \\\"$2\\\" '.policies.freshness_seconds[$k]' \\\"$REGISTRY\\\" ;;\"},{\"file\":\"/usr/local/libexec/homelab-backup-target-registry\",\"line\":46,\"text\":\"*) die USAGE_validate_active-vm-ids_active-app-ids_migrate-app-ids_app-active_app-logical_app-source-host_logical-owner_lifecycle_retention-logicals_retention-keep_policy-keep_freshness-seconds_systemd-expectations_rows 64 ;;\"},{\"file\":\"/usr/local/libexec/homelab-cloud-quorum-payload\",\"line\":403,\"text\":\"if ! awk -v target=\\\"$LOGICAL_ID/\\\" '$0==target{found=1} END{exit !found}' \\\"$root_listing\\\"; then\"},{\"file\":\"/usr/local/libexec/homelab-cloud-quorum-payload\",\"line\":410,\"text\":\"if awk -v target=\\\"$GENERATION/\\\" '$0==target{found=1} END{exit !found}' \\\"$logical_listing\\\"; then\"}]\nTARGET_CONTRACT_ROWS=[{\"id\":\"110\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm110\"},{\"id\":\"111\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm111\"},{\"id\":\"112\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm112\"},{\"id\":\"113\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm113\"},{\"id\":\"130\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm130\"},{\"id\":\"150\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm150\"},{\"id\":\"160\",\"kind\":\"VM\",\"lifecycle\":\"ACTIVE\",\"logical_id\":\"vm160\"}]\nCURRENT_VM_STATE_ROWS=[{\"age_seconds\":1783,\"exists\":true,\"last_attempt_epoch\":1790022508,\"last_success_epoch\":1790022508,\"replica_count\":2,\"resource_type\":\"lxc\",\"result\":\"SUCCESS\",\"state_id\":\"ct110\",\"vmid\":\"110\"},{\"age_seconds\":1636,\"exists\":true,\"last_attempt_epoch\":1790022655,\"last_success_epoch\":1790022655,\"replica_count\":2,\"resource_type\":\"lxc\",\"result\":\"SUCCESS\",\"state_id\":\"ct111\",\"vmid\":\"111\"},{\"age_seconds\":83215,\"exists\":true,\"last_attempt_epoch\":1789941076,\"last_success_epoch\":1789941076,\"replica_count\":2,\"resource_type\":\"lxc\",\"result\":\"SUCCESS\",\"state_id\":\"ct112\",\"vmid\":\"112\"},{\"age_seconds\":81050,\"exists\":true,\"last_attempt_epoch\":1789943241,\"last_success_epoch\":1789943241,\"replica_count\":2,\"resource_type\":\"lxc\",\"result\":\"SUCCESS\",\"state_id\":\"ct113\",\"vmid\":\"113\"},{\"age_seconds\":75658,\"exists\":true,\"last_attempt_epoch\":1789948633,\"last_success_epoch\":1789948633,\"replica_count\":2,\"resource_type\":\"qemu\",\"result\":\"SUCCESS\",\"state_id\":\"vm130\",\"vmid\":\"130\"},{\"age_seconds\":78944,\"exists\":true,\"last_attempt_epoch\":1789945347,\"last_success_epoch\":1789945347,\"replica_count\":2,\"resource_type\":\"qemu\",\"result\":\"SUCCESS\",\"state_id\":\"vm150\",\"vmid\":\"150\"},{\"age_seconds\":74191,\"exists\":true,\"last_attempt_epoch\":1789950100,\"last_success_epoch\":1789950100,\"replica_count\":2,\"resource_type\":\"qemu\",\"result\":\"SUCCESS\",\"state_id\":\"vm160\",\"vmid\":\"160\"}]\nREGISTRY_VM_FRESHNESS={\"lines\":[\"72000\",\"\"],\"rc\":0}\nREGISTRY_HELP={\"lines\":[\"\",\"TARGET_REGISTRY_ERROR=USAGE_validate_active-vm-ids_active-app-ids_migrate-app-ids_app-active_app-logical_app-source-host_logical-owner_lifecycle_retention-logicals_retention-keep_policy-keep_freshness-seconds_systemd-expectations_rows\"],\"rc\":64}\nDECISIVE_JOURNAL=[\"SCHEDULE_TARGET=xf-codevipe\",\"SCHEDULE_RESULT=SUCCESS\",\"homelab-backup-v2.service: Deactivated successfully.\",\"SCHEDULE_TARGET=xf-zakrutim\",\"SCHEDULE_RESULT=SUCCESS\",\"homelab-backup-v2.service: Deactivated successfully.\",\"INFO: starting new backup job: vzdump 110 --remove 0 --prune-backups 'keep-all=1' --compress zstd --tmpdir /var/tmp/homelab-vzdump-v2-v2-ct110-20260921T202514Z-1c872adccfab --mode snapshot --stdexcludes 0 --bwlimit 32768 --ionice 7 --node pve01 --zstd 1 --lockwait 0\",\"INFO: Backup job finished successfully\",\"notified via target `mail-to-root`\",\"SCHEDULE_TARGET=ct110\",\"SCHEDULE_RESULT=SUCCESS\",\"homelab-backup-v2.service: Deactivated successfully.\",\"SCHEDULE_TARGET=ct111\",\"SCHEDULE_RESULT=SUCCESS\",\"homelab-backup-v2.service: Deactivated successfully.\",\"SCHEDULE_DECISION=DEFER_NO_DUE_TARGET\",\"homelab-backup-v2.service: Deactivated successfully.\",\"SCHEDULE_DECISION=DEFER_NO_DUE_TARGET\",\"homelab-backup-v2.service: Deactivated successfully.\",\"SCHEDULE_DECISION=DEFER_NO_DUE_TARGET\",\"homelab-backup-v2.service: Deactivated successfully.\"]\nDECISION=SCHEDULER_ELIGIBILITY_FILTER_DIFFERS_FROM_RPO_SET\nNO_MUTATION=true\nTASK_RESULT=PASS_HOMELAB_BACKUP_SCHEDULER_CONTRACT_RCA_READONLY\nHOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\nWORKERS2_SCHEDULER_CONTRACT_RCA_END=1\n" + "output": "WORKERS2_NODEWORKER_CONTRACT_RCA_BEGIN=1\nCOMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1\nMODE=read-only\nCOMPONENT=homelab-backup-nodeworker-contract-rca\nMUTATION_BOUNDARY=READ_ONLY_NO_EXECUTION_OF_BACKUP_WORKERS_NO_SERVICE_START_NO_TIMER_CHANGE_NO_LOCK_BREAK_NO_GIT_WRITE\nWRAPPER_INFO={\"logic\":[{\"line\":4,\"text\":\"ACCEPTED=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b')\"},{\"line\":5,\"text\":\"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}\"}],\"path\":\"/usr/local/sbin/homelab-backup-v2\",\"sha256\":\"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2\",\"size\":1656}\nHASH_MATCHED_HELPERS={\"entry504.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"sha256\":\"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\",\"size\":10566},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"sha256\":\"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\",\"size\":10566}],\"fresh_lxc_helper.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\",\"sha256\":\"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\",\"size\":2320}],\"lxc_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\",\"sha256\":\"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\",\"size\":13825}],\"producer_exec_helper.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"sha256\":\"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\",\"size\":3449}],\"qemu_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"sha256\":\"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\",\"size\":4627}],\"scheduler_adapter.py\":[{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"sha256\":\"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\",\"size\":4097},{\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"sha256\":\"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\",\"size\":4097}]}\nHELPER_LOGIC_HITS={\"entry504.py\":[{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\"},{\"line\":64,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"'choose_due_target','write_state','epoch')\"},{\"line\":78,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\"},{\"line\":79,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\"},{\"line\":80,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced.\"},{\"line\":89,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper.selftest()\"},{\"line\":93,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_adapter=importlib.import_module('scheduler_adapter')\"},{\"line\":96,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\"},{\"line\":97,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\"},{\"line\":99,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _target(wrapper,lid):\"},{\"line\":100,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\"},{\"line\":101,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\"},{\"line\":104,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def selftest():\"},{\"line\":105,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":108,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\"},{\"line\":109,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\"},{\"line\":110,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\"},{\"line\":111,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_WRITE_BINDING')\"},{\"line\":112,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\"},{\"line\":113,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\"},{\"line\":114,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\"},{\"line\":116,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SELFTEST_OVERLAY504=PASS',flush=True)\"},{\"line\":120,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"argv=list(sys.argv[1:] if argv is None else argv)\"},{\"line\":121,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['selftest']:\"},{\"line\":122,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return selftest()\"},{\"line\":123,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":125,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-proof']:\"},{\"line\":129,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\"},{\"line\":132,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\"},{\"line\":141,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\"},{\"line\":142,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"first=legacy.choose_due_target(targets,state,now[0])\"},{\"line\":143,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\"},{\"line\":146,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\"},{\"line\":148,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\"},{\"line\":149,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\"},{\"line\":153,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\"},{\"line\":154,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}\"},{\"line\":155,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":159,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-select-live']:\"},{\"line\":160,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"state=legacy.load_state_all(); targets=wrapper.load_targets()\"},{\"line\":161,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"chosen=legacy.choose_due_target(targets,state)\"},{\"line\":163,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\"},{\"line\":165,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":167,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='plan-lxc':\"},{\"line\":168,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":169,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":170,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\"},{\"line\":172,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":174,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='verify-target':\"},{\"line\":175,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":176,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":179,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"out=wrapper.backup_target(t,True)\"},{\"line\":180,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"except legacy.BackupError as e:\"},{\"line\":181,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT=FAIL',flush=True)\"},{\"line\":182,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\"},{\"line\":184,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":186,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper.main([sys.argv[0],*argv])\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\"},{\"line\":64,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"'choose_due_target','write_state','epoch')\"},{\"line\":78,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\"},{\"line\":79,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\"},{\"line\":80,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced.\"},{\"line\":89,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper.selftest()\"},{\"line\":93,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"scheduler_adapter=importlib.import_module('scheduler_adapter')\"},{\"line\":96,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\"},{\"line\":97,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\"},{\"line\":99,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def _target(wrapper,lid):\"},{\"line\":100,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\"},{\"line\":101,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\"},{\"line\":104,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"def selftest():\"},{\"line\":105,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":108,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\"},{\"line\":109,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\"},{\"line\":110,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\"},{\"line\":111,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_WRITE_BINDING')\"},{\"line\":112,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\"},{\"line\":113,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\"},{\"line\":114,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\"},{\"line\":116,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SELFTEST_OVERLAY504=PASS',flush=True)\"},{\"line\":120,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"argv=list(sys.argv[1:] if argv is None else argv)\"},{\"line\":121,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['selftest']:\"},{\"line\":122,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return selftest()\"},{\"line\":123,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\"},{\"line\":125,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-proof']:\"},{\"line\":129,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\"},{\"line\":132,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\"},{\"line\":141,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\"},{\"line\":142,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"first=legacy.choose_due_target(targets,state,now[0])\"},{\"line\":143,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\"},{\"line\":146,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\"},{\"line\":148,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\"},{\"line\":149,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\"},{\"line\":153,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\"},{\"line\":154,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}\"},{\"line\":155,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":159,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if argv==['scheduler-select-live']:\"},{\"line\":160,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"state=legacy.load_state_all(); targets=wrapper.load_targets()\"},{\"line\":161,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"chosen=legacy.choose_due_target(targets,state)\"},{\"line\":163,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\"},{\"line\":165,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":167,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='plan-lxc':\"},{\"line\":168,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":169,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":170,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\"},{\"line\":172,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":174,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if len(argv)==2 and argv[0]=='verify-target':\"},{\"line\":175,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"t=_target(wrapper,argv[1])\"},{\"line\":176,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"if t.get('logical_id')=='guest-pve01-lxc-112':\"},{\"line\":179,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"out=wrapper.backup_target(t,True)\"},{\"line\":180,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"except legacy.BackupError as e:\"},{\"line\":181,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT=FAIL',flush=True)\"},{\"line\":182,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\"},{\"line\":184,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\"},{\"line\":186,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\",\"text\":\"return wrapper.main([sys.argv[0],*argv])\"}],\"fresh_lxc_helper.py\":[{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')\"},{\"line\":15,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if len(sys.argv)!=1: fail('HELPER_ARGC')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')\"},{\"line\":27,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')\"},{\"line\":30,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')\"},{\"line\":37,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"guest266.no_active_tasks(raw.get('tasks'),vmid)\"},{\"line\":39,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py\",\"text\":\"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')\"}],\"lxc_adapter.py\":[{\"line\":2,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"import base64, hashlib, json, os, pathlib, re, selectors, shlex, signal, stat, subprocess, sys, time\"},{\"line\":6,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"HELPER=pathlib.Path(__file__).resolve().parent/'fresh_lxc_helper.py'\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"def _live_inputs(legacy,node,vmid,scratch):\"},{\"line\":42,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue\"},{\"line\":50,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"try: rid=int(r.get('vmid'))\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"except Exception: raise AdapterError('RESOURCE_VMID')\"},{\"line\":52,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\\\"type\\\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py\",\"text\":\"_need(0int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"def selftest()->int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"},{\"line\":4,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')\"},{\"line\":26,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"def selftest()->int:\"},{\"line\":31,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\"},{\"line\":35,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]==['selftest']: return selftest()\"},{\"line\":36,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if sys.argv[1:]: fail('ARGC')\"},{\"line\":41,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if not (type(argv) is list and argv and all(type(v) is str and '\\\\x00' not in v for v in argv)): fail('ARGV')\"},{\"line\":44,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\",\"text\":\"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\"}],\"qemu_adapter.py\":[{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"},{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"},{\"line\":11,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _remote_sha(legacy,node,path):\"},{\"line\":12,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\"},{\"line\":17,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"def _select_qemu_outputs(vmid,files):\"},{\"line\":18,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(type(vmid) is int and vmid>0,'QEMU_VMID')\"},{\"line\":21,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\\\d{4}_\\\\d{2}_\\\\d{2}-\\\\d{2}_\\\\d{2}_\\\\d{2})\\\\.vma\\\\.zst$')\"},{\"line\":29,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\"},{\"line\":43,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]\"},{\"line\":45,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"row=rows[0]; node=row.get('node'); typ=row.get('type')\"},{\"line\":47,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\"},{\"line\":49,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\"},{\"line\":51,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\"},{\"line\":53,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)\"},{\"line\":54,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError('QEMU_VZDUMP_FAILED')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\"},{\"line\":56,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\\\n'],timeout=30)\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"try: src,log=_select_qemu_outputs(vmid,files)\"},{\"line\":60,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"raise legacy.BackupError(str(e)) from None\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\"},{\"line\":67,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"if node=='pve01': local=pathlib.Path(src)\"},{\"line\":69,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\"},{\"line\":74,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py\",\"text\":\"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\"}],\"scheduler_adapter.py\":[{\"line\":7,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"class SchedulerAdapterError(RuntimeError): pass\"},{\"line\":10,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not ok: raise SchedulerAdapterError(code)\"},{\"line\":23,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def _read_prior(legacy,logical_id):\"},{\"line\":25,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"p=root/(str(logical_id)+'.json')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def choose_due_target(targets,state,now=None):\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due=[]\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"for order,t in enumerate(targets):\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\"},{\"line\":70,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"overdue=age-seconds\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due.append((overdue,-order,t))\"},{\"line\":72,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not due: return None\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return max(due,key=lambda x:(x[0],x[1]))[2]\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def write_state(logical_id,result,**kw):\"},{\"line\":77,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"prior=_read_prior(legacy,logical_id)\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":90,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"legacy.choose_due_target=choose_due_target\"},{\"line\":92,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return {'choose_due_target':choose_due_target,'write_state':write_state,\"},{\"line\":7,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"class SchedulerAdapterError(RuntimeError): pass\"},{\"line\":10,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not ok: raise SchedulerAdapterError(code)\"},{\"line\":23,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def _read_prior(legacy,logical_id):\"},{\"line\":25,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"p=root/(str(logical_id)+'.json')\"},{\"line\":55,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def choose_due_target(targets,state,now=None):\"},{\"line\":57,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\"},{\"line\":58,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due=[]\"},{\"line\":59,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"for order,t in enumerate(targets):\"},{\"line\":61,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\"},{\"line\":62,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\"},{\"line\":70,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"overdue=age-seconds\"},{\"line\":71,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"due.append((overdue,-order,t))\"},{\"line\":72,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"if not due: return None\"},{\"line\":73,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return max(due,key=lambda x:(x[0],x[1]))[2]\"},{\"line\":75,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"def write_state(logical_id,result,**kw):\"},{\"line\":77,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"prior=_read_prior(legacy,logical_id)\"},{\"line\":81,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":88,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return original_write(logical_id,result,**clean)\"},{\"line\":90,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"legacy.choose_due_target=choose_due_target\"},{\"line\":92,\"path\":\"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\",\"text\":\"return {'choose_due_target':choose_due_target,'write_state':write_state,\"}]}\nNODEWORKER_INFO={\"path\":\"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker\",\"sha256\":\"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1\",\"size\":17702}\nNODEWORKER_LOGIC_HITS=[{\"line\":6,\"text\":\"STATE_ROOT=/var/lib/homelab-backup/cloud-quorum\"},{\"line\":8,\"text\":\"RESTORE_STATE_ROOT=/var/lib/homelab-backup/vm-restore-validation\"},{\"line\":9,\"text\":\"RESTORE_WORK_ROOT=/mnt/staging/homelab-vm-restore-validation\"},{\"line\":11,\"text\":\"REMOTE_A='pve01-mail-01-crypt:homelab-backups'\"},{\"line\":12,\"text\":\"REMOTE_B='pve01-mail-02-crypt:homelab-backups'\"},{\"line\":18,\"text\":\"ACTIVE_RESTORE_STAGE=\\\"\\\"\"},{\"line\":19,\"text\":\"cleanup_restore_stage(){ if [[ -n \\\"$ACTIVE_RESTORE_STAGE\\\" && \\\"$ACTIVE_RESTORE_STAGE\\\" == \\\"$RESTORE_WORK_ROOT\\\"/* && -d \\\"$ACTIVE_RESTORE_STAGE\\\" ]]; then rm -rf --one-file-system \\\"$ACTIVE_RESTORE_STAGE\\\"; fi; }\"},{\"line\":20,\"text\":\"trap cleanup_restore_stage EXIT\"},{\"line\":21,\"text\":\"active_backup_restore(){ local rc; if pgrep -af '(^|/)(vzdump|qmrestore|pctrestore|vma|zstd|rclone)([[:space:]]|$)'; then return 0; else rc=$?; [[ \\\"$rc\\\" == 1 ]] && return 0; die \\\"PGREP_FAILED_$rc\\\" 69; fi; }\"},{\"line\":24,\"text\":\"expected_owner(){\"},{\"line\":25,\"text\":\"case \\\"$1\\\" in\"},{\"line\":29,\"text\":\"*) die \\\"VMID_NOT_ALLOWED_$1\\\" 64 ;;\"},{\"line\":33,\"text\":\"case \\\"$1\\\" in\"},{\"line\":36,\"text\":\"*) die \\\"VMID_NOT_ALLOWED_$1\\\" 64 ;;\"},{\"line\":43,\"text\":\"local vmid=\\\"$1\\\" type=\\\"$2\\\"\"},{\"line\":44,\"text\":\"if [[ \\\"$type\\\" == \\\"qemu\\\" ]]; then qm status \\\"$vmid\\\" | awk '{print $2}'; else pct status \\\"$vmid\\\" | awk '{print $2}'; fi\"},{\"line\":47,\"text\":\"local vmid=\\\"$1\\\" owner type status expect_status\"},{\"line\":48,\"text\":\"owner=\\\"$(expected_owner \\\"$vmid\\\")\\\"\"},{\"line\":49,\"text\":\"type=\\\"$(expected_type \\\"$vmid\\\")\\\"\"},{\"line\":50,\"text\":\"[[ \\\"$HOST\\\" == \\\"$owner\\\" ]] || die \\\"OWNER_MISMATCH_${vmid}_${HOST}_EXPECTED_${owner}\\\" 65\"},{\"line\":52,\"text\":\"[[ -s \\\"/etc/pve/qemu-server/${vmid}.conf\\\" ]] || die \\\"QEMU_CONFIG_MISSING_$vmid\\\" 66\"},{\"line\":54,\"text\":\"[[ -s \\\"/etc/pve/lxc/${vmid}.conf\\\" ]] || die \\\"LXC_CONFIG_MISSING_$vmid\\\" 66\"},{\"line\":56,\"text\":\"status=\\\"$(current_status \\\"$vmid\\\" \\\"$type\\\")\\\"\"},{\"line\":57,\"text\":\"expect_status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":58,\"text\":\"[[ \\\"$status\\\" == \\\"$expect_status\\\" ]] || die \\\"STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\\\" 66\"},{\"line\":59,\"text\":\"if [[ \\\"$vmid\\\" == \\\"160\\\" ]]; then [[ \\\"$(snapshot_count_160)\\\" == \\\"0\\\" ]] || die \\\"VM160_SNAPSHOT_COUNT_CHANGED\\\" 66; fi\"},{\"line\":60,\"text\":\"if [[ \\\"$vmid\\\" == \\\"9130\\\" ]]; then [[ \\\"$(vm_lock 9130)\\\" == \\\"none\\\" ]] || die \\\"VM9130_LOCK_PRESENT\\\" 66; fi\"},{\"line\":65,\"text\":\"local vmid=\\\"$1\\\" type=\\\"$2\\\" status expect_status\"},{\"line\":66,\"text\":\"status=\\\"$(current_status \\\"$vmid\\\" \\\"$type\\\")\\\"\"},{\"line\":67,\"text\":\"expect_status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":68,\"text\":\"[[ \\\"$status\\\" == \\\"$expect_status\\\" ]] || die \\\"POST_STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\\\" 66\"},{\"line\":69,\"text\":\"if [[ \\\"$vmid\\\" == \\\"160\\\" ]]; then [[ \\\"$(snapshot_count_160)\\\" == \\\"0\\\" ]] || die \\\"VM160_SNAPSHOT_COUNT_CHANGED_POST\\\" 66; fi\"},{\"line\":70,\"text\":\"if [[ \\\"$vmid\\\" == \\\"9130\\\" ]]; then [[ \\\"$(vm_lock 9130)\\\" == \\\"none\\\" ]] || die \\\"VM9130_LOCK_PRESENT_POST\\\" 66; fi\"},{\"line\":73,\"text\":\"local vmid=\\\"$1\\\" dir=\\\"$STATE_ROOT/vm${vmid}\\\" f\"},{\"line\":79,\"text\":\"restore_dir(){ printf '%s\\\\n' \\\"$RESTORE_STATE_ROOT/vm$1\\\"; }\"},{\"line\":80,\"text\":\"restore_ok(){\"},{\"line\":81,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" f state sha\"},{\"line\":82,\"text\":\"f=\\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; state=\\\"$STATE_ROOT/vm${vmid}/$gen.json\\\"\"},{\"line\":85,\"text\":\"jq -e --arg l \\\"vm${vmid}\\\" --arg g \\\"$gen\\\" --arg s \\\"$state\\\" --arg sha \\\"$sha\\\" '.schema==\\\"homelab-vm-restore-validation-v1\\\" and .logical_id==$l and .generation==$g and .transport_state==\\\"SEALED\\\" and .transport_state_file==$s and .restore_source==\\\"Cloud A\\\" and .parts_manifest_verified==true and .payload_sha256==$sha and .payload_sha256_verified==true and .payload_decompression_verified==true and .proxmox_config_extract_verified==true and .archive_recovery_readback_verified==true and .bounded_staging==true and .full_local_payload_written==false and .full_restore_proven==false and .result==\\\"OK\\\"' \\\"$f\\\" >/dev/null\"},{\"line\":88,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" state=\\\"$3\\\" work=\\\"$4\\\" base manifest expected_msha got_msha expected_count expected_size idx name size psha count total\"},{\"line\":90,\"text\":\"[[ \\\"$base\\\" == \\\"${REMOTE_A%/}/vm${vmid}/$gen\\\" ]] || die \\\"RESTORE_A_BASE_MISMATCH_$vmid\\\" 70\"},{\"line\":92,\"text\":\"got_msha=\\\"$(sha256sum \\\"$manifest\\\"|awk '{print $1}')\\\"; [[ \\\"$got_msha\\\" == \\\"$expected_msha\\\" ]] || die \\\"RESTORE_A_MANIFEST_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":95,\"text\":\"[[ \\\"$idx\\\" =~ ^[0-9]{8}$ && \\\"$name\\\" == part-????????.bin && \\\"$size\\\" =~ ^[1-9][0-9]*$ && \\\"$psha\\\" =~ ^[0-9a-f]{64}$ ]] || die \\\"RESTORE_A_MANIFEST_ROW_INVALID_$vmid\\\" 70\"},{\"line\":96,\"text\":\"(( size <= 536870912 )) || die \\\"RESTORE_A_PART_EXCEEDS_BOUND_$vmid\\\" 70\"},{\"line\":97,\"text\":\"[[ \\\"$idx\\\" == \\\"$(printf '%08d' \\\"$count\\\")\\\" ]] || die \\\"RESTORE_A_MANIFEST_INDEX_INVALID_$vmid\\\" 70\"},{\"line\":100,\"text\":\"[[ \\\"$count\\\" == \\\"$expected_count\\\" ]] || die \\\"RESTORE_A_PART_COUNT_MISMATCH_$vmid\\\" 70\"},{\"line\":101,\"text\":\"[[ \\\"$total\\\" == \\\"$expected_size\\\" ]] || die \\\"RESTORE_A_MANIFEST_TOTAL_SIZE_MISMATCH_$vmid\\\" 70\"},{\"line\":105,\"text\":\"local vmid=\\\"$1\\\" base=\\\"$2\\\" manifest=\\\"$3\\\" work=\\\"$4\\\" idx name size psha part actual count\"},{\"line\":109,\"text\":\"[[ -s \\\"$part\\\" && ! -L \\\"$part\\\" && \\\"$(stat -c %s \\\"$part\\\")\\\" == \\\"$size\\\" ]] || die \\\"RESTORE_A_PART_SIZE_MISMATCH_$vmid\\\" 70\"},{\"line\":110,\"text\":\"actual=\\\"$(sha256sum \\\"$part\\\"|awk '{print $1}')\\\"; [[ \\\"$actual\\\" == \\\"$psha\\\" ]] || die \\\"RESTORE_A_PART_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":114,\"text\":\"restore_validate(){\"},{\"line\":115,\"text\":\"local vmid=\\\"$1\\\" gen=\\\"$2\\\" logical state work payload_name expected_sha expected_size base manifest fifo sha_out sha_pid pipe_rc sha_rc actual_sha config config_sha members member_count cfg_member level out tmp\"},{\"line\":116,\"text\":\"assert_local_identity \\\"$vmid\\\"; logical=\\\"vm${vmid}\\\"; state=\\\"$STATE_ROOT/$logical/$gen.json\\\"\"},{\"line\":117,\"text\":\"[[ -s \\\"$state\\\" && ! -L \\\"$state\\\" ]] || die \\\"RESTORE_STATE_MISSING_$vmid\\\" 65\"},{\"line\":118,\"text\":\"jq -e '.schema==\\\"homelab-cloud-quorum-payload-v1\\\" and .status==\\\"SEALED\\\" and .cloud_quorum==2 and .cloud_a_verified==true and .cloud_b_verified==true and .part_hashes_verified==true and .seal_written==true and .cloud_a_seal_verified==true and .cloud_b_seal_verified==true and .local_payload_present==false and .local_cleanup==\\\"OK\\\"' \\\"$state\\\" >/dev/null || die \\\"RESTORE_REQUIRES_STRICT_SEALED_$vmid\\\" 65\"},{\"line\":119,\"text\":\"if restore_ok \\\"$vmid\\\" \\\"$gen\\\"; then printf 'RESTORE_VALIDATION_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESULT=ALREADY_VALIDATED\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; return 0; fi\"},{\"line\":120,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die ACTIVE_BACKUP_RESTORE_PRESENT 75\"},{\"line\":122,\"text\":\"[[ \\\"$payload_name\\\" == \\\"vzdump-lxc-${vmid}-\\\"*.tar.zst || \\\"$payload_name\\\" == \\\"vzdump-qemu-${vmid}-\\\"*.vma.zst ]] || die \\\"RESTORE_PAYLOAD_NAME_INVALID_$vmid\\\" 70\"},{\"line\":123,\"text\":\"work=\\\"$RESTORE_WORK_ROOT/$logical/$gen\\\"; if [[ -e \\\"$work\\\" ]]; then [[ -d \\\"$work\\\" && ! -L \\\"$work\\\" ]] || die \\\"RESTORE_WORK_UNSAFE_$vmid\\\" 70; rm -rf --one-file-system \\\"$work\\\"; fi; mkdir -p \\\"$work\\\"; chmod 0700 \\\"$RESTORE_WORK_ROOT\\\" \\\"$RESTORE_WORK_ROOT/$logical\\\" \\\"$work\\\"; ACTIVE_RESTORE_STAGE=\\\"$work\\\"\"},{\"line\":124,\"text\":\"base=\\\"$(prepare_cloud_a_manifest \\\"$vmid\\\" \\\"$gen\\\" \\\"$state\\\" \\\"$work\\\")\\\"; manifest=\\\"$work/PARTS.tsv\\\"; fifo=\\\"$work/archive.sha.fifo\\\"; sha_out=\\\"$work/archive.sha256\\\"; mkfifo -m 0600 \\\"$fifo\\\"\"},{\"line\":127,\"text\":\"members=\\\"$work/members.txt\\\"; if stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | tee \\\"$fifo\\\" | zstd -dc | tar -tf - >\\\"$members\\\"; then pipe_rc=0; else pipe_rc=$?; fi\"},{\"line\":129,\"text\":\"if stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | tee \\\"$fifo\\\" | zstd -t - >/dev/null; then pipe_rc=0; else pipe_rc=$?; fi\"},{\"line\":132,\"text\":\"(( pipe_rc == 0 && sha_rc == 0 )) || die \\\"RESTORE_A_STREAM_VALIDATION_FAILED_${vmid}_${pipe_rc}_${sha_rc}\\\" 70\"},{\"line\":133,\"text\":\"actual_sha=\\\"$(awk 'NR==1{print $1}' \\\"$sha_out\\\")\\\"; [[ \\\"$actual_sha\\\" == \\\"$expected_sha\\\" ]] || die \\\"RESTORE_A_PAYLOAD_SHA_MISMATCH_$vmid\\\" 70\"},{\"line\":136,\"text\":\"[[ -s \\\"$members\\\" ]] || die \\\"RESTORE_LXC_ARCHIVE_EMPTY_$vmid\\\" 70\"},{\"line\":137,\"text\":\"awk '$0 ~ /^\\\\// || $0 ~ /(^|\\\\/)\\\\.\\\\.(\\\\/|$)/ {bad=1} END{exit bad}' \\\"$members\\\" || die \\\"RESTORE_LXC_MEMBER_UNSAFE_$vmid\\\" 70\"},{\"line\":138,\"text\":\"member_count=\\\"$(wc -l <\\\"$members\\\")\\\"; [[ \\\"$member_count\\\" =~ ^[1-9][0-9]*$ ]] || die \\\"RESTORE_LXC_MEMBER_COUNT_INVALID_$vmid\\\" 70\"},{\"line\":139,\"text\":\"cfg_member=\\\"$(awk '$0==\\\"./etc/vzdump/pct.conf\\\" || $0==\\\"etc/vzdump/pct.conf\\\" {print; exit}' \\\"$members\\\")\\\"; [[ -n \\\"$cfg_member\\\" ]] || die \\\"RESTORE_LXC_CONFIG_MEMBER_MISSING_$vmid\\\" 70\"},{\"line\":140,\"text\":\"if ( set +o pipefail; stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | zstd -dc | tar -xOf - \\\"$cfg_member\\\" >\\\"$config\\\" ); then :; else die \\\"RESTORE_LXC_CONFIG_EXTRACT_FAILED_$vmid\\\" 70; fi\"},{\"line\":143,\"text\":\"if ( set +o pipefail; stream_cloud_a \\\"$vmid\\\" \\\"$base\\\" \\\"$manifest\\\" \\\"$work\\\" | zstd -dc | vma config - >\\\"$config\\\" ); then :; else die \\\"RESTORE_QEMU_CONFIG_EXTRACT_FAILED_$vmid\\\" 70; fi\"},{\"line\":146,\"text\":\"[[ -s \\\"$config\\\" && ! -L \\\"$config\\\" ]] || die \\\"RESTORE_CONFIG_EMPTY_$vmid\\\" 70; config_sha=\\\"$(sha256sum \\\"$config\\\"|awk '{print $1}')\\\"\"},{\"line\":147,\"text\":\"out=\\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"; mkdir -p \\\"$(dirname \\\"$out\\\")\\\"; chmod 0700 \\\"$RESTORE_STATE_ROOT\\\" \\\"$(dirname \\\"$out\\\")\\\"; tmp=\\\"${out}.new.$$\\\"\"},{\"line\":148,\"text\":\"jq -n --arg logical \\\"$logical\\\" --arg generation \\\"$gen\\\" --argjson vmid \\\"$vmid\\\" --arg vm_type \\\"$VM_TYPE\\\" --arg state \\\"$state\\\" --arg sha \\\"$expected_sha\\\" --arg config_sha \\\"$config_sha\\\" --arg level \\\"$level\\\" --argjson member_count \\\"$member_count\\\" --arg at \\\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\\\" '{schema:\\\"homelab-vm-restore-validation-v1\\\",logical_id:$logical,generation:$generation,vmid:$vmid,vm_type:$vm_type,transport_state:\\\"SEALED\\\",transport_state_file:$state,restore_source:\\\"Cloud A\\\",parts_manifest_verified:true,payload_sha256:$sha,payload_sha256_verified:true,payload_decompression_verified:true,proxmox_config_extract_verified:true,proxmox_config_sha256:$config_sha,lxc_member_count:$member_count,archive_recovery_readback_verified:true,bounded_staging:true,max_staged_part_bytes:536870912,full_local_payload_written:false,full_restore_proven:false,validation_level:$level,result:\\\"OK\\\",validated_at_utc:$at}' >\\\"$tmp\\\"\"},{\"line\":149,\"text\":\"chmod 0600 \\\"$tmp\\\"; mv -f -- \\\"$tmp\\\" \\\"$out\\\"; rm -rf --one-file-system \\\"$work\\\"; ACTIVE_RESTORE_STAGE=\\\"\\\"\"},{\"line\":150,\"text\":\"restore_ok \\\"$vmid\\\" \\\"$gen\\\" || die \\\"RESTORE_EVIDENCE_POSTWRITE_INVALID_$vmid\\\" 70\"},{\"line\":151,\"text\":\"printf 'RESTORE_VALIDATION_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$out\\\"\"},{\"line\":154,\"text\":\"local vmid=\\\"$1\\\" owner type status\"},{\"line\":155,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":156,\"text\":\"owner=\\\"$(expected_owner \\\"$vmid\\\")\\\"\"},{\"line\":157,\"text\":\"type=\\\"$(expected_type \\\"$vmid\\\")\\\"\"},{\"line\":158,\"text\":\"status=\\\"$(expected_status \\\"$vmid\\\")\\\"\"},{\"line\":159,\"text\":\"printf 'PLAN_STATUS=OK\\\\nVMID=%s\\\\nOWNER=%s\\\\nTYPE=%s\\\\nEXPECTED_STATUS=%s\\\\n' \\\"$vmid\\\" \\\"$owner\\\" \\\"$type\\\" \\\"$status\\\"\"},{\"line\":162,\"text\":\"local vmid=\\\"$1\\\" generation=\\\"$2\\\"\"},{\"line\":163,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":164,\"text\":\"restore_validate \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":165,\"text\":\"assert_post_identity \\\"$vmid\\\" \\\"$VM_TYPE\\\"\"},{\"line\":166,\"text\":\"printf 'VERIFY_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$(restore_dir \\\"$vmid\\\")/$generation.json\\\"\"},{\"line\":168,\"text\":\"backup_one(){\"},{\"line\":169,\"text\":\"local vmid=\\\"$1\\\" pending_count pending state generation payload gen_dir archive_count archive log_file before_status\"},{\"line\":171,\"text\":\"assert_local_identity \\\"$vmid\\\"\"},{\"line\":176,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die \\\"ACTIVE_BACKUP_RESTORE_PRESENT\\\" 75\"},{\"line\":179,\"text\":\"mapfile -t pending < <(latest_incomplete_state \\\"$vmid\\\")\"},{\"line\":181,\"text\":\"(( pending_count <= 1 )) || die \\\"MULTIPLE_INCOMPLETE_GENERATIONS_$vmid\\\" 65\"},{\"line\":186,\"text\":\"printf 'RESUME=YES\\\\nVMID=%s\\\\nGENERATION=%s\\\\nSTATE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$state\\\"\"},{\"line\":187,\"text\":\"\\\"$TRANSPORT\\\" backup-delete \\\"vm${vmid}\\\" \\\"$generation\\\" \\\"$payload\\\" \\\"$REMOTE_A\\\" \\\"$REMOTE_B\\\" \\\"$STATE_ROOT\\\"\"},{\"line\":189,\"text\":\"generation=\\\"vm${vmid}-${HOST}-$(date -u +%Y%m%dT%H%M%SZ)\\\"\"},{\"line\":190,\"text\":\"gen_dir=\\\"$STAGE_ROOT/vm${vmid}/$generation\\\"\"},{\"line\":195,\"text\":\"printf 'RESUME=NO\\\\nVMID=%s\\\\nGENERATION=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":202,\"text\":\"if ! ( umask 0022; exec vzdump \\\"$vmid\\\" \\\"${vzdump_args[@]}\\\" ) >\\\"$log_file\\\" 2>&1; then\"},{\"line\":204,\"text\":\"die \\\"VZDUMP_FAILED_$vmid\\\" 70\"},{\"line\":206,\"text\":\"mapfile -t archives < <(find \\\"$gen_dir\\\" -maxdepth 1 -type f -name \\\"vzdump-*-${vmid}-*.zst\\\" -print)\"},{\"line\":208,\"text\":\"[[ \\\"$archive_count\\\" == \\\"1\\\" ]] || { rm -rf -- \\\"$gen_dir\\\"; die \\\"VZDUMP_ARCHIVE_COUNT_${vmid}_${archive_count}\\\" 70; }\"},{\"line\":210,\"text\":\"[[ -s \\\"$archive\\\" && ! -L \\\"$archive\\\" ]] || die \\\"VZDUMP_ARCHIVE_UNSAFE_$vmid\\\" 70\"},{\"line\":212,\"text\":\"\\\"$TRANSPORT\\\" backup-delete \\\"vm${vmid}\\\" \\\"$generation\\\" \\\"$archive\\\" \\\"$REMOTE_A\\\" \\\"$REMOTE_B\\\" \\\"$STATE_ROOT\\\"\"},{\"line\":215,\"text\":\"rmdir -- \\\"$STAGE_ROOT/vm${vmid}\\\" 2>/dev/null || true\"},{\"line\":217,\"text\":\"assert_post_identity \\\"$vmid\\\" \\\"$VM_TYPE\\\"\"},{\"line\":218,\"text\":\"state=\\\"$STATE_ROOT/vm${vmid}/$generation.json\\\"\"},{\"line\":220,\"text\":\"restore_validate \\\"$vmid\\\" \\\"$generation\\\"\"},{\"line\":221,\"text\":\"printf 'BACKUP_STATUS=SEALED\\\\nVMID=%s\\\\nGENERATION=%s\\\\nOWNER=%s\\\\nTYPE=%s\\\\nPOST_STATUS=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$generation\\\" \\\"$HOST\\\" \\\"$VM_TYPE\\\" \\\"$(expected_status \\\"$vmid\\\")\\\" \\\"$(restore_dir \\\"$vmid\\\")/$generation.json\\\"\"},{\"line\":226,\"text\":\"[[ -z \\\"$(active_backup_restore)\\\" ]] || die \\\"ACTIVE_BACKUP_RESTORE_PRESENT\\\" 75\"},{\"line\":231,\"text\":\"printf 'HOST_PREFLIGHT_STATUS=OK\\\\nHOST=%s\\\\nSTAGING_FREE_BYTES=%s\\\\nREMOTE_A_FREE_BYTES=%s\\\\nREMOTE_B_FREE_BYTES=%s\\\\nACTIVE_BACKUP_RESTORE=0\\\\n' \\\"$HOST\\\" \\\"$free\\\" \\\"$a_free\\\" \\\"$b_free\\\"\"},{\"line\":234,\"text\":\"local vmid=\\\"$1\\\" dir latest gen\"},{\"line\":235,\"text\":\"assert_local_identity \\\"$vmid\\\"; dir=\\\"$STATE_ROOT/vm${vmid}\\\"\"},{\"line\":236,\"text\":\"[[ -d \\\"$dir\\\" ]] || die \\\"STATE_DIR_MISSING_$vmid\\\" 65\"},{\"line\":238,\"text\":\"[[ -n \\\"$latest\\\" && -s \\\"$latest\\\" && ! -L \\\"$latest\\\" ]] || die \\\"LATEST_STATE_MISSING_$vmid\\\" 65\"},{\"line\":239,\"text\":\"jq -e '.status==\\\"SEALED\\\" and .cloud_quorum==2 and .local_payload_present==false and .local_cleanup==\\\"OK\\\" and .seal_written==true' \\\"$latest\\\" >/dev/null || die \\\"LATEST_STATE_NOT_SEALED_$vmid\\\" 65\"},{\"line\":240,\"text\":\"gen=\\\"$(jq -er '.generation' \\\"$latest\\\")\\\"; restore_ok \\\"$vmid\\\" \\\"$gen\\\" || die \\\"LATEST_RESTORE_NOT_OK_$vmid\\\" 65\"},{\"line\":241,\"text\":\"printf 'LATEST_SEALED_STATUS=OK\\\\nVMID=%s\\\\nGENERATION=%s\\\\nSTATE_FILE=%s\\\\nRESTORE_EVIDENCE=%s\\\\n' \\\"$vmid\\\" \\\"$gen\\\" \\\"$latest\\\" \\\"$(restore_dir \\\"$vmid\\\")/$gen.json\\\"\"},{\"line\":244,\"text\":\"case \\\"$ACTION\\\" in\"},{\"line\":246,\"text\":\"[[ \\\"$#\\\" == 1 ]] || die \\\"USAGE_HOST_PREFLIGHT\\\" 64\"},{\"line\":249,\"text\":\"latest-sealed)\"},{\"line\":250,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_LATEST_SEALED\\\" 64\"},{\"line\":254,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_PLAN\\\" 64\"},{\"line\":257,\"text\":\"backup)\"},{\"line\":258,\"text\":\"[[ \\\"$#\\\" == 2 ]] || die \\\"USAGE_BACKUP\\\" 64\"},{\"line\":259,\"text\":\"backup_one \\\"$2\\\"\"},{\"line\":261,\"text\":\"restore-validate)\"},{\"line\":262,\"text\":\"[[ \\\"$#\\\" == 3 ]] || die \\\"USAGE_RESTORE_VALIDATE\\\" 64\"},{\"line\":263,\"text\":\"restore_validate \\\"$2\\\" \\\"$3\\\"\"},{\"line\":266,\"text\":\"[[ \\\"$#\\\" == 3 ]] || die \\\"USAGE_VERIFY\\\" 64\"}]\nNODEWORKER_CLI_CANDIDATES=[{\"kind\":\"dispatch\",\"text\":\"case \\\"$1\\\" in\"},{\"kind\":\"subcommand-token\",\"text\":\"backup\"},{\"kind\":\"subcommand-token\",\"text\":\"restore\"},{\"kind\":\"subcommand-token\",\"text\":\"latest-sealed\"}]\nDECISION=DIRECT_NODEWORKER_TARGETED_BACKUP_CLI_DISCOVERED\nNO_MUTATION=true\nTASK_RESULT=PASS_HOMELAB_BACKUP_NODEWORKER_CONTRACT_RCA_READONLY\nHOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\nWORKERS2_NODEWORKER_CONTRACT_RCA_END=1\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index fc26e3ed..7f5a9a3d 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,15 +1,15 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1 +COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1 STATUS=OK RC=0 HOST=pve01 MODE=read-only -COMPONENT=homelab-backup-scheduler-contract-rca +COMPONENT=homelab-backup-nodeworker-contract-rca REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 -COMMAND_SHA256=03f74f4f55da06e3cb0f9a99977974ef5f7a54cf444a6d81d92957823f7e8f08 +COMMAND_SHA256=476f69ce1ba9062cf703c5b1de5f81404fc50b1b31240c36e2e6ecdcd7aebecc DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGE_DECLARED=false @@ -24,26 +24,25 @@ MUTATION_OUTCOME=NO_MUTATION SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=a0a1f31643f6b251d01109ba03b14ffd330a1bb432b6481e2854ccd40bf40b83 -SANITIZED_OUTPUT_SHA256=a0a1f31643f6b251d01109ba03b14ffd330a1bb432b6481e2854ccd40bf40b83 +RAW_EVIDENCE_SHA256=6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052 +SANITIZED_OUTPUT_SHA256=6889fdc8e9ed9a2a2d17d6033311e611ad2a4fc46893776f10806c0b194ff052 OUTPUT_BEGIN -WORKERS2_SCHEDULER_CONTRACT_RCA_BEGIN=1 -COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1 +WORKERS2_NODEWORKER_CONTRACT_RCA_BEGIN=1 +COMMAND_ID=SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1 MODE=read-only -COMPONENT=homelab-backup-scheduler-contract-rca -MUTATION_BOUNDARY=READ_ONLY_NO_SERVICE_START_NO_TIMER_CHANGE_NO_KILL_NO_SIGNAL_NO_LOCK_BREAK_NO_BACKUP_NO_GC_NO_MAIL_NO_GIT_WRITE -SOURCE_FILES=[{"path":"/etc/systemd/system/homelab-backup-v2.service","sha256":"1ef3e6bc660767a1f29a6a0bfa8d1b7a2419370b2250764ca181c34c93188565","size":309},{"path":"/usr/local/sbin/homelab-backup-v2","sha256":"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2","size":1656},{"path":"/usr/local/libexec/homelab-backup-target-registry","sha256":"c681c44be7557d192d7b453b67e31164237874596168f1d4c78e1e926e2e9cb4","size":4406},{"path":"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker","sha256":"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1","size":17702},{"path":"/usr/local/libexec/homelab-cloud-quorum-payload","sha256":"df9e19485e5d87112bf58bf77bdddf3b9b896418dd85ff945a31cd5b6817f352","size":38039}] -SCHEDULER_LOGIC_HITS=[{"file":"/etc/systemd/system/homelab-backup-v2.service","line":2,"text":"Description=Homelab Backup V2 manifest-driven scheduler"},{"file":"/etc/systemd/system/homelab-backup-v2.service","line":3,"text":"After=network-online.target"},{"file":"/etc/systemd/system/homelab-backup-v2.service","line":4,"text":"Wants=network-online.target"},{"file":"/etc/systemd/system/homelab-backup-v2.service","line":11,"text":"ExecStart=/usr/local/sbin/homelab-backup-v2 scheduled"},{"file":"/etc/systemd/system/homelab-backup-v2.service","line":14,"text":"IOSchedulingPriority=7"},{"file":"/usr/local/sbin/homelab-backup-v2","line":5,"text":"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":4,"text":"REGISTRY=\"${HOMELAB_BACKUP_TARGET_REGISTRY:-/etc/homelab-backup/targets.json}\""},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":5,"text":"die(){ printf 'TARGET_REGISTRY_ERROR=%s\\n' \"$1\" >&2; exit \"${2:-65}\"; }"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":10,"text":".schema==\"homelab-backup-target-registry-v1\" and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":13,"text":".policies.freshness_seconds.VM==72000 and .policies.freshness_seconds.APP==72000 and .policies.freshness_seconds.CONTROL==86400 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":14,"text":"(.targets|type)==\"array\" and (.targets|length)==21 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":15,"text":"([.targets[].id]|length)==([.targets[].id]|unique|length) and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":16,"text":"([.targets[].logical_id]|length)==([.targets[].logical_id]|unique|length) and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":17,"text":"([.targets[]|select(.kind==\"VM\" and .lifecycle==\"ACTIVE\")]|length)==11 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":18,"text":"([.targets[]|select(.kind==\"APP\" and .lifecycle==\"ACTIVE\")]|length)==4 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":19,"text":"([.targets[]|select(.kind==\"APP\" and .lifecycle==\"RETIRED_PRESERVE\")]|length)==3 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":20,"text":"([.targets[]|select(.kind==\"CONTROL\" and .lifecycle==\"ACTIVE\")]|length)==1 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":21,"text":"([.targets[]|select((.kind!=\"VM\" and .kind!=\"APP\" and .kind!=\"CONTROL\") or (.lifecycle!=\"ACTIVE\" and .lifecycle!=\"RETIRED_PRESERVE\"))]|length)==0 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":22,"text":"([.targets[]|select(.kind==\"VM\")|select(.owner!=\"pve01\" and .owner!=\"pve02\" and .owner!=\"pve03\")]|length)==0 and"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":27,"text":"rows(){ validate; jq -r '.targets[]|[.kind,.id,.logical_id,.owner,.lifecycle,(.source_host//\"\"),((.migrate//false)|tostring)]|@tsv' \"$REGISTRY\"; }"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":28,"text":"find_by_id(){ local kind=\"$1\" id=\"$2\"; validate; jq -er --arg k \"$kind\" --arg i \"$id\" '.targets[]|select(.kind==$k and .id==$i)' \"$REGISTRY\"; }"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":29,"text":"find_by_logical(){ local logical=\"$1\"; validate; jq -er --arg l \"$logical\" '.targets[]|select(.logical_id==$l)' \"$REGISTRY\"; }"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":31,"text":"validate) [[ \"$#\" == 1 ]] || die USAGE 64; validate; printf 'TARGET_REGISTRY=OK\\n' ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":32,"text":"active-vm-ids) [[ \"$#\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\"VM\" and .lifecycle==\"ACTIVE\")|.id' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":33,"text":"active-app-ids) [[ \"$#\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\"APP\" and .lifecycle==\"ACTIVE\")|.id' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":34,"text":"migrate-app-ids) [[ \"$#\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.kind==\"APP\" and .lifecycle==\"ACTIVE\" and .migrate==true)|.id' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":35,"text":"app-active) [[ \"$#\" == 2 ]] || die USAGE 64; find_by_id APP \"$2\" | jq -e '.lifecycle==\"ACTIVE\"' >/dev/null ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":36,"text":"app-logical) [[ \"$#\" == 2 ]] || die USAGE 64; find_by_id APP \"$2\" | jq -er 'select(.lifecycle==\"ACTIVE\")|.logical_id' ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":37,"text":"app-source-host) [[ \"$#\" == 2 ]] || die USAGE 64; find_by_id APP \"$2\" | jq -er 'select(.lifecycle==\"ACTIVE\")|.source_host' ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":39,"text":"lifecycle) [[ \"$#\" == 2 ]] || die USAGE 64; find_by_logical \"$2\" | jq -er '.lifecycle' ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":40,"text":"retention-logicals) [[ \"$#\" == 1 ]] || die USAGE 64; validate; jq -r '.targets[]|select(.lifecycle==\"ACTIVE\" or .lifecycle==\"RETIRED_PRESERVE\")|.logical_id' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":41,"text":"retention-keep) [[ \"$#\" == 2 ]] || die USAGE 64; rec=\"$(find_by_logical \"$2\")\"; life=\"$(jq -r '.lifecycle' <<<\"$rec\")\"; [[ \"$life\" == ACTIVE ]] || die RETENTION_KEEP_NOT_ACTIVE 64; kind=\"$(jq -r '.kind' <<<\"$rec\")\"; jq -er --arg k \"$kind\" '.policies.retention_keep[$k]' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":43,"text":"freshness-seconds) [[ \"$#\" == 2 ]] || die USAGE 64; validate; jq -er --arg k \"$2\" '.policies.freshness_seconds[$k]' \"$REGISTRY\" ;;"},{"file":"/usr/local/libexec/homelab-backup-target-registry","line":46,"text":"*) die USAGE_validate_active-vm-ids_active-app-ids_migrate-app-ids_app-active_app-logical_app-source-host_logical-owner_lifecycle_retention-logicals_retention-keep_policy-keep_freshness-seconds_systemd-expectations_rows 64 ;;"},{"file":"/usr/local/libexec/homelab-cloud-quorum-payload","line":403,"text":"if ! awk -v target=\"$LOGICAL_ID/\" '$0==target{found=1} END{exit !found}' \"$root_listing\"; then"},{"file":"/usr/local/libexec/homelab-cloud-quorum-payload","line":410,"text":"if awk -v target=\"$GENERATION/\" '$0==target{found=1} END{exit !found}' \"$logical_listing\"; then"}] -TARGET_CONTRACT_ROWS=[{"id":"110","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm110"},{"id":"111","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm111"},{"id":"112","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm112"},{"id":"113","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm113"},{"id":"130","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm130"},{"id":"150","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm150"},{"id":"160","kind":"VM","lifecycle":"ACTIVE","logical_id":"vm160"}] -CURRENT_VM_STATE_ROWS=[{"age_seconds":1783,"exists":true,"last_attempt_epoch":1790022508,"last_success_epoch":1790022508,"replica_count":2,"resource_type":"lxc","result":"SUCCESS","state_id":"ct110","vmid":"110"},{"age_seconds":1636,"exists":true,"last_attempt_epoch":1790022655,"last_success_epoch":1790022655,"replica_count":2,"resource_type":"lxc","result":"SUCCESS","state_id":"ct111","vmid":"111"},{"age_seconds":83215,"exists":true,"last_attempt_epoch":1789941076,"last_success_epoch":1789941076,"replica_count":2,"resource_type":"lxc","result":"SUCCESS","state_id":"ct112","vmid":"112"},{"age_seconds":81050,"exists":true,"last_attempt_epoch":1789943241,"last_success_epoch":1789943241,"replica_count":2,"resource_type":"lxc","result":"SUCCESS","state_id":"ct113","vmid":"113"},{"age_seconds":75658,"exists":true,"last_attempt_epoch":1789948633,"last_success_epoch":1789948633,"replica_count":2,"resource_type":"qemu","result":"SUCCESS","state_id":"vm130","vmid":"130"},{"age_seconds":78944,"exists":true,"last_attempt_epoch":1789945347,"last_success_epoch":1789945347,"replica_count":2,"resource_type":"qemu","result":"SUCCESS","state_id":"vm150","vmid":"150"},{"age_seconds":74191,"exists":true,"last_attempt_epoch":1789950100,"last_success_epoch":1789950100,"replica_count":2,"resource_type":"qemu","result":"SUCCESS","state_id":"vm160","vmid":"160"}] -REGISTRY_VM_FRESHNESS={"lines":["72000",""],"rc":0} -REGISTRY_HELP={"lines":["","TARGET_REGISTRY_ERROR=USAGE_validate_active-vm-ids_active-app-ids_migrate-app-ids_app-active_app-logical_app-source-host_logical-owner_lifecycle_retention-logicals_retention-keep_policy-keep_freshness-seconds_systemd-expectations_rows"],"rc":64} -DECISIVE_JOURNAL=["SCHEDULE_TARGET=xf-codevipe","SCHEDULE_RESULT=SUCCESS","homelab-backup-v2.service: Deactivated successfully.","SCHEDULE_TARGET=xf-zakrutim","SCHEDULE_RESULT=SUCCESS","homelab-backup-v2.service: Deactivated successfully.","INFO: starting new backup job: vzdump 110 --remove 0 --prune-backups 'keep-all=1' --compress zstd --tmpdir /var/tmp/homelab-vzdump-v2-v2-ct110-20260921T202514Z-1c872adccfab --mode snapshot --stdexcludes 0 --bwlimit 32768 --ionice 7 --node pve01 --zstd 1 --lockwait 0","INFO: Backup job finished successfully","notified via target `mail-to-root`","SCHEDULE_TARGET=ct110","SCHEDULE_RESULT=SUCCESS","homelab-backup-v2.service: Deactivated successfully.","SCHEDULE_TARGET=ct111","SCHEDULE_RESULT=SUCCESS","homelab-backup-v2.service: Deactivated successfully.","SCHEDULE_DECISION=DEFER_NO_DUE_TARGET","homelab-backup-v2.service: Deactivated successfully.","SCHEDULE_DECISION=DEFER_NO_DUE_TARGET","homelab-backup-v2.service: Deactivated successfully.","SCHEDULE_DECISION=DEFER_NO_DUE_TARGET","homelab-backup-v2.service: Deactivated successfully."] -DECISION=SCHEDULER_ELIGIBILITY_FILTER_DIFFERS_FROM_RPO_SET +COMPONENT=homelab-backup-nodeworker-contract-rca +MUTATION_BOUNDARY=READ_ONLY_NO_EXECUTION_OF_BACKUP_WORKERS_NO_SERVICE_START_NO_TIMER_CHANGE_NO_LOCK_BREAK_NO_GIT_WRITE +WRAPPER_INFO={"logic":[{"line":4,"text":"ACCEPTED=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b')"},{"line":5,"text":"EXPECTED={'fresh_lxc_helper.py': 'dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011', 'producer_exec_helper.py': 'b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3', 'lxc_adapter.py': '3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d', 'qemu_adapter.py': '1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b', 'scheduler_adapter.py': 'a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96', 'entry504.py': 'ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793'}"}],"path":"/usr/local/sbin/homelab-backup-v2","sha256":"5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2","size":1656} +HASH_MATCHED_HELPERS={"entry504.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","sha256":"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793","size":10566},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","sha256":"ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793","size":10566}],"fresh_lxc_helper.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-501r1-e55e5c8c446a/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py","sha256":"dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011","size":2320}],"lxc_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py","sha256":"3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d","size":13825}],"producer_exec_helper.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","sha256":"b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3","size":3449}],"qemu_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","sha256":"1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b","size":4627}],"scheduler_adapter.py":[{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","sha256":"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96","size":4097},{"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","sha256":"a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96","size":4097}]} +HELPER_LOGIC_HITS={"entry504.py":[{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',"},{"line":64,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"'choose_due_target','write_state','epoch')"},{"line":78,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])"},{"line":79,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:"},{"line":80,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced."},{"line":89,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper.selftest()"},{"line":93,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_adapter=importlib.import_module('scheduler_adapter')"},{"line":96,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)"},{"line":97,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired"},{"line":99,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _target(wrapper,lid):"},{"line":100,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]"},{"line":101,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')"},{"line":104,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def selftest():"},{"line":105,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":108,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:"},{"line":109,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')"},{"line":110,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:"},{"line":111,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_WRITE_BINDING')"},{"line":112,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:"},{"line":113,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')"},{"line":114,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):"},{"line":116,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SELFTEST_OVERLAY504=PASS',flush=True)"},{"line":120,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"argv=list(sys.argv[1:] if argv is None else argv)"},{"line":121,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['selftest']:"},{"line":122,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return selftest()"},{"line":123,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":125,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-proof']:"},{"line":129,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')"},{"line":132,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:"},{"line":141,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]"},{"line":142,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"first=legacy.choose_due_target(targets,state,now[0])"},{"line":143,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')"},{"line":146,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')"},{"line":148,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])"},{"line":149,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')"},{"line":153,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')"},{"line":154,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}"},{"line":155,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)"},{"line":159,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-select-live']:"},{"line":160,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"state=legacy.load_state_all(); targets=wrapper.load_targets()"},{"line":161,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"chosen=legacy.choose_due_target(targets,state)"},{"line":163,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)"},{"line":165,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)"},{"line":167,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='plan-lxc':"},{"line":168,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":169,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":170,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')"},{"line":172,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)"},{"line":174,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='verify-target':"},{"line":175,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":176,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":179,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"out=wrapper.backup_target(t,True)"},{"line":180,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"except legacy.BackupError as e:"},{"line":181,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT=FAIL',flush=True)"},{"line":182,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)"},{"line":184,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)"},{"line":186,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper.main([sys.argv[0],*argv])"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',"},{"line":64,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"'choose_due_target','write_state','epoch')"},{"line":78,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])"},{"line":79,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:"},{"line":80,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced."},{"line":89,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper.selftest()"},{"line":93,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"scheduler_adapter=importlib.import_module('scheduler_adapter')"},{"line":96,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)"},{"line":97,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired"},{"line":99,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def _target(wrapper,lid):"},{"line":100,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]"},{"line":101,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')"},{"line":104,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"def selftest():"},{"line":105,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":108,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:"},{"line":109,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_CHOOSE_BINDING')"},{"line":110,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:"},{"line":111,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_WRITE_BINDING')"},{"line":112,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:"},{"line":113,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')"},{"line":114,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):"},{"line":116,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SELFTEST_OVERLAY504=PASS',flush=True)"},{"line":120,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"argv=list(sys.argv[1:] if argv is None else argv)"},{"line":121,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['selftest']:"},{"line":122,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return selftest()"},{"line":123,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()"},{"line":125,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-proof']:"},{"line":129,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')"},{"line":132,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:"},{"line":141,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]"},{"line":142,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"first=legacy.choose_due_target(targets,state,now[0])"},{"line":143,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')"},{"line":146,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')"},{"line":148,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])"},{"line":149,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')"},{"line":153,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')"},{"line":154,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"proof={'failed_target':'proof-a','peer_selected_during_backoff':first['logical_id'],'retry_after_epoch':retry,'last_success_preserved':preserved==1000,'retry_target_after_backoff':second['logical_id'],'success_resets_failures':True,'production_state_root_used':False}"},{"line":155,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)"},{"line":159,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if argv==['scheduler-select-live']:"},{"line":160,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"state=legacy.load_state_all(); targets=wrapper.load_targets()"},{"line":161,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"chosen=legacy.choose_due_target(targets,state)"},{"line":163,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)"},{"line":165,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('SCHEDULER_LIVE_SELECTION='+json.dumps({'logical_id':chosen.get('logical_id'),'due_seconds':chosen.get('due_seconds'),'enabled':chosen.get('enabled') is True},separators=(',',':'),sort_keys=True),flush=True)"},{"line":167,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='plan-lxc':"},{"line":168,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":169,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":170,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')"},{"line":172,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('PLAN_LXC_RESULT='+json.dumps({'logical_id':t['logical_id'],'vmid':int(t['vmid']),'node':out['job']['node'],'job':out['job']},separators=(',',':'),sort_keys=True),flush=True)"},{"line":174,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if len(argv)==2 and argv[0]=='verify-target':"},{"line":175,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"t=_target(wrapper,argv[1])"},{"line":176,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"if t.get('logical_id')=='guest-pve01-lxc-112':"},{"line":179,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"out=wrapper.backup_target(t,True)"},{"line":180,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"except legacy.BackupError as e:"},{"line":181,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT=FAIL',flush=True)"},{"line":182,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_REASON='+str(e.code),flush=True)"},{"line":184,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)"},{"line":186,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py","text":"return wrapper.main([sys.argv[0],*argv])"}],"fresh_lxc_helper.py":[{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-500r1-a3964599e60c/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')"},{"line":15,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if len(sys.argv)!=1: fail('HELPER_ARGC')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"node=raw.get('node'); vmid=raw.get('vmid'); scratch=raw.get('scratch'); now=raw.get('now')"},{"line":27,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if type(node) is not str or type(vmid) is not int or type(scratch) is not str or type(now) is not int: fail('INPUT_FIELDS')"},{"line":30,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"plan=pve265.make_plan(raw.get('rows'),configs,raw.get('storage_rows'),defaults,int(raw.get('staging_free')),now,node=node)"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"jobs=[j for j in plan['jobs'] if j.get('vmid')==vmid]"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"if job.get('type')!='lxc' or job.get('node')!=node: fail('JOB_IDENTITY')"},{"line":37,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"guest266.no_active_tasks(raw.get('tasks'),vmid)"},{"line":39,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/fresh_lxc_helper.py","text":"keep=('vmid','type','node','status','template','config_sha256','disks','configured_disk_bytes','configured_archive_bound_bytes','archive_cap_bytes','global_defaults_sha256','blockers','coverage_eligible')"}],"lxc_adapter.py":[{"line":2,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"import base64, hashlib, json, os, pathlib, re, selectors, shlex, signal, stat, subprocess, sys, time"},{"line":6,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"HELPER=pathlib.Path(__file__).resolve().parent/'fresh_lxc_helper.py'"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"def _live_inputs(legacy,node,vmid,scratch):"},{"line":42,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue"},{"line":50,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"try: rid=int(r.get('vmid'))"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"except Exception: raise AdapterError('RESOURCE_VMID')"},{"line":52,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\"type\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/lxc_adapter.py","text":"_need(0int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-502r1-9d13ea486935/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"def selftest()->int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"},{"line":4,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')"},{"line":26,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"def selftest()->int:"},{"line":31,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)"},{"line":35,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if sys.argv[1:]==['selftest']: return selftest()"},{"line":36,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if sys.argv[1:]: fail('ARGC')"},{"line":41,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if type(x) is not dict or set(x)!={'argv','dest','cap','seconds'}: fail('INPUT_SCHEMA')"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if not (type(argv) is list and argv and all(type(v) is str and '\\x00' not in v for v in argv)): fail('ARGV')"},{"line":44,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py","text":"if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')"}],"qemu_adapter.py":[{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"},{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"},{"line":11,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _remote_sha(legacy,node,path):"},{"line":12,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)"},{"line":17,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"def _select_qemu_outputs(vmid,files):"},{"line":18,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(type(vmid) is int and vmid>0,'QEMU_VMID')"},{"line":21,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"pat=re.compile(r'^vzdump-qemu-'+re.escape(str(vmid))+r'-(\\d{4}_\\d{2}_\\d{2}-\\d{2}_\\d{2}_\\d{2})\\.vma\\.zst$')"},{"line":29,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'"},{"line":43,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vmid=int(t['vmid']); rows=[r for r in legacy.cluster_inventory() if int(r.get('vmid',-1))==vmid]"},{"line":45,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"row=rows[0]; node=row.get('node'); typ=row.get('type')"},{"line":47,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')"},{"line":49,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)"},{"line":51,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)"},{"line":53,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=vp.returncode,stderr_bytes=len(vp.stderr),stderr_sha256=hashlib.sha256(vp.stderr).hexdigest(),archive_selected=False)"},{"line":54,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError('QEMU_VZDUMP_FAILED')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')"},{"line":56,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"try: src,log=_select_qemu_outputs(vmid,files)"},{"line":60,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"raise legacy.BackupError(str(e)) from None"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)"},{"line":67,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"if node=='pve01': local=pathlib.Path(src)"},{"line":69,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),sidecar_count=1 if log else 0,archive_bytes=size,archive_selected=True)"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise"},{"line":74,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-503r1-ac51fd96ec13/qemu_adapter.py","text":"meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),"}],"scheduler_adapter.py":[{"line":7,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"class SchedulerAdapterError(RuntimeError): pass"},{"line":10,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not ok: raise SchedulerAdapterError(code)"},{"line":23,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def _read_prior(legacy,logical_id):"},{"line":25,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"p=root/(str(logical_id)+'.json')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def choose_due_target(targets,state,now=None):"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due=[]"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"for order,t in enumerate(targets):"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')"},{"line":70,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"overdue=age-seconds"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due.append((overdue,-order,t))"},{"line":72,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not due: return None"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return max(due,key=lambda x:(x[0],x[1]))[2]"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def write_state(logical_id,result,**kw):"},{"line":77,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"prior=_read_prior(legacy,logical_id)"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":90,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"legacy.choose_due_target=choose_due_target"},{"line":92,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return {'choose_due_target':choose_due_target,'write_state':write_state,"},{"line":7,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"class SchedulerAdapterError(RuntimeError): pass"},{"line":10,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not ok: raise SchedulerAdapterError(code)"},{"line":23,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def _read_prior(legacy,logical_id):"},{"line":25,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"p=root/(str(logical_id)+'.json')"},{"line":55,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def choose_due_target(targets,state,now=None):"},{"line":57,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')"},{"line":58,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due=[]"},{"line":59,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"for order,t in enumerate(targets):"},{"line":61,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)"},{"line":62,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"_need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')"},{"line":70,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"overdue=age-seconds"},{"line":71,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"due.append((overdue,-order,t))"},{"line":72,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"if not due: return None"},{"line":73,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return max(due,key=lambda x:(x[0],x[1]))[2]"},{"line":75,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"def write_state(logical_id,result,**kw):"},{"line":77,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"prior=_read_prior(legacy,logical_id)"},{"line":81,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":88,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return original_write(logical_id,result,**clean)"},{"line":90,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"legacy.choose_due_target=choose_due_target"},{"line":92,"path":"/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py","text":"return {'choose_due_target':choose_due_target,'write_state':write_state,"}]} +NODEWORKER_INFO={"path":"/usr/local/libexec/homelab-vm-cloud-quorum-node-worker","sha256":"91bdd116be865560a38105dffbd1a66d687232035e2359e4a5be4d225e9c61d1","size":17702} +NODEWORKER_LOGIC_HITS=[{"line":6,"text":"STATE_ROOT=/var/lib/homelab-backup/cloud-quorum"},{"line":8,"text":"RESTORE_STATE_ROOT=/var/lib/homelab-backup/vm-restore-validation"},{"line":9,"text":"RESTORE_WORK_ROOT=/mnt/staging/homelab-vm-restore-validation"},{"line":11,"text":"REMOTE_A='pve01-mail-01-crypt:homelab-backups'"},{"line":12,"text":"REMOTE_B='pve01-mail-02-crypt:homelab-backups'"},{"line":18,"text":"ACTIVE_RESTORE_STAGE=\"\""},{"line":19,"text":"cleanup_restore_stage(){ if [[ -n \"$ACTIVE_RESTORE_STAGE\" && \"$ACTIVE_RESTORE_STAGE\" == \"$RESTORE_WORK_ROOT\"/* && -d \"$ACTIVE_RESTORE_STAGE\" ]]; then rm -rf --one-file-system \"$ACTIVE_RESTORE_STAGE\"; fi; }"},{"line":20,"text":"trap cleanup_restore_stage EXIT"},{"line":21,"text":"active_backup_restore(){ local rc; if pgrep -af '(^|/)(vzdump|qmrestore|pctrestore|vma|zstd|rclone)([[:space:]]|$)'; then return 0; else rc=$?; [[ \"$rc\" == 1 ]] && return 0; die \"PGREP_FAILED_$rc\" 69; fi; }"},{"line":24,"text":"expected_owner(){"},{"line":25,"text":"case \"$1\" in"},{"line":29,"text":"*) die \"VMID_NOT_ALLOWED_$1\" 64 ;;"},{"line":33,"text":"case \"$1\" in"},{"line":36,"text":"*) die \"VMID_NOT_ALLOWED_$1\" 64 ;;"},{"line":43,"text":"local vmid=\"$1\" type=\"$2\""},{"line":44,"text":"if [[ \"$type\" == \"qemu\" ]]; then qm status \"$vmid\" | awk '{print $2}'; else pct status \"$vmid\" | awk '{print $2}'; fi"},{"line":47,"text":"local vmid=\"$1\" owner type status expect_status"},{"line":48,"text":"owner=\"$(expected_owner \"$vmid\")\""},{"line":49,"text":"type=\"$(expected_type \"$vmid\")\""},{"line":50,"text":"[[ \"$HOST\" == \"$owner\" ]] || die \"OWNER_MISMATCH_${vmid}_${HOST}_EXPECTED_${owner}\" 65"},{"line":52,"text":"[[ -s \"/etc/pve/qemu-server/${vmid}.conf\" ]] || die \"QEMU_CONFIG_MISSING_$vmid\" 66"},{"line":54,"text":"[[ -s \"/etc/pve/lxc/${vmid}.conf\" ]] || die \"LXC_CONFIG_MISSING_$vmid\" 66"},{"line":56,"text":"status=\"$(current_status \"$vmid\" \"$type\")\""},{"line":57,"text":"expect_status=\"$(expected_status \"$vmid\")\""},{"line":58,"text":"[[ \"$status\" == \"$expect_status\" ]] || die \"STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\" 66"},{"line":59,"text":"if [[ \"$vmid\" == \"160\" ]]; then [[ \"$(snapshot_count_160)\" == \"0\" ]] || die \"VM160_SNAPSHOT_COUNT_CHANGED\" 66; fi"},{"line":60,"text":"if [[ \"$vmid\" == \"9130\" ]]; then [[ \"$(vm_lock 9130)\" == \"none\" ]] || die \"VM9130_LOCK_PRESENT\" 66; fi"},{"line":65,"text":"local vmid=\"$1\" type=\"$2\" status expect_status"},{"line":66,"text":"status=\"$(current_status \"$vmid\" \"$type\")\""},{"line":67,"text":"expect_status=\"$(expected_status \"$vmid\")\""},{"line":68,"text":"[[ \"$status\" == \"$expect_status\" ]] || die \"POST_STATUS_MISMATCH_${vmid}_${status}_EXPECTED_${expect_status}\" 66"},{"line":69,"text":"if [[ \"$vmid\" == \"160\" ]]; then [[ \"$(snapshot_count_160)\" == \"0\" ]] || die \"VM160_SNAPSHOT_COUNT_CHANGED_POST\" 66; fi"},{"line":70,"text":"if [[ \"$vmid\" == \"9130\" ]]; then [[ \"$(vm_lock 9130)\" == \"none\" ]] || die \"VM9130_LOCK_PRESENT_POST\" 66; fi"},{"line":73,"text":"local vmid=\"$1\" dir=\"$STATE_ROOT/vm${vmid}\" f"},{"line":79,"text":"restore_dir(){ printf '%s\\n' \"$RESTORE_STATE_ROOT/vm$1\"; }"},{"line":80,"text":"restore_ok(){"},{"line":81,"text":"local vmid=\"$1\" gen=\"$2\" f state sha"},{"line":82,"text":"f=\"$(restore_dir \"$vmid\")/$gen.json\"; state=\"$STATE_ROOT/vm${vmid}/$gen.json\""},{"line":85,"text":"jq -e --arg l \"vm${vmid}\" --arg g \"$gen\" --arg s \"$state\" --arg sha \"$sha\" '.schema==\"homelab-vm-restore-validation-v1\" and .logical_id==$l and .generation==$g and .transport_state==\"SEALED\" and .transport_state_file==$s and .restore_source==\"Cloud A\" and .parts_manifest_verified==true and .payload_sha256==$sha and .payload_sha256_verified==true and .payload_decompression_verified==true and .proxmox_config_extract_verified==true and .archive_recovery_readback_verified==true and .bounded_staging==true and .full_local_payload_written==false and .full_restore_proven==false and .result==\"OK\"' \"$f\" >/dev/null"},{"line":88,"text":"local vmid=\"$1\" gen=\"$2\" state=\"$3\" work=\"$4\" base manifest expected_msha got_msha expected_count expected_size idx name size psha count total"},{"line":90,"text":"[[ \"$base\" == \"${REMOTE_A%/}/vm${vmid}/$gen\" ]] || die \"RESTORE_A_BASE_MISMATCH_$vmid\" 70"},{"line":92,"text":"got_msha=\"$(sha256sum \"$manifest\"|awk '{print $1}')\"; [[ \"$got_msha\" == \"$expected_msha\" ]] || die \"RESTORE_A_MANIFEST_SHA_MISMATCH_$vmid\" 70"},{"line":95,"text":"[[ \"$idx\" =~ ^[0-9]{8}$ && \"$name\" == part-????????.bin && \"$size\" =~ ^[1-9][0-9]*$ && \"$psha\" =~ ^[0-9a-f]{64}$ ]] || die \"RESTORE_A_MANIFEST_ROW_INVALID_$vmid\" 70"},{"line":96,"text":"(( size <= 536870912 )) || die \"RESTORE_A_PART_EXCEEDS_BOUND_$vmid\" 70"},{"line":97,"text":"[[ \"$idx\" == \"$(printf '%08d' \"$count\")\" ]] || die \"RESTORE_A_MANIFEST_INDEX_INVALID_$vmid\" 70"},{"line":100,"text":"[[ \"$count\" == \"$expected_count\" ]] || die \"RESTORE_A_PART_COUNT_MISMATCH_$vmid\" 70"},{"line":101,"text":"[[ \"$total\" == \"$expected_size\" ]] || die \"RESTORE_A_MANIFEST_TOTAL_SIZE_MISMATCH_$vmid\" 70"},{"line":105,"text":"local vmid=\"$1\" base=\"$2\" manifest=\"$3\" work=\"$4\" idx name size psha part actual count"},{"line":109,"text":"[[ -s \"$part\" && ! -L \"$part\" && \"$(stat -c %s \"$part\")\" == \"$size\" ]] || die \"RESTORE_A_PART_SIZE_MISMATCH_$vmid\" 70"},{"line":110,"text":"actual=\"$(sha256sum \"$part\"|awk '{print $1}')\"; [[ \"$actual\" == \"$psha\" ]] || die \"RESTORE_A_PART_SHA_MISMATCH_$vmid\" 70"},{"line":114,"text":"restore_validate(){"},{"line":115,"text":"local vmid=\"$1\" gen=\"$2\" logical state work payload_name expected_sha expected_size base manifest fifo sha_out sha_pid pipe_rc sha_rc actual_sha config config_sha members member_count cfg_member level out tmp"},{"line":116,"text":"assert_local_identity \"$vmid\"; logical=\"vm${vmid}\"; state=\"$STATE_ROOT/$logical/$gen.json\""},{"line":117,"text":"[[ -s \"$state\" && ! -L \"$state\" ]] || die \"RESTORE_STATE_MISSING_$vmid\" 65"},{"line":118,"text":"jq -e '.schema==\"homelab-cloud-quorum-payload-v1\" and .status==\"SEALED\" and .cloud_quorum==2 and .cloud_a_verified==true and .cloud_b_verified==true and .part_hashes_verified==true and .seal_written==true and .cloud_a_seal_verified==true and .cloud_b_seal_verified==true and .local_payload_present==false and .local_cleanup==\"OK\"' \"$state\" >/dev/null || die \"RESTORE_REQUIRES_STRICT_SEALED_$vmid\" 65"},{"line":119,"text":"if restore_ok \"$vmid\" \"$gen\"; then printf 'RESTORE_VALIDATION_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESULT=ALREADY_VALIDATED\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$(restore_dir \"$vmid\")/$gen.json\"; return 0; fi"},{"line":120,"text":"[[ -z \"$(active_backup_restore)\" ]] || die ACTIVE_BACKUP_RESTORE_PRESENT 75"},{"line":122,"text":"[[ \"$payload_name\" == \"vzdump-lxc-${vmid}-\"*.tar.zst || \"$payload_name\" == \"vzdump-qemu-${vmid}-\"*.vma.zst ]] || die \"RESTORE_PAYLOAD_NAME_INVALID_$vmid\" 70"},{"line":123,"text":"work=\"$RESTORE_WORK_ROOT/$logical/$gen\"; if [[ -e \"$work\" ]]; then [[ -d \"$work\" && ! -L \"$work\" ]] || die \"RESTORE_WORK_UNSAFE_$vmid\" 70; rm -rf --one-file-system \"$work\"; fi; mkdir -p \"$work\"; chmod 0700 \"$RESTORE_WORK_ROOT\" \"$RESTORE_WORK_ROOT/$logical\" \"$work\"; ACTIVE_RESTORE_STAGE=\"$work\""},{"line":124,"text":"base=\"$(prepare_cloud_a_manifest \"$vmid\" \"$gen\" \"$state\" \"$work\")\"; manifest=\"$work/PARTS.tsv\"; fifo=\"$work/archive.sha.fifo\"; sha_out=\"$work/archive.sha256\"; mkfifo -m 0600 \"$fifo\""},{"line":127,"text":"members=\"$work/members.txt\"; if stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | tee \"$fifo\" | zstd -dc | tar -tf - >\"$members\"; then pipe_rc=0; else pipe_rc=$?; fi"},{"line":129,"text":"if stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | tee \"$fifo\" | zstd -t - >/dev/null; then pipe_rc=0; else pipe_rc=$?; fi"},{"line":132,"text":"(( pipe_rc == 0 && sha_rc == 0 )) || die \"RESTORE_A_STREAM_VALIDATION_FAILED_${vmid}_${pipe_rc}_${sha_rc}\" 70"},{"line":133,"text":"actual_sha=\"$(awk 'NR==1{print $1}' \"$sha_out\")\"; [[ \"$actual_sha\" == \"$expected_sha\" ]] || die \"RESTORE_A_PAYLOAD_SHA_MISMATCH_$vmid\" 70"},{"line":136,"text":"[[ -s \"$members\" ]] || die \"RESTORE_LXC_ARCHIVE_EMPTY_$vmid\" 70"},{"line":137,"text":"awk '$0 ~ /^\\// || $0 ~ /(^|\\/)\\.\\.(\\/|$)/ {bad=1} END{exit bad}' \"$members\" || die \"RESTORE_LXC_MEMBER_UNSAFE_$vmid\" 70"},{"line":138,"text":"member_count=\"$(wc -l <\"$members\")\"; [[ \"$member_count\" =~ ^[1-9][0-9]*$ ]] || die \"RESTORE_LXC_MEMBER_COUNT_INVALID_$vmid\" 70"},{"line":139,"text":"cfg_member=\"$(awk '$0==\"./etc/vzdump/pct.conf\" || $0==\"etc/vzdump/pct.conf\" {print; exit}' \"$members\")\"; [[ -n \"$cfg_member\" ]] || die \"RESTORE_LXC_CONFIG_MEMBER_MISSING_$vmid\" 70"},{"line":140,"text":"if ( set +o pipefail; stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | zstd -dc | tar -xOf - \"$cfg_member\" >\"$config\" ); then :; else die \"RESTORE_LXC_CONFIG_EXTRACT_FAILED_$vmid\" 70; fi"},{"line":143,"text":"if ( set +o pipefail; stream_cloud_a \"$vmid\" \"$base\" \"$manifest\" \"$work\" | zstd -dc | vma config - >\"$config\" ); then :; else die \"RESTORE_QEMU_CONFIG_EXTRACT_FAILED_$vmid\" 70; fi"},{"line":146,"text":"[[ -s \"$config\" && ! -L \"$config\" ]] || die \"RESTORE_CONFIG_EMPTY_$vmid\" 70; config_sha=\"$(sha256sum \"$config\"|awk '{print $1}')\""},{"line":147,"text":"out=\"$(restore_dir \"$vmid\")/$gen.json\"; mkdir -p \"$(dirname \"$out\")\"; chmod 0700 \"$RESTORE_STATE_ROOT\" \"$(dirname \"$out\")\"; tmp=\"${out}.new.$$\""},{"line":148,"text":"jq -n --arg logical \"$logical\" --arg generation \"$gen\" --argjson vmid \"$vmid\" --arg vm_type \"$VM_TYPE\" --arg state \"$state\" --arg sha \"$expected_sha\" --arg config_sha \"$config_sha\" --arg level \"$level\" --argjson member_count \"$member_count\" --arg at \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" '{schema:\"homelab-vm-restore-validation-v1\",logical_id:$logical,generation:$generation,vmid:$vmid,vm_type:$vm_type,transport_state:\"SEALED\",transport_state_file:$state,restore_source:\"Cloud A\",parts_manifest_verified:true,payload_sha256:$sha,payload_sha256_verified:true,payload_decompression_verified:true,proxmox_config_extract_verified:true,proxmox_config_sha256:$config_sha,lxc_member_count:$member_count,archive_recovery_readback_verified:true,bounded_staging:true,max_staged_part_bytes:536870912,full_local_payload_written:false,full_restore_proven:false,validation_level:$level,result:\"OK\",validated_at_utc:$at}' >\"$tmp\""},{"line":149,"text":"chmod 0600 \"$tmp\"; mv -f -- \"$tmp\" \"$out\"; rm -rf --one-file-system \"$work\"; ACTIVE_RESTORE_STAGE=\"\""},{"line":150,"text":"restore_ok \"$vmid\" \"$gen\" || die \"RESTORE_EVIDENCE_POSTWRITE_INVALID_$vmid\" 70"},{"line":151,"text":"printf 'RESTORE_VALIDATION_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$out\""},{"line":154,"text":"local vmid=\"$1\" owner type status"},{"line":155,"text":"assert_local_identity \"$vmid\""},{"line":156,"text":"owner=\"$(expected_owner \"$vmid\")\""},{"line":157,"text":"type=\"$(expected_type \"$vmid\")\""},{"line":158,"text":"status=\"$(expected_status \"$vmid\")\""},{"line":159,"text":"printf 'PLAN_STATUS=OK\\nVMID=%s\\nOWNER=%s\\nTYPE=%s\\nEXPECTED_STATUS=%s\\n' \"$vmid\" \"$owner\" \"$type\" \"$status\""},{"line":162,"text":"local vmid=\"$1\" generation=\"$2\""},{"line":163,"text":"assert_local_identity \"$vmid\""},{"line":164,"text":"restore_validate \"$vmid\" \"$generation\""},{"line":165,"text":"assert_post_identity \"$vmid\" \"$VM_TYPE\""},{"line":166,"text":"printf 'VERIFY_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$generation\" \"$(restore_dir \"$vmid\")/$generation.json\""},{"line":168,"text":"backup_one(){"},{"line":169,"text":"local vmid=\"$1\" pending_count pending state generation payload gen_dir archive_count archive log_file before_status"},{"line":171,"text":"assert_local_identity \"$vmid\""},{"line":176,"text":"[[ -z \"$(active_backup_restore)\" ]] || die \"ACTIVE_BACKUP_RESTORE_PRESENT\" 75"},{"line":179,"text":"mapfile -t pending < <(latest_incomplete_state \"$vmid\")"},{"line":181,"text":"(( pending_count <= 1 )) || die \"MULTIPLE_INCOMPLETE_GENERATIONS_$vmid\" 65"},{"line":186,"text":"printf 'RESUME=YES\\nVMID=%s\\nGENERATION=%s\\nSTATE=%s\\n' \"$vmid\" \"$generation\" \"$state\""},{"line":187,"text":"\"$TRANSPORT\" backup-delete \"vm${vmid}\" \"$generation\" \"$payload\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\""},{"line":189,"text":"generation=\"vm${vmid}-${HOST}-$(date -u +%Y%m%dT%H%M%SZ)\""},{"line":190,"text":"gen_dir=\"$STAGE_ROOT/vm${vmid}/$generation\""},{"line":195,"text":"printf 'RESUME=NO\\nVMID=%s\\nGENERATION=%s\\n' \"$vmid\" \"$generation\""},{"line":202,"text":"if ! ( umask 0022; exec vzdump \"$vmid\" \"${vzdump_args[@]}\" ) >\"$log_file\" 2>&1; then"},{"line":204,"text":"die \"VZDUMP_FAILED_$vmid\" 70"},{"line":206,"text":"mapfile -t archives < <(find \"$gen_dir\" -maxdepth 1 -type f -name \"vzdump-*-${vmid}-*.zst\" -print)"},{"line":208,"text":"[[ \"$archive_count\" == \"1\" ]] || { rm -rf -- \"$gen_dir\"; die \"VZDUMP_ARCHIVE_COUNT_${vmid}_${archive_count}\" 70; }"},{"line":210,"text":"[[ -s \"$archive\" && ! -L \"$archive\" ]] || die \"VZDUMP_ARCHIVE_UNSAFE_$vmid\" 70"},{"line":212,"text":"\"$TRANSPORT\" backup-delete \"vm${vmid}\" \"$generation\" \"$archive\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\""},{"line":215,"text":"rmdir -- \"$STAGE_ROOT/vm${vmid}\" 2>/dev/null || true"},{"line":217,"text":"assert_post_identity \"$vmid\" \"$VM_TYPE\""},{"line":218,"text":"state=\"$STATE_ROOT/vm${vmid}/$generation.json\""},{"line":220,"text":"restore_validate \"$vmid\" \"$generation\""},{"line":221,"text":"printf 'BACKUP_STATUS=SEALED\\nVMID=%s\\nGENERATION=%s\\nOWNER=%s\\nTYPE=%s\\nPOST_STATUS=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$generation\" \"$HOST\" \"$VM_TYPE\" \"$(expected_status \"$vmid\")\" \"$(restore_dir \"$vmid\")/$generation.json\""},{"line":226,"text":"[[ -z \"$(active_backup_restore)\" ]] || die \"ACTIVE_BACKUP_RESTORE_PRESENT\" 75"},{"line":231,"text":"printf 'HOST_PREFLIGHT_STATUS=OK\\nHOST=%s\\nSTAGING_FREE_BYTES=%s\\nREMOTE_A_FREE_BYTES=%s\\nREMOTE_B_FREE_BYTES=%s\\nACTIVE_BACKUP_RESTORE=0\\n' \"$HOST\" \"$free\" \"$a_free\" \"$b_free\""},{"line":234,"text":"local vmid=\"$1\" dir latest gen"},{"line":235,"text":"assert_local_identity \"$vmid\"; dir=\"$STATE_ROOT/vm${vmid}\""},{"line":236,"text":"[[ -d \"$dir\" ]] || die \"STATE_DIR_MISSING_$vmid\" 65"},{"line":238,"text":"[[ -n \"$latest\" && -s \"$latest\" && ! -L \"$latest\" ]] || die \"LATEST_STATE_MISSING_$vmid\" 65"},{"line":239,"text":"jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .local_payload_present==false and .local_cleanup==\"OK\" and .seal_written==true' \"$latest\" >/dev/null || die \"LATEST_STATE_NOT_SEALED_$vmid\" 65"},{"line":240,"text":"gen=\"$(jq -er '.generation' \"$latest\")\"; restore_ok \"$vmid\" \"$gen\" || die \"LATEST_RESTORE_NOT_OK_$vmid\" 65"},{"line":241,"text":"printf 'LATEST_SEALED_STATUS=OK\\nVMID=%s\\nGENERATION=%s\\nSTATE_FILE=%s\\nRESTORE_EVIDENCE=%s\\n' \"$vmid\" \"$gen\" \"$latest\" \"$(restore_dir \"$vmid\")/$gen.json\""},{"line":244,"text":"case \"$ACTION\" in"},{"line":246,"text":"[[ \"$#\" == 1 ]] || die \"USAGE_HOST_PREFLIGHT\" 64"},{"line":249,"text":"latest-sealed)"},{"line":250,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_LATEST_SEALED\" 64"},{"line":254,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_PLAN\" 64"},{"line":257,"text":"backup)"},{"line":258,"text":"[[ \"$#\" == 2 ]] || die \"USAGE_BACKUP\" 64"},{"line":259,"text":"backup_one \"$2\""},{"line":261,"text":"restore-validate)"},{"line":262,"text":"[[ \"$#\" == 3 ]] || die \"USAGE_RESTORE_VALIDATE\" 64"},{"line":263,"text":"restore_validate \"$2\" \"$3\""},{"line":266,"text":"[[ \"$#\" == 3 ]] || die \"USAGE_VERIFY\" 64"}] +NODEWORKER_CLI_CANDIDATES=[{"kind":"dispatch","text":"case \"$1\" in"},{"kind":"subcommand-token","text":"backup"},{"kind":"subcommand-token","text":"restore"},{"kind":"subcommand-token","text":"latest-sealed"}] +DECISION=DIRECT_NODEWORKER_TARGETED_BACKUP_CLI_DISCOVERED NO_MUTATION=true -TASK_RESULT=PASS_HOMELAB_BACKUP_SCHEDULER_CONTRACT_RCA_READONLY -HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"SUPPORT-260921-HOMELAB-BACKUP-SCHEDULER-CONTRACT-RCA-READONLY-1103R1","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} -WORKERS2_SCHEDULER_CONTRACT_RCA_END=1 +TASK_RESULT=PASS_HOMELAB_BACKUP_NODEWORKER_CONTRACT_RCA_READONLY +HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"SUPPORT-260921-HOMELAB-BACKUP-NODEWORKER-CONTRACT-RCA-READONLY-1104R1","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} +WORKERS2_NODEWORKER_CONTRACT_RCA_END=1 OUTPUT_END CHAT_OUTPUT_END