diff --git a/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.json b/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.json new file mode 100644 index 00000000..e74c15b8 --- /dev/null +++ b/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "newfi-newfdom-messengers214-backupv2-producer-contract-readonly-audit", + "started_at_utc": "2026-09-20T02:01:22Z", + "finished_at_utc": "2026-09-20T02:01:22Z", + "reference_register_checked": true, + "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", + "error_register_checked": true, + "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", + "command_sha256": "ead8fdf05c4cb0a9b8b49f67777a3e68a7a96170d3e4b5061fa03171a66917da", + "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": "99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec", + "sanitized_output_sha256": "99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "NEWFI207_BEGIN=true\nMODE=read-only\nIMMUTABLE_PLAN_CHECK=PASS\nCHANGES_MADE=false\nMUTATION_OUTCOME=NO_MUTATION\nPIN_CHECK=PASS\nACCEPTED_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b\nRELEASE_FILE_COUNT=6\nINTERESTING_FILE_COUNT=6\nFILE_1_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nFILE_1_BYTES=10566\nFILE_1_MODE=0o400\nFILE_1_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\nFILE_1_KEYWORD_SCORE=13\nFILE_1_AST_DEF_COUNT=0\nFILE_1_AST_IMPORT_COUNT=0\nFILE_1_AST_STRING_COUNT=7\nFILE_1_STRING_1_LINE=4\nFILE_1_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nFILE_1_STRING_2_LINE=62\nFILE_1_STRING_2_VALUE=backup_target\nFILE_1_STRING_3_LINE=62\nFILE_1_STRING_3_VALUE=ssh_remote\nFILE_1_STRING_4_LINE=135\nFILE_1_STRING_4_VALUE=payload_sha256\nFILE_1_STRING_5_LINE=135\nFILE_1_STRING_5_VALUE=manifest_sha256\nFILE_1_STRING_6_LINE=135\nFILE_1_STRING_6_VALUE=replicas\nFILE_1_STRING_7_LINE=132\nFILE_1_STRING_7_VALUE=homelab-scheduler-proof-\nFILE_2_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nFILE_2_BYTES=13825\nFILE_2_MODE=0o400\nFILE_2_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\nFILE_2_KEYWORD_SCORE=9\nFILE_2_AST_DEF_COUNT=2\nFILE_2_DEF_1_LINE=35\nFILE_2_DEF_1_NAME=_remote_sha\nFILE_2_DEF_2_LINE=117\nFILE_2_DEF_2_NAME=_execute_remote\nFILE_2_AST_IMPORT_COUNT=0\nFILE_2_AST_STRING_COUNT=17\nFILE_2_STRING_1_LINE=79\nFILE_2_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-plan-only\nFILE_2_STRING_2_LINE=118\nFILE_2_STRING_2_VALUE=REMOTE_NODE\nFILE_2_STRING_3_LINE=119\nFILE_2_STRING_3_VALUE=REMOTE_ARGV\nFILE_2_STRING_4_LINE=120\nFILE_2_STRING_4_VALUE=REMOTE_ARGV_NODE\nFILE_2_STRING_5_LINE=121\nFILE_2_STRING_5_VALUE=REMOTE_CAP_VALUE\nFILE_2_STRING_6_LINE=124\nFILE_2_STRING_6_VALUE=REMOTE_WORKDIR\nFILE_2_STRING_7_LINE=158\nFILE_2_STRING_7_VALUE=remote-bounded-ssh-cwd-root\nFILE_2_STRING_8_LINE=198\nFILE_2_STRING_8_VALUE=/var/tmp/homelab-vzdump-v2-\nFILE_2_STRING_9_LINE=149\nFILE_2_STRING_9_VALUE=REMOTE_TIMEOUT\nFILE_2_STRING_10_LINE=151\nFILE_2_STRING_10_VALUE=REMOTE_RC\nFILE_2_STRING_11_LINE=152\nFILE_2_STRING_11_VALUE=REMOTE_EMPTY\nFILE_2_STRING_12_LINE=155\nFILE_2_STRING_12_VALUE=REMOTE_FILE_IDENTITY\nFILE_2_STRING_13_LINE=162\nFILE_2_STRING_13_VALUE=remote-bounded-ssh-cwd-root\nFILE_2_STRING_14_LINE=204\nFILE_2_STRING_14_VALUE=payload.bin\nFILE_2_STRING_15_LINE=210\nFILE_2_STRING_15_VALUE=VZDUMP_PAYLOAD_BOUND\nFILE_2_STRING_16_LINE=138\nFILE_2_STRING_16_VALUE=REMOTE_TIMEOUT\nFILE_2_STRING_17_LINE=143\nFILE_2_STRING_17_VALUE=REMOTE_CAP\nFILE_3_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\nFILE_3_BYTES=4627\nFILE_3_MODE=0o400\nFILE_3_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\nFILE_3_KEYWORD_SCORE=9\nFILE_3_AST_DEF_COUNT=1\nFILE_3_DEF_1_LINE=11\nFILE_3_DEF_1_NAME=_remote_sha\nFILE_3_AST_IMPORT_COUNT=0\nFILE_3_AST_STRING_COUNT=3\nFILE_3_STRING_1_LINE=48\nFILE_3_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-\nFILE_3_STRING_2_LINE=66\nFILE_3_STRING_2_VALUE=payload.bin\nFILE_3_STRING_3_LINE=70\nFILE_3_STRING_3_VALUE=QEMU_PAYLOAD_MISSING\nFILE_4_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nFILE_4_BYTES=4097\nFILE_4_MODE=0o400\nFILE_4_SHA256=a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\nFILE_4_KEYWORD_SCORE=9\nFILE_4_AST_DEF_COUNT=0\nFILE_4_AST_IMPORT_COUNT=0\nFILE_4_AST_STRING_COUNT=9\nFILE_4_STRING_1_LINE=44\nFILE_4_STRING_1_VALUE=last_success_payload_sha256\nFILE_4_STRING_2_LINE=45\nFILE_4_STRING_2_VALUE=last_success_manifest_sha256\nFILE_4_STRING_3_LINE=45\nFILE_4_STRING_3_VALUE=last_success_replicas\nFILE_4_STRING_4_LINE=37\nFILE_4_STRING_4_VALUE=payload_sha256\nFILE_4_STRING_5_LINE=37\nFILE_4_STRING_5_VALUE=last_success_payload_sha256\nFILE_4_STRING_6_LINE=38\nFILE_4_STRING_6_VALUE=manifest_sha256\nFILE_4_STRING_7_LINE=38\nFILE_4_STRING_7_VALUE=last_success_manifest_sha256\nFILE_4_STRING_8_LINE=38\nFILE_4_STRING_8_VALUE=replicas\nFILE_4_STRING_9_LINE=38\nFILE_4_STRING_9_VALUE=last_success_replicas\nFILE_5_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nFILE_5_BYTES=3449\nFILE_5_MODE=0o400\nFILE_5_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\nFILE_5_KEYWORD_SCORE=7\nFILE_5_AST_DEF_COUNT=0\nFILE_5_AST_IMPORT_COUNT=0\nFILE_5_AST_STRING_COUNT=2\nFILE_5_STRING_1_LINE=4\nFILE_5_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411\nFILE_5_STRING_2_LINE=45\nFILE_5_STRING_2_VALUE=payload.bin\nFILE_6_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nFILE_6_BYTES=2320\nFILE_6_MODE=0o400\nFILE_6_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\nFILE_6_KEYWORD_SCORE=3\nFILE_6_AST_DEF_COUNT=0\nFILE_6_AST_IMPORT_COUNT=0\nFILE_6_AST_STRING_COUNT=1\nFILE_6_STRING_1_LINE=4\nFILE_6_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nCTX_1_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_1_START_LINE=15\nCTX_1_END_LINE=21\nCTX_1_L15=}\nCTX_1_L16=\nCTX_1_L17=def _sha(p):\nCTX_1_L18= h=hashlib.sha256()\nCTX_1_L19= with open(p,'rb',buffering=0) as f:\nCTX_1_L20= while True:\nCTX_1_L21= b=f.read(1<<20)\nCTX_2_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_2_START_LINE=34\nCTX_2_END_LINE=40\nCTX_2_L34=\nCTX_2_L35=class _GlobalsProxy:\nCTX_2_L36= __slots__=('_g',)\nCTX_2_L37= def __init__(self,g): object.__setattr__(self,'_g',g)\nCTX_2_L38= def __getattr__(self,n):\nCTX_2_L39= try: return self._g[n]\nCTX_2_L40= except KeyError as e: raise AttributeError(n) from e\nCTX_3_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_3_START_LINE=59\nCTX_3_END_LINE=72\nCTX_3_L59= if len(found)!=1:\nCTX_3_L60= raise RuntimeError('LEGACY_PROVENANCE_CARDINALITY')\nCTX_3_L61= g=next(iter(found.values()))\nCTX_3_L62= required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\nCTX_3_L63= '_default_unprivileged_lxc','mapped_scratch_probe','_stream_argv_to_local','run',\nCTX_3_L64= 'choose_due_target','write_state','epoch')\nCTX_3_L65= if any(not callable(g.get(n)) for n in required):\nCTX_3_L66= raise RuntimeError('LEGACY_PROVENANCE_API')\nCTX_3_L67= original=g['capture_pve_guest']\nCTX_3_L68= proxy=_GlobalsProxy(g)\nCTX_3_L69= if not isinstance(g.get('SCP'),str) or not g['SCP'].startswith('/'):\nCTX_3_L70= raise RuntimeError('LEGACY_SCP_API')\nCTX_3_L71= qemu_patched=qemu_adapter.bind(proxy,original)\nCTX_3_L72= if not callable(qemu_patched):\nCTX_4_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_4_START_LINE=75\nCTX_4_END_LINE=82\nCTX_4_L75= if not callable(patched):\nCTX_4_L76= raise RuntimeError('LXC_ADAPTER_BIND_RESULT')\nCTX_4_L77= g['capture_pve_guest']=patched\nCTX_4_L78= scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\nCTX_4_L79= if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\nCTX_4_L80= raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\nCTX_4_L81= return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\nCTX_4_L82=\nCTX_5_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_5_START_LINE=96\nCTX_5_END_LINE=117\nCTX_5_L96= wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\nCTX_5_L97= return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\nCTX_5_L98=\nCTX_5_L99=def _target(wrapper,lid):\nCTX_5_L100= rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\nCTX_5_L101= if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\nCTX_5_L102= return hits[0]\nCTX_5_L103=\nCTX_5_L104=def selftest():\nCTX_5_L105= wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\nCTX_5_L106= if wired['legacy_globals'].get('capture_pve_guest') is not wired['patched_capture']:\nCTX_5_L107= raise RuntimeError('PATCH_BINDING')\nCTX_5_L108= if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\nCTX_5_L109= raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\nCTX_5_L110= if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\nCTX_5_L111= raise RuntimeError('SCHEDULER_WRITE_BINDING')\nCTX_5_L112= if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\nCTX_5_L113= raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\nCTX_5_L114= if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\nCTX_5_L115= raise RuntimeError('WRAPPER_PUBLIC_API')\nCTX_5_L116= print('SELFTEST_OVERLAY504=PASS',flush=True)\nCTX_5_L117= return 0\nCTX_6_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_6_START_LINE=125\nCTX_6_END_LINE=187\nCTX_6_L125= if argv==['scheduler-proof']:\nCTX_6_L126= import tempfile\nCTX_6_L127= legacy=wired['legacy']; g=wired['legacy_globals']\nCTX_6_L128= old_root=g.get('STATE_ROOT'); old_epoch=g.get('epoch')\nCTX_6_L129= if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\nCTX_6_L130= now=[1000]\nCTX_6_L131= try:\nCTX_6_L132= with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\nCTX_6_L133= g['STATE_ROOT']=pathlib.Path(td); (g['STATE_ROOT']/'state').mkdir(mode=0o700)\nCTX_6_L134= g['epoch']=lambda: now[0]\nCTX_6_L135= common={'payload_sha256':'a'*64,'manifest_sha256':'b'*64,'replicas':['proof-r1','proof-r2']}\nCTX_6_L136= legacy.write_state('proof-a','SUCCESS',generation='proof-a-good',**common)\nCTX_6_L137= legacy.write_state('proof-b','SUCCESS',generation='proof-b-good',**common)\nCTX_6_L138= now[0]=100000\nCTX_6_L139= legacy.write_state('proof-a','FAIL',generation='proof-a-bad',reason='PROOF_FAILURE',sealed=False)\nCTX_6_L140= state=legacy.load_state_all(); a=state['proof-a']\nCTX_6_L141= targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\nCTX_6_L142= first=legacy.choose_due_target(targets,state,now[0])\nCTX_6_L143= if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\nCTX_6_L144= retry=int(a.get('retry_after_epoch',0)); preserved=int(a.get('last_success_epoch',0))\nCTX_6_L145= if preserved!=1000 or a.get('last_success_generation')!='proof-a-good' or int(a.get('consecutive_failures',0))!=1 or retry!=101800:\nCTX_6_L146= raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\nCTX_6_L147= now[0]=retry+1\nCTX_6_L148= second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\nCTX_6_L149= if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\nCTX_6_L150= legacy.write_state('proof-a','SUCCESS',generation='proof-a-recovered',**common)\nCTX_6_L151= recovered=legacy.load_state_all()['proof-a']\nCTX_6_L152= if int(recovered.get('consecutive_failures',-1))!=0 or int(recovered.get('retry_after_epoch',-1))!=0:\nCTX_6_L153= raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\nCTX_6_L154= 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}\nCTX_6_L155= print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\nCTX_6_L156= return 0\nCTX_6_L157= finally:\nCTX_6_L158= g['STATE_ROOT']=old_root; g['epoch']=old_epoch\nCTX_6_L159= if argv==['scheduler-select-live']:\nCTX_6_L160= state=legacy.load_state_all(); targets=wrapper.load_targets()\nCTX_6_L161= chosen=legacy.choose_due_target(targets,state)\nCTX_6_L162= if chosen is None:\nCTX_6_L163= print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\nCTX_6_L164= else:\nCTX_6_L165= 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)\nCTX_6_L166= return 0\nCTX_6_L167= if len(argv)==2 and argv[0]=='plan-lxc':\nCTX_6_L168= t=_target(wrapper,argv[1])\nCTX_6_L169= if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\nCTX_6_L170= raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\nCTX_6_L171= out=lxc_adapter.plan_only(legacy,t)\nCTX_6_L172= 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)\nCTX_6_L173= return 0\nCTX_6_L174= if len(argv)==2 and argv[0]=='verify-target':\nCTX_6_L175= t=_target(wrapper,argv[1])\nCTX_6_L176= if t.get('logical_id')=='guest-pve01-lxc-112':\nCTX_6_L177= raise RuntimeError('VERIFY_SYNTHETIC_CT112_FORBIDDEN')\nCTX_6_L178= try:\nCTX_6_L179= out=wrapper.backup_target(t,True)\nCTX_6_L180= except legacy.BackupError as e:\nCTX_6_L181= print('VERIFY_TARGET_RESULT=FAIL',flush=True)\nCTX_6_L182= print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\nCTX_6_L183= return 2\nCTX_6_L184= print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\nCTX_6_L185= return 0\nCTX_6_L186= return wrapper.main([sys.argv[0],*argv])\nCTX_6_L187=\nCTX_7_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_7_START_LINE=20\nCTX_7_END_LINE=26\nCTX_7_L20= except Exception as e: raise AdapterError(code) from e\nCTX_7_L21=\nCTX_7_L22=def _sha_file(p):\nCTX_7_L23= h=hashlib.sha256()\nCTX_7_L24= with open(p,'rb',buffering=0) as f:\nCTX_7_L25= for b in iter(lambda:f.read(1<<20),b''): h.update(b)\nCTX_7_L26= return h.hexdigest()\nCTX_8_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_8_START_LINE=32\nCTX_8_END_LINE=62\nCTX_8_L32= if n<=0: raise AdapterError('WRITE_FAILED')\nCTX_8_L33= view=view[n:]\nCTX_8_L34=\nCTX_8_L35=def _remote_sha(legacy,node,path):\nCTX_8_L36= p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\nCTX_8_L37= parts=p.stdout.decode('ascii','strict').strip().split()\nCTX_8_L38= _need(len(parts)>=2 and parts[1]==path,'TOOL_SHA_OUTPUT')\nCTX_8_L39= return parts[0]\nCTX_8_L40=\nCTX_8_L41=def _live_inputs(legacy,node,vmid,scratch):\nCTX_8_L42= _need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')\nCTX_8_L43= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')\nCTX_8_L44= rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')\nCTX_8_L45= stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')\nCTX_8_L46= _need(type(rows) is list and type(stores) is list,'PVE_LIST_SCHEMA')\nCTX_8_L47= configs=[]\nCTX_8_L48= for r in rows:\nCTX_8_L49= if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue\nCTX_8_L50= try: rid=int(r.get('vmid'))\nCTX_8_L51= except Exception: raise AdapterError('RESOURCE_VMID')\nCTX_8_L52= cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\"type\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')\nCTX_8_L53= _need(type(cfg) is dict,'CONFIG_SCHEMA')\nCTX_8_L54= configs.append([rid,cfg])\nCTX_8_L55= tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')\nCTX_8_L56= _need(type(tasks) is list and len(tasks)<1000,'TASKS_SCHEMA')\nCTX_8_L57= q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)\nCTX_8_L58= defaults=None\nCTX_8_L59= if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout\nCTX_8_L60= elif q.returncode!=1: raise AdapterError('DEFAULTS_PROBE')\nCTX_8_L61= st=os.statvfs('/mnt/staging'); free=int(st.f_bavail*st.f_frsize)\nCTX_8_L62= return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,\nCTX_9_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_9_START_LINE=85\nCTX_9_END_LINE=91\nCTX_9_L85= a=_helper(_live_inputs(legacy,node,vmid,scratch)); b=_helper(_live_inputs(legacy,node,vmid,scratch))\nCTX_9_L86= _need(_stable_job(a['job'])==_stable_job(b['job']),'FRESH_PLAN_UNSTABLE')\nCTX_9_L87= _need(a['argv']==b['argv'],'FRESH_ARGV_UNSTABLE')\nCTX_9_L88= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_POST')\nCTX_9_L89= return b\nCTX_9_L90=\nCTX_9_L91=def _execute_local(legacy,node,argv,dest,cap,timeout):\nCTX_10_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_10_START_LINE=94\nCTX_10_END_LINE=109\nCTX_10_L94= data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode()\nCTX_10_L95= p=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV)\nCTX_10_L96= if p.stderr or not p.stdout or len(p.stdout)>262144:\nCTX_10_L97= raise ExecFailure('LOCAL_HELPER_PROTOCOL',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)})\nCTX_10_L98= try: out=json.loads(p.stdout)\nCTX_10_L99= except Exception:\nCTX_10_L100= raise ExecFailure('LOCAL_HELPER_JSON',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)})\nCTX_10_L101= summary={'executor':'local-proven-pve270','helper_rc':p.returncode,'exception_class':out.get('exception_class'),'exception_message_sha256':out.get('exception_message_sha256')}\nCTX_10_L102= if isinstance(out.get('process'),dict): summary.update(out['process'])\nCTX_10_L103= if p.returncode!=0 or out.get('status')!='OK': raise ExecFailure('LOCAL_PRODUCER_FAILED',summary)\nCTX_10_L104= result=out.get('result'); _need(type(result) is dict,'LOCAL_RESULT_SCHEMA')\nCTX_10_L105= _need(pathlib.Path(dest).is_file() and pathlib.Path(dest).stat().st_size==int(result.get('size',-1)),'LOCAL_RESULT_FILE')\nCTX_10_L106= return summary|{'size':result['size'],'sha256':result['sha256'],'producer_rc':result.get('producer_rc')}\nCTX_10_L107=\nCTX_10_L108=def _kill(p):\nCTX_10_L109= try: os.killpg(p.pid,signal.SIGTERM)\nCTX_11_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_11_START_LINE=114\nCTX_11_END_LINE=166\nCTX_11_L114= except ProcessLookupError: pass\nCTX_11_L115= p.wait()\nCTX_11_L116=\nCTX_11_L117=def _execute_remote(legacy,node,argv,dest,cap,timeout):\nCTX_11_L118= _need(re.fullmatch(r'pve0[123]',str(node)) is not None and node!='pve01','REMOTE_NODE')\nCTX_11_L119= _need(type(argv) is list and argv and argv[0]=='/usr/bin/vzdump' and all(type(x) is str and '\\x00' not in x for x in argv),'REMOTE_ARGV')\nCTX_11_L120= _need('--node' in argv and argv[argv.index('--node')+1]==node,'REMOTE_ARGV_NODE')\nCTX_11_L121= _need(type(cap) is int and 0=deadline: raise ExecFailure('REMOTE_TIMEOUT',{})\nCTX_11_L139= for key,_ in sel.select(min(.2,max(0,deadline-now))):\nCTX_11_L140= b=os.read(key.fileobj.fileno(),65536)\nCTX_11_L141= if not b: sel.unregister(key.fileobj); continue\nCTX_11_L142= if key.fileobj is p.stdout:\nCTX_11_L143= if total+len(b)>cap: raise ExecFailure('REMOTE_CAP',{})\nCTX_11_L144= _write_all(fd,b); digest.update(b); total+=len(b)\nCTX_11_L145= else:\nCTX_11_L146= err_total+=len(b); eh.update(b); keep=b[:max(0,MAX_STDERR-err_kept)]\nCTX_11_L147= if keep: _write_all(efd,keep); err_kept+=len(keep)\nCTX_11_L148= left=deadline-time.monotonic()\nCTX_11_L149= if left<=0: raise ExecFailure('REMOTE_TIMEOUT',{})\nCTX_11_L150= rc=p.wait(timeout=left)\nCTX_11_L151= if rc!=0: raise ExecFailure('REMOTE_RC',{})\nCTX_11_L152= if total<=0: raise ExecFailure('REMOTE_EMPTY',{})\nCTX_11_L153= stf=os.fstat(fd); named=os.stat(dest,follow_symlinks=False)\nCTX_11_L154= if (stf.st_dev,stf.st_ino)!=(initial.st_dev,initial.st_ino) or (named.st_dev,named.st_ino)!=(initial.st_dev,initial.st_ino) or stf.st_nlink!=1 or stf.st_size!=total:\nCTX_11_L155= raise ExecFailure('REMOTE_FILE_IDENTITY',{})\nCTX_11_L156= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_EXEC_POST')\nCTX_11_L157= os.fchmod(fd,0o400); os.fsync(fd); os.fsync(efd); good=True\nCTX_11_L158= return {'executor':'remote-bounded-ssh-cwd-root','producer_rc':rc,'size':total,'sha256':digest.hexdigest(),\nCTX_11_L159= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}\nCTX_11_L160= except ExecFailure as e:\nCTX_11_L161= if p is not None and p.poll() is None: _kill(p)\nCTX_11_L162= summary={'executor':'remote-bounded-ssh-cwd-root','producer_rc':None if p is None else p.returncode,'archive_bytes':total,\nCTX_11_L163= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}\nCTX_11_L164= summary.update(e.summary); raise ExecFailure(e.code,summary)\nCTX_11_L165= finally:\nCTX_11_L166= if p is not None:\nCTX_12_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_12_START_LINE=171\nCTX_12_END_LINE=178\nCTX_12_L171= try: os.fsync(fd); os.fsync(efd)\nCTX_12_L172= except OSError: pass\nCTX_12_L173= os.close(fd); os.close(efd)\nCTX_12_L174= summary={'process_started':p is not None,'producer_rc':None if p is None else p.returncode,'capture_success':good,'archive_bytes':total,\nCTX_12_L175= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest(),'raw_stderr_exported':False,'cwd':'/'}\nCTX_12_L176= try:\nCTX_12_L177= mb=(json.dumps(summary,separators=(',',':'),sort_keys=True)+'\\n').encode()\nCTX_12_L178= mfd=os.open(metap,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)\nCTX_13_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_13_START_LINE=182\nCTX_13_END_LINE=188\nCTX_13_L182=\nCTX_13_L183=def _emit_diag(node,summary):\nCTX_13_L184= safe={'node':node}\nCTX_13_L185= for k in ('executor','failure_code','helper_rc','producer_rc','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','exception_class','exception_message_sha256'):\nCTX_13_L186= if k in summary: safe[k]=summary[k]\nCTX_13_L187= print('LXC_EXECUTION_DIAG='+json.dumps(safe,separators=(',',':'),sort_keys=True),flush=True)\nCTX_13_L188=\nCTX_14_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_14_START_LINE=196\nCTX_14_END_LINE=218\nCTX_14_L196= _need(typ==t.get('guest_type')=='lxc','PVE_GUEST_TYPE_DRIFT')\nCTX_14_L197= legacy._default_unprivileged_lxc(node,vmid)\nCTX_14_L198= scratch=f'/var/tmp/homelab-vzdump-v2-{gen}'\nCTX_14_L199= legacy.ssh_remote(node,['install','-d','-m','710','-o','0','-g','100000',scratch],timeout=30)\nCTX_14_L200= q=legacy.ssh_remote(node,['stat','-c','%a:%u:%g',scratch],timeout=30)\nCTX_14_L201= _need(q.stdout.decode().strip()=='710:0:100000','PVE_MAPPED_SCRATCH_ACCESS_CONTRACT')\nCTX_14_L202= try:\nCTX_14_L203= legacy.mapped_scratch_probe(node,scratch)\nCTX_14_L204= p=plan_only(legacy,t,scratch); local=pathlib.Path(work)/'payload.bin'; cap=int(p['job']['archive_cap_bytes'])\nCTX_14_L205= try:\nCTX_14_L206= result=_execute_local(legacy,node,p['argv'],local,cap,7200) if node=='pve01' else _execute_remote(legacy,node,p['argv'],local,cap,7200)\nCTX_14_L207= except ExecFailure as e:\nCTX_14_L208= _emit_diag(node,e.summary|{'failure_code':e.code})\nCTX_14_L209= raise legacy.BackupError('LXC_PRODUCER_FAILED') from None\nCTX_14_L210= _need(local.is_file() and 0=2 and parts[1]==path,'QEMU_TOOL_SHA_OUTPUT')\nCTX_15_L15= return parts[0]\nCTX_15_L16=\nCTX_15_L17=def _select_qemu_outputs(vmid,files):\nCTX_15_L18= _need(type(vmid) is int and vmid>0,'QEMU_VMID')\nCTX_15_L19= _need(type(files) is list and files and all(type(x) is str and x.startswith('/') and '\\x00' not in x for x in files),'QEMU_OUTPUT_LIST')\nCTX_15_L20= _need(len(files)==len(set(files)),'QEMU_OUTPUT_DUPLICATE')\nCTX_15_L21= 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$')\nCTX_15_L22= archives=[]\nCTX_15_L23= for f in files:\nCTX_15_L24= name=pathlib.PurePosixPath(f).name\nCTX_15_L25= m=pat.fullmatch(name)\nCTX_15_L26= if m: archives.append((f,m.group(1)))\nCTX_15_L27= _need(len(archives)==1,'QEMU_ARCHIVE_NOT_UNIQUE')\nCTX_15_L28= archive,stamp=archives[0]; parent=pathlib.PurePosixPath(archive).parent\nCTX_15_L29= expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\nCTX_15_L30= allowed={archive}; log=None\nCTX_15_L31= if str(expected_log) in files:\nCTX_15_L32= log=str(expected_log); allowed.add(log)\nCTX_15_L33= _need(set(files)==allowed,'QEMU_OUTPUT_UNEXPECTED_FILE')\nCTX_15_L34= return archive,log\nCTX_15_L35=\nCTX_15_L36=def _emit_diag(**kw):\nCTX_15_L37= print('QEMU_EXECUTION_DIAG='+json.dumps(kw,separators=(',',':'),sort_keys=True),flush=True)\nCTX_16_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\nCTX_16_START_LINE=44\nCTX_16_END_LINE=78\nCTX_16_L44= _need(len(rows)==1,'PVE_GUEST_NOT_UNIQUE')\nCTX_16_L45= row=rows[0]; node=row.get('node'); typ=row.get('type')\nCTX_16_L46= _need(typ==t.get('guest_type')=='qemu','PVE_GUEST_TYPE_DRIFT')\nCTX_16_L47= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\nCTX_16_L48= srcdir=f'/var/tmp/homelab-vzdump-v2-{gen}'\nCTX_16_L49= legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\nCTX_16_L50= try:\nCTX_16_L51= vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\nCTX_16_L52= if vp.returncode!=0:\nCTX_16_L53= _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)\nCTX_16_L54= raise legacy.BackupError('QEMU_VZDUMP_FAILED')\nCTX_16_L55= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\nCTX_16_L56= p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)\nCTX_16_L57= files=[x for x in p.stdout.decode('utf-8','strict').splitlines() if x]\nCTX_16_L58= try: src,log=_select_qemu_outputs(vmid,files)\nCTX_16_L59= except QemuAdapterError as e:\nCTX_16_L60= _emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\nCTX_16_L61= raise legacy.BackupError(str(e)) from None\nCTX_16_L62= q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\nCTX_16_L63= raw=q.stdout.decode('ascii','strict').strip()\nCTX_16_L64= _need(raw.isdigit() and int(raw)>0,'QEMU_ARCHIVE_STAT')\nCTX_16_L65= size=int(raw)\nCTX_16_L66= local=pathlib.Path(work)/'payload.bin'\nCTX_16_L67= if node=='pve01': local=pathlib.Path(src)\nCTX_16_L68= else:\nCTX_16_L69= legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\nCTX_16_L70= _need(pathlib.Path(local).is_file() and pathlib.Path(local).stat().st_size==size,'QEMU_PAYLOAD_MISSING')\nCTX_16_L71= _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)\nCTX_16_L72= except Exception:\nCTX_16_L73= legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\nCTX_16_L74= cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\nCTX_16_L75= meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\nCTX_16_L76= 'producer_contract':'strict-qemu-vma-zst-plus-matching-log-overlay503'}\nCTX_16_L77= return pathlib.Path(local),meta,cleanup\nCTX_16_L78= capture_pve_guest.__name__='capture_pve_guest'\nCTX_17_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_17_START_LINE=20\nCTX_17_END_LINE=28\nCTX_17_L20= n=max(1,_as_nonneg_int(consecutive_failures,1))\nCTX_17_L21= return min(MAX_BACKOFF,MIN_BACKOFF*(2**min(n-1,4)))\nCTX_17_L22=\nCTX_17_L23=def _read_prior(legacy,logical_id):\nCTX_17_L24= root=pathlib.Path(legacy.STATE_ROOT)/'state'\nCTX_17_L25= p=root/(str(logical_id)+'.json')\nCTX_17_L26= try:\nCTX_17_L27= if not p.is_file(): return {}\nCTX_17_L28= d=json.loads(p.read_text(encoding='utf-8'))\nCTX_18_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_18_START_LINE=34\nCTX_18_END_LINE=48\nCTX_18_L34= if not isinstance(prior,dict): return {}\nCTX_18_L35= if prior.get('result')=='SUCCESS':\nCTX_18_L36= out={'last_success_epoch':_as_nonneg_int(prior.get('last_success_epoch'),0)}\nCTX_18_L37= mapping=(('generation','last_success_generation'),('payload_sha256','last_success_payload_sha256'),\nCTX_18_L38= ('manifest_sha256','last_success_manifest_sha256'),('replicas','last_success_replicas'),\nCTX_18_L39= ('green_verified','last_success_green_verified'))\nCTX_18_L40= for src,dst in mapping:\nCTX_18_L41= if src in prior: out[dst]=prior[src]\nCTX_18_L42= return out\nCTX_18_L43= out={}\nCTX_18_L44= for k in ('last_success_epoch','last_success_generation','last_success_payload_sha256',\nCTX_18_L45= 'last_success_manifest_sha256','last_success_replicas','last_success_green_verified'):\nCTX_18_L46= if k in prior: out[k]=prior[k]\nCTX_18_L47= return out\nCTX_18_L48=\nCTX_19_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_19_START_LINE=50\nCTX_19_END_LINE=65\nCTX_19_L50= _need(callable(original_choose),'ORIGINAL_CHOOSE_REQUIRED')\nCTX_19_L51= _need(callable(original_write),'ORIGINAL_WRITE_REQUIRED')\nCTX_19_L52= _need(callable(getattr(legacy,'epoch',None)),'LEGACY_EPOCH_REQUIRED')\nCTX_19_L53= _need(hasattr(legacy,'STATE_ROOT'),'LEGACY_STATE_ROOT_REQUIRED')\nCTX_19_L54=\nCTX_19_L55= def choose_due_target(targets,state,now=None):\nCTX_19_L56= now=_as_nonneg_int(legacy.epoch() if now is None else now,0)\nCTX_19_L57= _need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\nCTX_19_L58= due=[]\nCTX_19_L59= for order,t in enumerate(targets):\nCTX_19_L60= if not isinstance(t,dict) or t.get('enabled') is not True: continue\nCTX_19_L61= lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\nCTX_19_L62= _need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\nCTX_19_L63= s=state.get(lid,{})\nCTX_19_L64= if not isinstance(s,dict): s={}\nCTX_19_L65= retry_after=_as_nonneg_int(s.get('retry_after_epoch'),0)\nCTX_20_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_20_START_LINE=72\nCTX_20_END_LINE=93\nCTX_20_L72= if not due: return None\nCTX_20_L73= return max(due,key=lambda x:(x[0],x[1]))[2]\nCTX_20_L74=\nCTX_20_L75= def write_state(logical_id,result,**kw):\nCTX_20_L76= now=_as_nonneg_int(legacy.epoch(),0)\nCTX_20_L77= prior=_read_prior(legacy,logical_id)\nCTX_20_L78= if result=='SUCCESS':\nCTX_20_L79= clean=dict(kw)\nCTX_20_L80= clean.update({'last_attempt_epoch':now,'consecutive_failures':0,'retry_after_epoch':0,'failure_backoff_seconds':0})\nCTX_20_L81= return original_write(logical_id,result,**clean)\nCTX_20_L82= failures=_as_nonneg_int(prior.get('consecutive_failures'),0)+1\nCTX_20_L83= backoff=backoff_seconds(failures)\nCTX_20_L84= clean=dict(kw)\nCTX_20_L85= clean.update(_success_snapshot(prior))\nCTX_20_L86= clean.update({'last_attempt_epoch':now,'consecutive_failures':failures,\nCTX_20_L87= 'retry_after_epoch':now+backoff,'failure_backoff_seconds':backoff})\nCTX_20_L88= return original_write(logical_id,result,**clean)\nCTX_20_L89=\nCTX_20_L90= legacy.choose_due_target=choose_due_target\nCTX_20_L91= legacy.write_state=write_state\nCTX_20_L92= return {'choose_due_target':choose_due_target,'write_state':write_state,\nCTX_20_L93= 'original_choose':original_choose,'original_write':original_write}\nCTX_21_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_21_START_LINE=7\nCTX_21_END_LINE=13\nCTX_21_L7=MAX_INPUT=262144\nCTX_21_L8=\nCTX_21_L9=def sha_file(p:pathlib.Path)->str:\nCTX_21_L10= h=hashlib.sha256()\nCTX_21_L11= with open(p,'rb',buffering=0) as f:\nCTX_21_L12= for b in iter(lambda:f.read(1<<20),b''): h.update(b)\nCTX_21_L13= return h.hexdigest()\nCTX_22_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_22_START_LINE=20\nCTX_22_END_LINE=33\nCTX_22_L20= if not p.is_file() or p.is_symlink(): return None\nCTX_22_L21= try: d=json.loads(p.read_bytes())\nCTX_22_L22= except Exception: return {'summary_read':'FAILED'}\nCTX_22_L23= keys=('process_started','producer_rc','capture_success','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','raw_stderr_exported','child_umask')\nCTX_22_L24= return {k:d.get(k) for k in keys if k in d}\nCTX_22_L25=\nCTX_22_L26=def selftest()->int:\nCTX_22_L27= if sha_file(VZDUMP)!=VZDUMP_SHA: fail('VZDUMP_IDENTITY')\nCTX_22_L28= sys.path.insert(0,str(BASE))\nCTX_22_L29= import adapter\nCTX_22_L30= adapter.verify_sources(); adapter.load_graph()\nCTX_22_L31= print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\nCTX_22_L32= return 0\nCTX_22_L33=\nCTX_23_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_23_START_LINE=42\nCTX_23_END_LINE=66\nCTX_23_L42= argv=x['argv']; dest=pathlib.Path(x['dest']); cap=x['cap']; seconds=x['seconds']\nCTX_23_L43= 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')\nCTX_23_L44= if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\nCTX_23_L45= if not (dest.is_absolute() and dest.name=='payload.bin' and '..' not in dest.parts): fail('DEST')\nCTX_23_L46= if not (type(cap) is int and 0str:\nCTX_25_L9= return hashlib.sha256(p.read_bytes()).hexdigest()\nCTX_25_L10=\nCTX_25_L11=def fail(code:str):\nCTX_25_L12= raise RuntimeError(code)\nCTX_26_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nCTX_26_START_LINE=17\nCTX_26_END_LINE=23\nCTX_26_L17= if not p.is_file() or p.is_symlink() or sha(p)!=PVE265_SHA: fail('PVE265_IDENTITY')\nCTX_26_L18= sys.path.insert(0,str(C411))\nCTX_26_L19= import adapter\nCTX_26_L20= adapter.verify_sources()\nCTX_26_L21= guest266,pve265,_pve270,_pve282=adapter.load_graph()\nCTX_26_L22= data=sys.stdin.buffer.read(4_000_001)\nCTX_26_L23= if not data or len(data)>4_000_000: fail('INPUT_BOUND')\nCTX_27_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nCTX_27_START_LINE=36\nCTX_27_END_LINE=42\nCTX_27_L36= if job.get('configured_full_cycle_fits') is not True or job.get('compression_dependent') is not False: fail('JOB_CAPACITY_POLICY')\nCTX_27_L37= guest266.no_active_tasks(raw.get('tasks'),vmid)\nCTX_27_L38= argv=pve265.dump_argv(job,'/usr/bin/vzdump',scratch,now)\nCTX_27_L39= 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')\nCTX_27_L40= out={'schema':1,'argv':argv,'job':{k:job.get(k) for k in keep}}\nCTX_27_L41= sys.stdout.write(json.dumps(out,separators=(',',':'),sort_keys=True)+'\\n')\nCTX_27_L42= return 0\nUSA_STATE_FULL_SAFE_BEGIN=true\nUSA_STATE_FIELD=$.consecutive_failures=0\nUSA_STATE_FIELD=$.failure_backoff_seconds=0\nUSA_STATE_FIELD=$.generation=v2-md-relay-20260919T070058Z-0e409ea129e2\nUSA_STATE_FIELD=$.green_verified=False\nUSA_STATE_FIELD=$.last_attempt_epoch=1789801278\nUSA_STATE_FIELD=$.last_success_epoch=1789801278\nUSA_STATE_FIELD=$.logical_id=md-relay\nUSA_STATE_FIELD=$.manifest_sha256=6887c5423640738aeb2bc1d104d515df1d1a21e2cd2d3291481475aa81cb6838\nUSA_STATE_FIELD=$.payload_sha256=187401a5fbf6c29b4dfd77e5d272db77951aa45003d0d80e0be834235571f32f\nUSA_STATE_FIELD=$.replicas[0].crypt=pve03-mail-04-crypt\nUSA_STATE_FIELD=$.replicas[0].physical=pve03-mail-04\nUSA_STATE_FIELD=$.replicas[1].crypt=pve03-mail-01-crypt\nUSA_STATE_FIELD=$.replicas[1].physical=pve03-mail-01\nUSA_STATE_FIELD=$.result=SUCCESS\nUSA_STATE_FIELD=$.retry_after_epoch=0\nUSA_STATE_FIELD=$.schema=1\nUSA_STATE_FIELD=$.updated_at_utc=2026-09-19T07:01:18Z\nUSA_STATE_FULL_SAFE_END=true\nMOLDOVA_STATE_FULL_SAFE_BEGIN=true\nMOLDOVA_STATE_FIELD=$.consecutive_failures=6\nMOLDOVA_STATE_FIELD=$.failure_backoff_seconds=21600\nMOLDOVA_STATE_FIELD=$.generation=v2-us-netbird-20260920T000652Z-7ecdcfcafc12\nMOLDOVA_STATE_FIELD=$.last_attempt_epoch=1789862827\nMOLDOVA_STATE_FIELD=$.last_success_epoch=1789704670\nMOLDOVA_STATE_FIELD=$.last_success_generation=v2-us-netbird-20260918T041032Z-d7648be4c16b\nMOLDOVA_STATE_FIELD=$.last_success_green_verified=False\nMOLDOVA_STATE_FIELD=$.last_success_manifest_sha256=f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5\nMOLDOVA_STATE_FIELD=$.last_success_payload_sha256=e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf\nMOLDOVA_STATE_FIELD=$.last_success_replicas[0].crypt=pve01-mail-05-crypt\nMOLDOVA_STATE_FIELD=$.last_success_replicas[0].physical=pve01-mail-05\nMOLDOVA_STATE_FIELD=$.last_success_replicas[1].crypt=pve03-mail-04-crypt\nMOLDOVA_STATE_FIELD=$.last_success_replicas[1].physical=pve03-mail-04\nMOLDOVA_STATE_FIELD=$.logical_id=us-netbird\nMOLDOVA_STATE_FIELD=$.reason=PIPE_FAILED\nMOLDOVA_STATE_FIELD=$.result=FAIL\nMOLDOVA_STATE_FIELD=$.retry_after_epoch=1789884427\nMOLDOVA_STATE_FIELD=$.schema=1\nMOLDOVA_STATE_FIELD=$.sealed=False\nMOLDOVA_STATE_FIELD=$.updated_at_utc=2026-09-20T00:07:07Z\nMOLDOVA_STATE_FULL_SAFE_END=true\nHAS_RCLONE_SOURCE=false\nHAS_GENERATION_MANIFEST_PAYLOAD_SOURCE=true\nHAS_REMOTE_REPLICA_SOURCE=true\nDECISION=HOLD_BACKUP207_PRODUCER_CONTRACT_INCOMPLETE\nNEXT_GATE=READ_ONLY_TARGETED_MODULE_FOLLOWUP\nCLOUD_READS=0\nCLOUD_WRITES=0\nVPS_SSH_ATTEMPTS=0\nMESSENGERS214_CLOSED=false\nMAJOR_STAGES_REMAINING=8\nNEWFI207_END=true\n" +} diff --git a/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.txt b/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.txt new file mode 100644 index 00000000..692b5cb9 --- /dev/null +++ b/runtime/history/NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207.txt @@ -0,0 +1,779 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207 +STATUS=OK +RC=0 +HOST=pve01 +MODE=read-only +COMPONENT=newfi-newfdom-messengers214-backupv2-producer-contract-readonly-audit +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 +COMMAND_SHA256=ead8fdf05c4cb0a9b8b49f67777a3e68a7a96170d3e4b5061fa03171a66917da +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=99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec +SANITIZED_OUTPUT_SHA256=99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec +OUTPUT_BEGIN +NEWFI207_BEGIN=true +MODE=read-only +IMMUTABLE_PLAN_CHECK=PASS +CHANGES_MADE=false +MUTATION_OUTCOME=NO_MUTATION +PIN_CHECK=PASS +ACCEPTED_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b +RELEASE_FILE_COUNT=6 +INTERESTING_FILE_COUNT=6 +FILE_1_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +FILE_1_BYTES=10566 +FILE_1_MODE=0o400 +FILE_1_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793 +FILE_1_KEYWORD_SCORE=13 +FILE_1_AST_DEF_COUNT=0 +FILE_1_AST_IMPORT_COUNT=0 +FILE_1_AST_STRING_COUNT=7 +FILE_1_STRING_1_LINE=4 +FILE_1_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1 +FILE_1_STRING_2_LINE=62 +FILE_1_STRING_2_VALUE=backup_target +FILE_1_STRING_3_LINE=62 +FILE_1_STRING_3_VALUE=ssh_remote +FILE_1_STRING_4_LINE=135 +FILE_1_STRING_4_VALUE=payload_sha256 +FILE_1_STRING_5_LINE=135 +FILE_1_STRING_5_VALUE=manifest_sha256 +FILE_1_STRING_6_LINE=135 +FILE_1_STRING_6_VALUE=replicas +FILE_1_STRING_7_LINE=132 +FILE_1_STRING_7_VALUE=homelab-scheduler-proof- +FILE_2_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +FILE_2_BYTES=13825 +FILE_2_MODE=0o400 +FILE_2_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d +FILE_2_KEYWORD_SCORE=9 +FILE_2_AST_DEF_COUNT=2 +FILE_2_DEF_1_LINE=35 +FILE_2_DEF_1_NAME=_remote_sha +FILE_2_DEF_2_LINE=117 +FILE_2_DEF_2_NAME=_execute_remote +FILE_2_AST_IMPORT_COUNT=0 +FILE_2_AST_STRING_COUNT=17 +FILE_2_STRING_1_LINE=79 +FILE_2_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-plan-only +FILE_2_STRING_2_LINE=118 +FILE_2_STRING_2_VALUE=REMOTE_NODE +FILE_2_STRING_3_LINE=119 +FILE_2_STRING_3_VALUE=REMOTE_ARGV +FILE_2_STRING_4_LINE=120 +FILE_2_STRING_4_VALUE=REMOTE_ARGV_NODE +FILE_2_STRING_5_LINE=121 +FILE_2_STRING_5_VALUE=REMOTE_CAP_VALUE +FILE_2_STRING_6_LINE=124 +FILE_2_STRING_6_VALUE=REMOTE_WORKDIR +FILE_2_STRING_7_LINE=158 +FILE_2_STRING_7_VALUE=remote-bounded-ssh-cwd-root +FILE_2_STRING_8_LINE=198 +FILE_2_STRING_8_VALUE=/var/tmp/homelab-vzdump-v2- +FILE_2_STRING_9_LINE=149 +FILE_2_STRING_9_VALUE=REMOTE_TIMEOUT +FILE_2_STRING_10_LINE=151 +FILE_2_STRING_10_VALUE=REMOTE_RC +FILE_2_STRING_11_LINE=152 +FILE_2_STRING_11_VALUE=REMOTE_EMPTY +FILE_2_STRING_12_LINE=155 +FILE_2_STRING_12_VALUE=REMOTE_FILE_IDENTITY +FILE_2_STRING_13_LINE=162 +FILE_2_STRING_13_VALUE=remote-bounded-ssh-cwd-root +FILE_2_STRING_14_LINE=204 +FILE_2_STRING_14_VALUE=payload.bin +FILE_2_STRING_15_LINE=210 +FILE_2_STRING_15_VALUE=VZDUMP_PAYLOAD_BOUND +FILE_2_STRING_16_LINE=138 +FILE_2_STRING_16_VALUE=REMOTE_TIMEOUT +FILE_2_STRING_17_LINE=143 +FILE_2_STRING_17_VALUE=REMOTE_CAP +FILE_3_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py +FILE_3_BYTES=4627 +FILE_3_MODE=0o400 +FILE_3_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b +FILE_3_KEYWORD_SCORE=9 +FILE_3_AST_DEF_COUNT=1 +FILE_3_DEF_1_LINE=11 +FILE_3_DEF_1_NAME=_remote_sha +FILE_3_AST_IMPORT_COUNT=0 +FILE_3_AST_STRING_COUNT=3 +FILE_3_STRING_1_LINE=48 +FILE_3_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2- +FILE_3_STRING_2_LINE=66 +FILE_3_STRING_2_VALUE=payload.bin +FILE_3_STRING_3_LINE=70 +FILE_3_STRING_3_VALUE=QEMU_PAYLOAD_MISSING +FILE_4_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +FILE_4_BYTES=4097 +FILE_4_MODE=0o400 +FILE_4_SHA256=a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96 +FILE_4_KEYWORD_SCORE=9 +FILE_4_AST_DEF_COUNT=0 +FILE_4_AST_IMPORT_COUNT=0 +FILE_4_AST_STRING_COUNT=9 +FILE_4_STRING_1_LINE=44 +FILE_4_STRING_1_VALUE=last_success_payload_sha256 +FILE_4_STRING_2_LINE=45 +FILE_4_STRING_2_VALUE=last_success_manifest_sha256 +FILE_4_STRING_3_LINE=45 +FILE_4_STRING_3_VALUE=last_success_replicas +FILE_4_STRING_4_LINE=37 +FILE_4_STRING_4_VALUE=payload_sha256 +FILE_4_STRING_5_LINE=37 +FILE_4_STRING_5_VALUE=last_success_payload_sha256 +FILE_4_STRING_6_LINE=38 +FILE_4_STRING_6_VALUE=manifest_sha256 +FILE_4_STRING_7_LINE=38 +FILE_4_STRING_7_VALUE=last_success_manifest_sha256 +FILE_4_STRING_8_LINE=38 +FILE_4_STRING_8_VALUE=replicas +FILE_4_STRING_9_LINE=38 +FILE_4_STRING_9_VALUE=last_success_replicas +FILE_5_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +FILE_5_BYTES=3449 +FILE_5_MODE=0o400 +FILE_5_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3 +FILE_5_KEYWORD_SCORE=7 +FILE_5_AST_DEF_COUNT=0 +FILE_5_AST_IMPORT_COUNT=0 +FILE_5_AST_STRING_COUNT=2 +FILE_5_STRING_1_LINE=4 +FILE_5_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411 +FILE_5_STRING_2_LINE=45 +FILE_5_STRING_2_VALUE=payload.bin +FILE_6_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +FILE_6_BYTES=2320 +FILE_6_MODE=0o400 +FILE_6_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011 +FILE_6_KEYWORD_SCORE=3 +FILE_6_AST_DEF_COUNT=0 +FILE_6_AST_IMPORT_COUNT=0 +FILE_6_AST_STRING_COUNT=1 +FILE_6_STRING_1_LINE=4 +FILE_6_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1 +CTX_1_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_1_START_LINE=15 +CTX_1_END_LINE=21 +CTX_1_L15=} +CTX_1_L16= +CTX_1_L17=def _sha(p): +CTX_1_L18= h=hashlib.sha256() +CTX_1_L19= with open(p,'rb',buffering=0) as f: +CTX_1_L20= while True: +CTX_1_L21= b=f.read(1<<20) +CTX_2_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_2_START_LINE=34 +CTX_2_END_LINE=40 +CTX_2_L34= +CTX_2_L35=class _GlobalsProxy: +CTX_2_L36= __slots__=('_g',) +CTX_2_L37= def __init__(self,g): object.__setattr__(self,'_g',g) +CTX_2_L38= def __getattr__(self,n): +CTX_2_L39= try: return self._g[n] +CTX_2_L40= except KeyError as e: raise AttributeError(n) from e +CTX_3_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_3_START_LINE=59 +CTX_3_END_LINE=72 +CTX_3_L59= if len(found)!=1: +CTX_3_L60= raise RuntimeError('LEGACY_PROVENANCE_CARDINALITY') +CTX_3_L61= g=next(iter(found.values())) +CTX_3_L62= required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote', +CTX_3_L63= '_default_unprivileged_lxc','mapped_scratch_probe','_stream_argv_to_local','run', +CTX_3_L64= 'choose_due_target','write_state','epoch') +CTX_3_L65= if any(not callable(g.get(n)) for n in required): +CTX_3_L66= raise RuntimeError('LEGACY_PROVENANCE_API') +CTX_3_L67= original=g['capture_pve_guest'] +CTX_3_L68= proxy=_GlobalsProxy(g) +CTX_3_L69= if not isinstance(g.get('SCP'),str) or not g['SCP'].startswith('/'): +CTX_3_L70= raise RuntimeError('LEGACY_SCP_API') +CTX_3_L71= qemu_patched=qemu_adapter.bind(proxy,original) +CTX_3_L72= if not callable(qemu_patched): +CTX_4_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_4_START_LINE=75 +CTX_4_END_LINE=82 +CTX_4_L75= if not callable(patched): +CTX_4_L76= raise RuntimeError('LXC_ADAPTER_BIND_RESULT') +CTX_4_L77= g['capture_pve_guest']=patched +CTX_4_L78= scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state']) +CTX_4_L79= if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']: +CTX_4_L80= raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT') +CTX_4_L81= return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired} +CTX_4_L82= +CTX_5_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_5_START_LINE=96 +CTX_5_END_LINE=117 +CTX_5_L96= wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE) +CTX_5_L97= return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired +CTX_5_L98= +CTX_5_L99=def _target(wrapper,lid): +CTX_5_L100= rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid] +CTX_5_L101= if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY') +CTX_5_L102= return hits[0] +CTX_5_L103= +CTX_5_L104=def selftest(): +CTX_5_L105= wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load() +CTX_5_L106= if wired['legacy_globals'].get('capture_pve_guest') is not wired['patched_capture']: +CTX_5_L107= raise RuntimeError('PATCH_BINDING') +CTX_5_L108= if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']: +CTX_5_L109= raise RuntimeError('SCHEDULER_CHOOSE_BINDING') +CTX_5_L110= if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']: +CTX_5_L111= raise RuntimeError('SCHEDULER_WRITE_BINDING') +CTX_5_L112= if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]: +CTX_5_L113= raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT') +CTX_5_L114= if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets): +CTX_5_L115= raise RuntimeError('WRAPPER_PUBLIC_API') +CTX_5_L116= print('SELFTEST_OVERLAY504=PASS',flush=True) +CTX_5_L117= return 0 +CTX_6_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_6_START_LINE=125 +CTX_6_END_LINE=187 +CTX_6_L125= if argv==['scheduler-proof']: +CTX_6_L126= import tempfile +CTX_6_L127= legacy=wired['legacy']; g=wired['legacy_globals'] +CTX_6_L128= old_root=g.get('STATE_ROOT'); old_epoch=g.get('epoch') +CTX_6_L129= if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE') +CTX_6_L130= now=[1000] +CTX_6_L131= try: +CTX_6_L132= with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td: +CTX_6_L133= g['STATE_ROOT']=pathlib.Path(td); (g['STATE_ROOT']/'state').mkdir(mode=0o700) +CTX_6_L134= g['epoch']=lambda: now[0] +CTX_6_L135= common={'payload_sha256':'a'*64,'manifest_sha256':'b'*64,'replicas':['proof-r1','proof-r2']} +CTX_6_L136= legacy.write_state('proof-a','SUCCESS',generation='proof-a-good',**common) +CTX_6_L137= legacy.write_state('proof-b','SUCCESS',generation='proof-b-good',**common) +CTX_6_L138= now[0]=100000 +CTX_6_L139= legacy.write_state('proof-a','FAIL',generation='proof-a-bad',reason='PROOF_FAILURE',sealed=False) +CTX_6_L140= state=legacy.load_state_all(); a=state['proof-a'] +CTX_6_L141= targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}] +CTX_6_L142= first=legacy.choose_due_target(targets,state,now[0]) +CTX_6_L143= if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED') +CTX_6_L144= retry=int(a.get('retry_after_epoch',0)); preserved=int(a.get('last_success_epoch',0)) +CTX_6_L145= if preserved!=1000 or a.get('last_success_generation')!='proof-a-good' or int(a.get('consecutive_failures',0))!=1 or retry!=101800: +CTX_6_L146= raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE') +CTX_6_L147= now[0]=retry+1 +CTX_6_L148= second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0]) +CTX_6_L149= if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE') +CTX_6_L150= legacy.write_state('proof-a','SUCCESS',generation='proof-a-recovered',**common) +CTX_6_L151= recovered=legacy.load_state_all()['proof-a'] +CTX_6_L152= if int(recovered.get('consecutive_failures',-1))!=0 or int(recovered.get('retry_after_epoch',-1))!=0: +CTX_6_L153= raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET') +CTX_6_L154= 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} +CTX_6_L155= print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True) +CTX_6_L156= return 0 +CTX_6_L157= finally: +CTX_6_L158= g['STATE_ROOT']=old_root; g['epoch']=old_epoch +CTX_6_L159= if argv==['scheduler-select-live']: +CTX_6_L160= state=legacy.load_state_all(); targets=wrapper.load_targets() +CTX_6_L161= chosen=legacy.choose_due_target(targets,state) +CTX_6_L162= if chosen is None: +CTX_6_L163= print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True) +CTX_6_L164= else: +CTX_6_L165= 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) +CTX_6_L166= return 0 +CTX_6_L167= if len(argv)==2 and argv[0]=='plan-lxc': +CTX_6_L168= t=_target(wrapper,argv[1]) +CTX_6_L169= if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112': +CTX_6_L170= raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC') +CTX_6_L171= out=lxc_adapter.plan_only(legacy,t) +CTX_6_L172= 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) +CTX_6_L173= return 0 +CTX_6_L174= if len(argv)==2 and argv[0]=='verify-target': +CTX_6_L175= t=_target(wrapper,argv[1]) +CTX_6_L176= if t.get('logical_id')=='guest-pve01-lxc-112': +CTX_6_L177= raise RuntimeError('VERIFY_SYNTHETIC_CT112_FORBIDDEN') +CTX_6_L178= try: +CTX_6_L179= out=wrapper.backup_target(t,True) +CTX_6_L180= except legacy.BackupError as e: +CTX_6_L181= print('VERIFY_TARGET_RESULT=FAIL',flush=True) +CTX_6_L182= print('VERIFY_TARGET_REASON='+str(e.code),flush=True) +CTX_6_L183= return 2 +CTX_6_L184= print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True) +CTX_6_L185= return 0 +CTX_6_L186= return wrapper.main([sys.argv[0],*argv]) +CTX_6_L187= +CTX_7_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_7_START_LINE=20 +CTX_7_END_LINE=26 +CTX_7_L20= except Exception as e: raise AdapterError(code) from e +CTX_7_L21= +CTX_7_L22=def _sha_file(p): +CTX_7_L23= h=hashlib.sha256() +CTX_7_L24= with open(p,'rb',buffering=0) as f: +CTX_7_L25= for b in iter(lambda:f.read(1<<20),b''): h.update(b) +CTX_7_L26= return h.hexdigest() +CTX_8_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_8_START_LINE=32 +CTX_8_END_LINE=62 +CTX_8_L32= if n<=0: raise AdapterError('WRITE_FAILED') +CTX_8_L33= view=view[n:] +CTX_8_L34= +CTX_8_L35=def _remote_sha(legacy,node,path): +CTX_8_L36= p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30) +CTX_8_L37= parts=p.stdout.decode('ascii','strict').strip().split() +CTX_8_L38= _need(len(parts)>=2 and parts[1]==path,'TOOL_SHA_OUTPUT') +CTX_8_L39= return parts[0] +CTX_8_L40= +CTX_8_L41=def _live_inputs(legacy,node,vmid,scratch): +CTX_8_L42= _need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY') +CTX_8_L43= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY') +CTX_8_L44= rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON') +CTX_8_L45= stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON') +CTX_8_L46= _need(type(rows) is list and type(stores) is list,'PVE_LIST_SCHEMA') +CTX_8_L47= configs=[] +CTX_8_L48= for r in rows: +CTX_8_L49= if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue +CTX_8_L50= try: rid=int(r.get('vmid')) +CTX_8_L51= except Exception: raise AdapterError('RESOURCE_VMID') +CTX_8_L52= cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r["type"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON') +CTX_8_L53= _need(type(cfg) is dict,'CONFIG_SCHEMA') +CTX_8_L54= configs.append([rid,cfg]) +CTX_8_L55= tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON') +CTX_8_L56= _need(type(tasks) is list and len(tasks)<1000,'TASKS_SCHEMA') +CTX_8_L57= q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False) +CTX_8_L58= defaults=None +CTX_8_L59= if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout +CTX_8_L60= elif q.returncode!=1: raise AdapterError('DEFAULTS_PROBE') +CTX_8_L61= st=os.statvfs('/mnt/staging'); free=int(st.f_bavail*st.f_frsize) +CTX_8_L62= return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs, +CTX_9_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_9_START_LINE=85 +CTX_9_END_LINE=91 +CTX_9_L85= a=_helper(_live_inputs(legacy,node,vmid,scratch)); b=_helper(_live_inputs(legacy,node,vmid,scratch)) +CTX_9_L86= _need(_stable_job(a['job'])==_stable_job(b['job']),'FRESH_PLAN_UNSTABLE') +CTX_9_L87= _need(a['argv']==b['argv'],'FRESH_ARGV_UNSTABLE') +CTX_9_L88= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_POST') +CTX_9_L89= return b +CTX_9_L90= +CTX_9_L91=def _execute_local(legacy,node,argv,dest,cap,timeout): +CTX_10_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_10_START_LINE=94 +CTX_10_END_LINE=109 +CTX_10_L94= data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode() +CTX_10_L95= p=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV) +CTX_10_L96= if p.stderr or not p.stdout or len(p.stdout)>262144: +CTX_10_L97= raise ExecFailure('LOCAL_HELPER_PROTOCOL',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)}) +CTX_10_L98= try: out=json.loads(p.stdout) +CTX_10_L99= except Exception: +CTX_10_L100= raise ExecFailure('LOCAL_HELPER_JSON',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)}) +CTX_10_L101= summary={'executor':'local-proven-pve270','helper_rc':p.returncode,'exception_class':out.get('exception_class'),'exception_message_sha256':out.get('exception_message_sha256')} +CTX_10_L102= if isinstance(out.get('process'),dict): summary.update(out['process']) +CTX_10_L103= if p.returncode!=0 or out.get('status')!='OK': raise ExecFailure('LOCAL_PRODUCER_FAILED',summary) +CTX_10_L104= result=out.get('result'); _need(type(result) is dict,'LOCAL_RESULT_SCHEMA') +CTX_10_L105= _need(pathlib.Path(dest).is_file() and pathlib.Path(dest).stat().st_size==int(result.get('size',-1)),'LOCAL_RESULT_FILE') +CTX_10_L106= return summary|{'size':result['size'],'sha256':result['sha256'],'producer_rc':result.get('producer_rc')} +CTX_10_L107= +CTX_10_L108=def _kill(p): +CTX_10_L109= try: os.killpg(p.pid,signal.SIGTERM) +CTX_11_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_11_START_LINE=114 +CTX_11_END_LINE=166 +CTX_11_L114= except ProcessLookupError: pass +CTX_11_L115= p.wait() +CTX_11_L116= +CTX_11_L117=def _execute_remote(legacy,node,argv,dest,cap,timeout): +CTX_11_L118= _need(re.fullmatch(r'pve0[123]',str(node)) is not None and node!='pve01','REMOTE_NODE') +CTX_11_L119= _need(type(argv) is list and argv and argv[0]=='/usr/bin/vzdump' and all(type(x) is str and '\x00' not in x for x in argv),'REMOTE_ARGV') +CTX_11_L120= _need('--node' in argv and argv[argv.index('--node')+1]==node,'REMOTE_ARGV_NODE') +CTX_11_L121= _need(type(cap) is int and 0=deadline: raise ExecFailure('REMOTE_TIMEOUT',{}) +CTX_11_L139= for key,_ in sel.select(min(.2,max(0,deadline-now))): +CTX_11_L140= b=os.read(key.fileobj.fileno(),65536) +CTX_11_L141= if not b: sel.unregister(key.fileobj); continue +CTX_11_L142= if key.fileobj is p.stdout: +CTX_11_L143= if total+len(b)>cap: raise ExecFailure('REMOTE_CAP',{}) +CTX_11_L144= _write_all(fd,b); digest.update(b); total+=len(b) +CTX_11_L145= else: +CTX_11_L146= err_total+=len(b); eh.update(b); keep=b[:max(0,MAX_STDERR-err_kept)] +CTX_11_L147= if keep: _write_all(efd,keep); err_kept+=len(keep) +CTX_11_L148= left=deadline-time.monotonic() +CTX_11_L149= if left<=0: raise ExecFailure('REMOTE_TIMEOUT',{}) +CTX_11_L150= rc=p.wait(timeout=left) +CTX_11_L151= if rc!=0: raise ExecFailure('REMOTE_RC',{}) +CTX_11_L152= if total<=0: raise ExecFailure('REMOTE_EMPTY',{}) +CTX_11_L153= stf=os.fstat(fd); named=os.stat(dest,follow_symlinks=False) +CTX_11_L154= if (stf.st_dev,stf.st_ino)!=(initial.st_dev,initial.st_ino) or (named.st_dev,named.st_ino)!=(initial.st_dev,initial.st_ino) or stf.st_nlink!=1 or stf.st_size!=total: +CTX_11_L155= raise ExecFailure('REMOTE_FILE_IDENTITY',{}) +CTX_11_L156= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_EXEC_POST') +CTX_11_L157= os.fchmod(fd,0o400); os.fsync(fd); os.fsync(efd); good=True +CTX_11_L158= return {'executor':'remote-bounded-ssh-cwd-root','producer_rc':rc,'size':total,'sha256':digest.hexdigest(), +CTX_11_L159= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()} +CTX_11_L160= except ExecFailure as e: +CTX_11_L161= if p is not None and p.poll() is None: _kill(p) +CTX_11_L162= summary={'executor':'remote-bounded-ssh-cwd-root','producer_rc':None if p is None else p.returncode,'archive_bytes':total, +CTX_11_L163= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()} +CTX_11_L164= summary.update(e.summary); raise ExecFailure(e.code,summary) +CTX_11_L165= finally: +CTX_11_L166= if p is not None: +CTX_12_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_12_START_LINE=171 +CTX_12_END_LINE=178 +CTX_12_L171= try: os.fsync(fd); os.fsync(efd) +CTX_12_L172= except OSError: pass +CTX_12_L173= os.close(fd); os.close(efd) +CTX_12_L174= summary={'process_started':p is not None,'producer_rc':None if p is None else p.returncode,'capture_success':good,'archive_bytes':total, +CTX_12_L175= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest(),'raw_stderr_exported':False,'cwd':'/'} +CTX_12_L176= try: +CTX_12_L177= mb=(json.dumps(summary,separators=(',',':'),sort_keys=True)+'\n').encode() +CTX_12_L178= mfd=os.open(metap,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) +CTX_13_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_13_START_LINE=182 +CTX_13_END_LINE=188 +CTX_13_L182= +CTX_13_L183=def _emit_diag(node,summary): +CTX_13_L184= safe={'node':node} +CTX_13_L185= for k in ('executor','failure_code','helper_rc','producer_rc','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','exception_class','exception_message_sha256'): +CTX_13_L186= if k in summary: safe[k]=summary[k] +CTX_13_L187= print('LXC_EXECUTION_DIAG='+json.dumps(safe,separators=(',',':'),sort_keys=True),flush=True) +CTX_13_L188= +CTX_14_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_14_START_LINE=196 +CTX_14_END_LINE=218 +CTX_14_L196= _need(typ==t.get('guest_type')=='lxc','PVE_GUEST_TYPE_DRIFT') +CTX_14_L197= legacy._default_unprivileged_lxc(node,vmid) +CTX_14_L198= scratch=f'/var/tmp/homelab-vzdump-v2-{gen}' +CTX_14_L199= legacy.ssh_remote(node,['install','-d','-m','710','-o','0','-g','100000',scratch],timeout=30) +CTX_14_L200= q=legacy.ssh_remote(node,['stat','-c','%a:%u:%g',scratch],timeout=30) +CTX_14_L201= _need(q.stdout.decode().strip()=='710:0:100000','PVE_MAPPED_SCRATCH_ACCESS_CONTRACT') +CTX_14_L202= try: +CTX_14_L203= legacy.mapped_scratch_probe(node,scratch) +CTX_14_L204= p=plan_only(legacy,t,scratch); local=pathlib.Path(work)/'payload.bin'; cap=int(p['job']['archive_cap_bytes']) +CTX_14_L205= try: +CTX_14_L206= result=_execute_local(legacy,node,p['argv'],local,cap,7200) if node=='pve01' else _execute_remote(legacy,node,p['argv'],local,cap,7200) +CTX_14_L207= except ExecFailure as e: +CTX_14_L208= _emit_diag(node,e.summary|{'failure_code':e.code}) +CTX_14_L209= raise legacy.BackupError('LXC_PRODUCER_FAILED') from None +CTX_14_L210= _need(local.is_file() and 0=2 and parts[1]==path,'QEMU_TOOL_SHA_OUTPUT') +CTX_15_L15= return parts[0] +CTX_15_L16= +CTX_15_L17=def _select_qemu_outputs(vmid,files): +CTX_15_L18= _need(type(vmid) is int and vmid>0,'QEMU_VMID') +CTX_15_L19= _need(type(files) is list and files and all(type(x) is str and x.startswith('/') and '\x00' not in x for x in files),'QEMU_OUTPUT_LIST') +CTX_15_L20= _need(len(files)==len(set(files)),'QEMU_OUTPUT_DUPLICATE') +CTX_15_L21= 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$') +CTX_15_L22= archives=[] +CTX_15_L23= for f in files: +CTX_15_L24= name=pathlib.PurePosixPath(f).name +CTX_15_L25= m=pat.fullmatch(name) +CTX_15_L26= if m: archives.append((f,m.group(1))) +CTX_15_L27= _need(len(archives)==1,'QEMU_ARCHIVE_NOT_UNIQUE') +CTX_15_L28= archive,stamp=archives[0]; parent=pathlib.PurePosixPath(archive).parent +CTX_15_L29= expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log' +CTX_15_L30= allowed={archive}; log=None +CTX_15_L31= if str(expected_log) in files: +CTX_15_L32= log=str(expected_log); allowed.add(log) +CTX_15_L33= _need(set(files)==allowed,'QEMU_OUTPUT_UNEXPECTED_FILE') +CTX_15_L34= return archive,log +CTX_15_L35= +CTX_15_L36=def _emit_diag(**kw): +CTX_15_L37= print('QEMU_EXECUTION_DIAG='+json.dumps(kw,separators=(',',':'),sort_keys=True),flush=True) +CTX_16_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py +CTX_16_START_LINE=44 +CTX_16_END_LINE=78 +CTX_16_L44= _need(len(rows)==1,'PVE_GUEST_NOT_UNIQUE') +CTX_16_L45= row=rows[0]; node=row.get('node'); typ=row.get('type') +CTX_16_L46= _need(typ==t.get('guest_type')=='qemu','PVE_GUEST_TYPE_DRIFT') +CTX_16_L47= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE') +CTX_16_L48= srcdir=f'/var/tmp/homelab-vzdump-v2-{gen}' +CTX_16_L49= legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30) +CTX_16_L50= try: +CTX_16_L51= vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False) +CTX_16_L52= if vp.returncode!=0: +CTX_16_L53= _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) +CTX_16_L54= raise legacy.BackupError('QEMU_VZDUMP_FAILED') +CTX_16_L55= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST') +CTX_16_L56= p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\n'],timeout=30) +CTX_16_L57= files=[x for x in p.stdout.decode('utf-8','strict').splitlines() if x] +CTX_16_L58= try: src,log=_select_qemu_outputs(vmid,files) +CTX_16_L59= except QemuAdapterError as e: +CTX_16_L60= _emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e)) +CTX_16_L61= raise legacy.BackupError(str(e)) from None +CTX_16_L62= q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30) +CTX_16_L63= raw=q.stdout.decode('ascii','strict').strip() +CTX_16_L64= _need(raw.isdigit() and int(raw)>0,'QEMU_ARCHIVE_STAT') +CTX_16_L65= size=int(raw) +CTX_16_L66= local=pathlib.Path(work)/'payload.bin' +CTX_16_L67= if node=='pve01': local=pathlib.Path(src) +CTX_16_L68= else: +CTX_16_L69= legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200) +CTX_16_L70= _need(pathlib.Path(local).is_file() and pathlib.Path(local).stat().st_size==size,'QEMU_PAYLOAD_MISSING') +CTX_16_L71= _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) +CTX_16_L72= except Exception: +CTX_16_L73= legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise +CTX_16_L74= cleanup={'kind':'pve_source_dir','node':node,'path':srcdir} +CTX_16_L75= meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'), +CTX_16_L76= 'producer_contract':'strict-qemu-vma-zst-plus-matching-log-overlay503'} +CTX_16_L77= return pathlib.Path(local),meta,cleanup +CTX_16_L78= capture_pve_guest.__name__='capture_pve_guest' +CTX_17_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_17_START_LINE=20 +CTX_17_END_LINE=28 +CTX_17_L20= n=max(1,_as_nonneg_int(consecutive_failures,1)) +CTX_17_L21= return min(MAX_BACKOFF,MIN_BACKOFF*(2**min(n-1,4))) +CTX_17_L22= +CTX_17_L23=def _read_prior(legacy,logical_id): +CTX_17_L24= root=pathlib.Path(legacy.STATE_ROOT)/'state' +CTX_17_L25= p=root/(str(logical_id)+'.json') +CTX_17_L26= try: +CTX_17_L27= if not p.is_file(): return {} +CTX_17_L28= d=json.loads(p.read_text(encoding='utf-8')) +CTX_18_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_18_START_LINE=34 +CTX_18_END_LINE=48 +CTX_18_L34= if not isinstance(prior,dict): return {} +CTX_18_L35= if prior.get('result')=='SUCCESS': +CTX_18_L36= out={'last_success_epoch':_as_nonneg_int(prior.get('last_success_epoch'),0)} +CTX_18_L37= mapping=(('generation','last_success_generation'),('payload_sha256','last_success_payload_sha256'), +CTX_18_L38= ('manifest_sha256','last_success_manifest_sha256'),('replicas','last_success_replicas'), +CTX_18_L39= ('green_verified','last_success_green_verified')) +CTX_18_L40= for src,dst in mapping: +CTX_18_L41= if src in prior: out[dst]=prior[src] +CTX_18_L42= return out +CTX_18_L43= out={} +CTX_18_L44= for k in ('last_success_epoch','last_success_generation','last_success_payload_sha256', +CTX_18_L45= 'last_success_manifest_sha256','last_success_replicas','last_success_green_verified'): +CTX_18_L46= if k in prior: out[k]=prior[k] +CTX_18_L47= return out +CTX_18_L48= +CTX_19_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_19_START_LINE=50 +CTX_19_END_LINE=65 +CTX_19_L50= _need(callable(original_choose),'ORIGINAL_CHOOSE_REQUIRED') +CTX_19_L51= _need(callable(original_write),'ORIGINAL_WRITE_REQUIRED') +CTX_19_L52= _need(callable(getattr(legacy,'epoch',None)),'LEGACY_EPOCH_REQUIRED') +CTX_19_L53= _need(hasattr(legacy,'STATE_ROOT'),'LEGACY_STATE_ROOT_REQUIRED') +CTX_19_L54= +CTX_19_L55= def choose_due_target(targets,state,now=None): +CTX_19_L56= now=_as_nonneg_int(legacy.epoch() if now is None else now,0) +CTX_19_L57= _need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA') +CTX_19_L58= due=[] +CTX_19_L59= for order,t in enumerate(targets): +CTX_19_L60= if not isinstance(t,dict) or t.get('enabled') is not True: continue +CTX_19_L61= lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0) +CTX_19_L62= _need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA') +CTX_19_L63= s=state.get(lid,{}) +CTX_19_L64= if not isinstance(s,dict): s={} +CTX_19_L65= retry_after=_as_nonneg_int(s.get('retry_after_epoch'),0) +CTX_20_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_20_START_LINE=72 +CTX_20_END_LINE=93 +CTX_20_L72= if not due: return None +CTX_20_L73= return max(due,key=lambda x:(x[0],x[1]))[2] +CTX_20_L74= +CTX_20_L75= def write_state(logical_id,result,**kw): +CTX_20_L76= now=_as_nonneg_int(legacy.epoch(),0) +CTX_20_L77= prior=_read_prior(legacy,logical_id) +CTX_20_L78= if result=='SUCCESS': +CTX_20_L79= clean=dict(kw) +CTX_20_L80= clean.update({'last_attempt_epoch':now,'consecutive_failures':0,'retry_after_epoch':0,'failure_backoff_seconds':0}) +CTX_20_L81= return original_write(logical_id,result,**clean) +CTX_20_L82= failures=_as_nonneg_int(prior.get('consecutive_failures'),0)+1 +CTX_20_L83= backoff=backoff_seconds(failures) +CTX_20_L84= clean=dict(kw) +CTX_20_L85= clean.update(_success_snapshot(prior)) +CTX_20_L86= clean.update({'last_attempt_epoch':now,'consecutive_failures':failures, +CTX_20_L87= 'retry_after_epoch':now+backoff,'failure_backoff_seconds':backoff}) +CTX_20_L88= return original_write(logical_id,result,**clean) +CTX_20_L89= +CTX_20_L90= legacy.choose_due_target=choose_due_target +CTX_20_L91= legacy.write_state=write_state +CTX_20_L92= return {'choose_due_target':choose_due_target,'write_state':write_state, +CTX_20_L93= 'original_choose':original_choose,'original_write':original_write} +CTX_21_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_21_START_LINE=7 +CTX_21_END_LINE=13 +CTX_21_L7=MAX_INPUT=262144 +CTX_21_L8= +CTX_21_L9=def sha_file(p:pathlib.Path)->str: +CTX_21_L10= h=hashlib.sha256() +CTX_21_L11= with open(p,'rb',buffering=0) as f: +CTX_21_L12= for b in iter(lambda:f.read(1<<20),b''): h.update(b) +CTX_21_L13= return h.hexdigest() +CTX_22_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_22_START_LINE=20 +CTX_22_END_LINE=33 +CTX_22_L20= if not p.is_file() or p.is_symlink(): return None +CTX_22_L21= try: d=json.loads(p.read_bytes()) +CTX_22_L22= except Exception: return {'summary_read':'FAILED'} +CTX_22_L23= keys=('process_started','producer_rc','capture_success','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','raw_stderr_exported','child_umask') +CTX_22_L24= return {k:d.get(k) for k in keys if k in d} +CTX_22_L25= +CTX_22_L26=def selftest()->int: +CTX_22_L27= if sha_file(VZDUMP)!=VZDUMP_SHA: fail('VZDUMP_IDENTITY') +CTX_22_L28= sys.path.insert(0,str(BASE)) +CTX_22_L29= import adapter +CTX_22_L30= adapter.verify_sources(); adapter.load_graph() +CTX_22_L31= print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True) +CTX_22_L32= return 0 +CTX_22_L33= +CTX_23_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_23_START_LINE=42 +CTX_23_END_LINE=66 +CTX_23_L42= argv=x['argv']; dest=pathlib.Path(x['dest']); cap=x['cap']; seconds=x['seconds'] +CTX_23_L43= 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') +CTX_23_L44= if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH') +CTX_23_L45= if not (dest.is_absolute() and dest.name=='payload.bin' and '..' not in dest.parts): fail('DEST') +CTX_23_L46= if not (type(cap) is int and 0str: +CTX_25_L9= return hashlib.sha256(p.read_bytes()).hexdigest() +CTX_25_L10= +CTX_25_L11=def fail(code:str): +CTX_25_L12= raise RuntimeError(code) +CTX_26_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +CTX_26_START_LINE=17 +CTX_26_END_LINE=23 +CTX_26_L17= if not p.is_file() or p.is_symlink() or sha(p)!=PVE265_SHA: fail('PVE265_IDENTITY') +CTX_26_L18= sys.path.insert(0,str(C411)) +CTX_26_L19= import adapter +CTX_26_L20= adapter.verify_sources() +CTX_26_L21= guest266,pve265,_pve270,_pve282=adapter.load_graph() +CTX_26_L22= data=sys.stdin.buffer.read(4_000_001) +CTX_26_L23= if not data or len(data)>4_000_000: fail('INPUT_BOUND') +CTX_27_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +CTX_27_START_LINE=36 +CTX_27_END_LINE=42 +CTX_27_L36= if job.get('configured_full_cycle_fits') is not True or job.get('compression_dependent') is not False: fail('JOB_CAPACITY_POLICY') +CTX_27_L37= guest266.no_active_tasks(raw.get('tasks'),vmid) +CTX_27_L38= argv=pve265.dump_argv(job,'/usr/bin/vzdump',scratch,now) +CTX_27_L39= 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') +CTX_27_L40= out={'schema':1,'argv':argv,'job':{k:job.get(k) for k in keep}} +CTX_27_L41= sys.stdout.write(json.dumps(out,separators=(',',':'),sort_keys=True)+'\n') +CTX_27_L42= return 0 +USA_STATE_FULL_SAFE_BEGIN=true +USA_STATE_FIELD=$.consecutive_failures=0 +USA_STATE_FIELD=$.failure_backoff_seconds=0 +USA_STATE_FIELD=$.generation=v2-md-relay-20260919T070058Z-0e409ea129e2 +USA_STATE_FIELD=$.green_verified=False +USA_STATE_FIELD=$.last_attempt_epoch=1789801278 +USA_STATE_FIELD=$.last_success_epoch=1789801278 +USA_STATE_FIELD=$.logical_id=md-relay +USA_STATE_FIELD=$.manifest_sha256=6887c5423640738aeb2bc1d104d515df1d1a21e2cd2d3291481475aa81cb6838 +USA_STATE_FIELD=$.payload_sha256=187401a5fbf6c29b4dfd77e5d272db77951aa45003d0d80e0be834235571f32f +USA_STATE_FIELD=$.replicas[0].crypt=pve03-mail-04-crypt +USA_STATE_FIELD=$.replicas[0].physical=pve03-mail-04 +USA_STATE_FIELD=$.replicas[1].crypt=pve03-mail-01-crypt +USA_STATE_FIELD=$.replicas[1].physical=pve03-mail-01 +USA_STATE_FIELD=$.result=SUCCESS +USA_STATE_FIELD=$.retry_after_epoch=0 +USA_STATE_FIELD=$.schema=1 +USA_STATE_FIELD=$.updated_at_utc=2026-09-19T07:01:18Z +USA_STATE_FULL_SAFE_END=true +MOLDOVA_STATE_FULL_SAFE_BEGIN=true +MOLDOVA_STATE_FIELD=$.consecutive_failures=6 +MOLDOVA_STATE_FIELD=$.failure_backoff_seconds=21600 +MOLDOVA_STATE_FIELD=$.generation=v2-us-netbird-20260920T000652Z-7ecdcfcafc12 +MOLDOVA_STATE_FIELD=$.last_attempt_epoch=1789862827 +MOLDOVA_STATE_FIELD=$.last_success_epoch=1789704670 +MOLDOVA_STATE_FIELD=$.last_success_generation=v2-us-netbird-20260918T041032Z-d7648be4c16b +MOLDOVA_STATE_FIELD=$.last_success_green_verified=False +MOLDOVA_STATE_FIELD=$.last_success_manifest_sha256=f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5 +MOLDOVA_STATE_FIELD=$.last_success_payload_sha256=e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf +MOLDOVA_STATE_FIELD=$.last_success_replicas[0].crypt=pve01-mail-05-crypt +MOLDOVA_STATE_FIELD=$.last_success_replicas[0].physical=pve01-mail-05 +MOLDOVA_STATE_FIELD=$.last_success_replicas[1].crypt=pve03-mail-04-crypt +MOLDOVA_STATE_FIELD=$.last_success_replicas[1].physical=pve03-mail-04 +MOLDOVA_STATE_FIELD=$.logical_id=us-netbird +MOLDOVA_STATE_FIELD=$.reason=PIPE_FAILED +MOLDOVA_STATE_FIELD=$.result=FAIL +MOLDOVA_STATE_FIELD=$.retry_after_epoch=1789884427 +MOLDOVA_STATE_FIELD=$.schema=1 +MOLDOVA_STATE_FIELD=$.sealed=False +MOLDOVA_STATE_FIELD=$.updated_at_utc=2026-09-20T00:07:07Z +MOLDOVA_STATE_FULL_SAFE_END=true +HAS_RCLONE_SOURCE=false +HAS_GENERATION_MANIFEST_PAYLOAD_SOURCE=true +HAS_REMOTE_REPLICA_SOURCE=true +DECISION=HOLD_BACKUP207_PRODUCER_CONTRACT_INCOMPLETE +NEXT_GATE=READ_ONLY_TARGETED_MODULE_FOLLOWUP +CLOUD_READS=0 +CLOUD_WRITES=0 +VPS_SSH_ATTEMPTS=0 +MESSENGERS214_CLOSED=false +MAJOR_STAGES_REMAINING=8 +NEWFI207_END=true + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index f2f69977..e74c15b8 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,38 +1,38 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "SUPPORT-260920-PVEPRO-RUSSIAN-PRODUCTION-PROMOTION-737R3", + "command_id": "NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207", "status": "OK", "rc": 0, "host": "pve01", - "mode": "change", - "component": "pvepro-russian-production-promotion", - "started_at_utc": "2026-09-20T01:59:29Z", - "finished_at_utc": "2026-09-20T02:00:37Z", + "mode": "read-only", + "component": "newfi-newfdom-messengers214-backupv2-producer-contract-readonly-audit", + "started_at_utc": "2026-09-20T02:01:22Z", + "finished_at_utc": "2026-09-20T02:01:22Z", "reference_register_checked": true, "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", "error_register_checked": true, "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", - "command_sha256": "ef9665faee60b4d430fb1b80fac16a3185b76d6defdb96b3b0f7805ea5e73408", + "command_sha256": "ead8fdf05c4cb0a9b8b49f67777a3e68a7a96170d3e4b5061fa03171a66917da", "duplicate_failed_command_blocked": false, "block_reason": null, "execution_started": true, - "change_declared": true, + "change_declared": false, "result_contract_valid": true, - "result_contract_status": "OK", + "result_contract_status": null, "result_contract_error": null, "command_rc": 0, - "changes_made": true, + "changes_made": false, "rollback_started": false, "rollback_restored": null, - "mutation_outcome": "MUTATED", + "mutation_outcome": "NO_MUTATION", "sanitized": true, "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "3df50151bcdef254b90951adba906dde1344ddf15c5f2a414f792dc462232eb1", - "sanitized_output_sha256": "3df50151bcdef254b90951adba906dde1344ddf15c5f2a414f792dc462232eb1", + "raw_evidence_sha256": "99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec", + "sanitized_output_sha256": "99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "RU_ARCHIVE_BYTES=298309\nRU_ARCHIVE_SHA256=68e0308b23a30dadd6399032fbef22e09693220a97a602ee6ef8a8c5492bce6b\nPROD_QGA_TRIES_PRE=1\nVERIFY_TRANSPORT_RC=0\nVERIFY_EXITCODE=0\nVERIFY_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nVERIFY_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nPHP_RC=0\nPHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nPHP_OUTPUT_BEGIN\nDEFAULT_LANGUAGE_ID=1\nRU_COUNT=0\nLANGUAGE_COUNT=1\nENGLISH_ID1_EXISTS=1\nRU_PHRASE_COUNT=0\nPHRASE_MAP_LANG2_COUNT=0\nMANUAL_JOB_COUNT=0\nLANGUAGE_REBUILD_COUNT=0\nTHREAD_COUNT=44\nPOST_COUNT=44\nADMIN_COUNT=1\nBOARD_ACTIVE=true\nREGISTRATION_ENABLED=false\nPHP_OUTPUT_END\nVERIFY_OUTPUT_END\nPROD_PREFLIGHT_STATE={\"XF_SHA\":\"d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\",\"PHP_RC\":\"0\",\"PHP_STDERR_SHA256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"DEFAULT_LANGUAGE_ID\":\"1\",\"RU_COUNT\":\"0\",\"LANGUAGE_COUNT\":\"1\",\"ENGLISH_ID1_EXISTS\":\"1\",\"RU_PHRASE_COUNT\":\"0\",\"PHRASE_MAP_LANG2_COUNT\":\"0\",\"MANUAL_JOB_COUNT\":\"0\",\"LANGUAGE_REBUILD_COUNT\":\"0\",\"THREAD_COUNT\":\"44\",\"POST_COUNT\":\"44\",\"ADMIN_COUNT\":\"1\",\"BOARD_ACTIVE\":\"true\",\"REGISTRATION_ENABLED\":\"false\"}\nPROD_PREFLIGHT_PRISTINE=true\nPROD_SNAPSHOT_RC=0\nPROD_QGA_POST_SNAPSHOT_TRIES=1\nPREFLIGHT_TRANSPORT_RC=0\nPREFLIGHT_EXITCODE=0\nPREFLIGHT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nPREFLIGHT_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nPRE_8de7be8a08_EXISTS=true\nPRE_c77f45df09_EXISTS=true\nPRE_83b35b44e3_EXISTS=true\nPRE_5dcfee669e_EXISTS=true\nWWW_DATA_UID=33\nWWW_DATA_GID=33\nPREFLIGHT_OUTPUT_END\nWRITE_ZIP_TRANSPORT_RC=0\nWRITE_ZIP_EXITCODE=0\nWRITE_ZIP_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nWRITE_ZIP_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nZIP_STDIN_BYTES=298309\nZIP_STDIN_SHA256=68e0308b23a30dadd6399032fbef22e09693220a97a602ee6ef8a8c5492bce6b\nWRITE_ZIP_OUTPUT_END\nEXTRACT_TRANSPORT_RC=0\nEXTRACT_EXITCODE=0\nEXTRACT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nEXTRACT_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nZIP_XML_COUNT=1\nEXTRACTED_XML_BYTES=2240918\nEXTRACTED_XML_SHA256=36e02066e1d3f81827acb009937e79fcecbd686148bbbfe977dfeb3f5b000a63\nEXTRACT_OUTPUT_END\nIMPORT_TRANSPORT_RC=0\nIMPORT_EXITCODE=0\nIMPORT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nIMPORT_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nPHP_RC=0\nPHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nPHP_OUTPUT_BEGIN\nRU_LANGUAGE_ID=2\nRU_PHRASE_COUNT=11142\nMANUAL_JOB_COUNT_AFTER_IMPORT=1\nLANGUAGE_REBUILD_COUNT_AFTER_IMPORT=1\nSET_DEFAULT_RU=true\nSET_PROD_BOARD_ACTIVE=true\nPHP_OUTPUT_END\nIMPORT_OUTPUT_END\nLANGUAGE_REBUILD_MANUAL_JOB_BEFORE=1\nRUN_MANUAL_JOB_TRANSPORT_RC=0\nRUN_MANUAL_JOB_EXITCODE=0\nRUN_MANUAL_JOB_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nRUN_MANUAL_JOB_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nRUN_JOBS_RC=0\nRUN_JOBS_STDOUT=All outstanding jobs have run. \nRUN_JOBS_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nRUN_MANUAL_JOB_OUTPUT_END\nVERIFY_TRANSPORT_RC=0\nVERIFY_EXITCODE=0\nVERIFY_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nVERIFY_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nPHP_RC=0\nPHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nPHP_OUTPUT_BEGIN\nDEFAULT_LANGUAGE_ID=2\nRU_COUNT=1\nLANGUAGE_COUNT=2\nENGLISH_ID1_EXISTS=1\nRU_PHRASE_COUNT=11142\nPHRASE_MAP_LANG2_COUNT=11194\nMANUAL_JOB_COUNT=0\nLANGUAGE_REBUILD_COUNT=0\nTHREAD_COUNT=44\nPOST_COUNT=44\nADMIN_COUNT=1\nBOARD_ACTIVE=true\nREGISTRATION_ENABLED=false\nPHP_OUTPUT_END\nVERIFY_OUTPUT_END\nEXPECTED_PHRASE_MAP_LANG2_COUNT=11194\nACTUAL_PHRASE_MAP_LANG2_COUNT=11194\nPROD_POST_JOB_STATE_OK=true\nCURL_TRANSPORT_RC=0\nCURL_EXITCODE=0\nCURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nCURL_RC=0\nCURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_BODY_BYTES=77563\nCURL_BODY_SHA256=75c3f6fe94b0bb9a256453e1ee6c2ddeb25922081d49df3766f2b919ea440597\nCURL_META=200|77562|http://127.0.0.1/index.php\nCURL_HAS_PVEPRO=true\nCURL_HAS_RUSSIAN=true\nCURL_OUTPUT_END\nCURL_TRANSPORT_RC=0\nCURL_EXITCODE=0\nCURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nCURL_RC=0\nCURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_BODY_BYTES=77563\nCURL_BODY_SHA256=c0223dd51c6bf730b7fa8b9796fe550c87dd86331e09ab31b0ba83903deddd5c\nCURL_META=200|77562|http://127.0.0.1/index.php\nCURL_HAS_PVEPRO=true\nCURL_HAS_RUSSIAN=true\nCURL_OUTPUT_END\nCURL_TRANSPORT_RC=0\nCURL_EXITCODE=0\nCURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nCURL_RC=0\nCURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCURL_BODY_BYTES=77563\nCURL_BODY_SHA256=75604368701d0f4e0d64de59972ce520d51eada71fa7f1128fd816cd44ba9b3c\nCURL_META=200|77562|http://127.0.0.1/index.php\nCURL_HAS_PVEPRO=true\nCURL_HAS_RUSSIAN=true\nCURL_OUTPUT_END\nPROD_LOCAL_RENDER_SAMPLES=[{\"sample\":1,\"meta\":\"200|77562|http://127.0.0.1/index.php\",\"bytes\":\"77563\",\"pvepro\":\"true\",\"russian\":\"true\",\"ok\":true},{\"sample\":2,\"meta\":\"200|77562|http://127.0.0.1/index.php\",\"bytes\":\"77563\",\"pvepro\":\"true\",\"russian\":\"true\",\"ok\":true},{\"sample\":3,\"meta\":\"200|77562|http://127.0.0.1/index.php\",\"bytes\":\"77563\",\"pvepro\":\"true\",\"russian\":\"true\",\"ok\":true}]\nPROD_LOCAL_RENDER_GOOD_SAMPLES=3\nPROD_LOCAL_RUSSIAN_RENDER_OK=true\nPUBLIC_RUSSIAN_SAMPLES=[{\"rc\":0,\"bytes\":77564,\"meta\":\"200|77564|https://pvepro.ru/index.php\",\"pvepro\":true,\"russian\":true,\"sha256\":\"88298b0df6320f72c44ece92107db37a346846be560414c8750d4d001ddfbb9c\",\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"ok\":true,\"sample\":1},{\"rc\":0,\"bytes\":77564,\"meta\":\"200|77564|https://pvepro.ru/index.php\",\"pvepro\":true,\"russian\":true,\"sha256\":\"6c71d16e595e848b2a922a92152f1799d731704f159eb104e3bed4f7f5f2b4d7\",\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"ok\":true,\"sample\":2},{\"rc\":0,\"bytes\":77564,\"meta\":\"200|77564|https://pvepro.ru/index.php\",\"pvepro\":true,\"russian\":true,\"sha256\":\"64c95996b161f134cc827ba7026d145ae62140847c61bcddb09080704fe71f48\",\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"ok\":true,\"sample\":3},{\"rc\":0,\"bytes\":77564,\"meta\":\"200|77564|https://pvepro.ru/index.php\",\"pvepro\":true,\"russian\":true,\"sha256\":\"53560fc2a5614663d1c88f49a9d411dd13bb0630ce575c9f80669aefcd651deb\",\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"ok\":true,\"sample\":4},{\"rc\":0,\"bytes\":77564,\"meta\":\"200|77564|https://pvepro.ru/index.php\",\"pvepro\":true,\"russian\":true,\"sha256\":\"e07eda0b107e5b8e5054295587b63d2ededa5b5f512fc5336510677486045ac5\",\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"ok\":true,\"sample\":5}]\nPUBLIC_RUSSIAN_GOOD_SAMPLES=5\nPUBLIC_RUSSIAN_STABLE=true\nCLEANUP_TRANSPORT_RC=0\nCLEANUP_EXITCODE=0\nCLEANUP_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nCLEANUP_OUTPUT_BEGIN\nXF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219\nTEMP_FILES_REMOVED=true\nCLEANUP_OUTPUT_END\nPROD_SNAPSHOT_DELETE_RC=0\nSTAGING_MUTATED=false\nPRODUCTION_LANGUAGE_PROMOTED=true\nDEFAULT_LANGUAGE_ID=2\nRUSSIAN_LANGUAGE_CODE=ru-RU\nRUSSIAN_PHRASE_COUNT=11142\nRUSSIAN_PHRASE_MAP_COUNT=11194\nENGLISH_FALLBACK_RETAINED=true\nREGISTRATION_PUBLIC_LAUNCH=CLOSED\nRUSSIAN_CORE_CHECKPOINT_COMPLETE=true\nTASK_COMPLETE=true\nTASK_RESULT=PASS_PVEPRO_RUSSIAN_PRODUCTION_PROMOTION\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260920-PVEPRO-RUSSIAN-PRODUCTION-PROMOTION-737R3\",\"status\":\"OK\",\"changes_made\":true,\"rollback_started\":false,\"rollback_restored\":null}\n" + "output": "NEWFI207_BEGIN=true\nMODE=read-only\nIMMUTABLE_PLAN_CHECK=PASS\nCHANGES_MADE=false\nMUTATION_OUTCOME=NO_MUTATION\nPIN_CHECK=PASS\nACCEPTED_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b\nRELEASE_FILE_COUNT=6\nINTERESTING_FILE_COUNT=6\nFILE_1_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nFILE_1_BYTES=10566\nFILE_1_MODE=0o400\nFILE_1_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\nFILE_1_KEYWORD_SCORE=13\nFILE_1_AST_DEF_COUNT=0\nFILE_1_AST_IMPORT_COUNT=0\nFILE_1_AST_STRING_COUNT=7\nFILE_1_STRING_1_LINE=4\nFILE_1_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nFILE_1_STRING_2_LINE=62\nFILE_1_STRING_2_VALUE=backup_target\nFILE_1_STRING_3_LINE=62\nFILE_1_STRING_3_VALUE=ssh_remote\nFILE_1_STRING_4_LINE=135\nFILE_1_STRING_4_VALUE=payload_sha256\nFILE_1_STRING_5_LINE=135\nFILE_1_STRING_5_VALUE=manifest_sha256\nFILE_1_STRING_6_LINE=135\nFILE_1_STRING_6_VALUE=replicas\nFILE_1_STRING_7_LINE=132\nFILE_1_STRING_7_VALUE=homelab-scheduler-proof-\nFILE_2_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nFILE_2_BYTES=13825\nFILE_2_MODE=0o400\nFILE_2_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d\nFILE_2_KEYWORD_SCORE=9\nFILE_2_AST_DEF_COUNT=2\nFILE_2_DEF_1_LINE=35\nFILE_2_DEF_1_NAME=_remote_sha\nFILE_2_DEF_2_LINE=117\nFILE_2_DEF_2_NAME=_execute_remote\nFILE_2_AST_IMPORT_COUNT=0\nFILE_2_AST_STRING_COUNT=17\nFILE_2_STRING_1_LINE=79\nFILE_2_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-plan-only\nFILE_2_STRING_2_LINE=118\nFILE_2_STRING_2_VALUE=REMOTE_NODE\nFILE_2_STRING_3_LINE=119\nFILE_2_STRING_3_VALUE=REMOTE_ARGV\nFILE_2_STRING_4_LINE=120\nFILE_2_STRING_4_VALUE=REMOTE_ARGV_NODE\nFILE_2_STRING_5_LINE=121\nFILE_2_STRING_5_VALUE=REMOTE_CAP_VALUE\nFILE_2_STRING_6_LINE=124\nFILE_2_STRING_6_VALUE=REMOTE_WORKDIR\nFILE_2_STRING_7_LINE=158\nFILE_2_STRING_7_VALUE=remote-bounded-ssh-cwd-root\nFILE_2_STRING_8_LINE=198\nFILE_2_STRING_8_VALUE=/var/tmp/homelab-vzdump-v2-\nFILE_2_STRING_9_LINE=149\nFILE_2_STRING_9_VALUE=REMOTE_TIMEOUT\nFILE_2_STRING_10_LINE=151\nFILE_2_STRING_10_VALUE=REMOTE_RC\nFILE_2_STRING_11_LINE=152\nFILE_2_STRING_11_VALUE=REMOTE_EMPTY\nFILE_2_STRING_12_LINE=155\nFILE_2_STRING_12_VALUE=REMOTE_FILE_IDENTITY\nFILE_2_STRING_13_LINE=162\nFILE_2_STRING_13_VALUE=remote-bounded-ssh-cwd-root\nFILE_2_STRING_14_LINE=204\nFILE_2_STRING_14_VALUE=payload.bin\nFILE_2_STRING_15_LINE=210\nFILE_2_STRING_15_VALUE=VZDUMP_PAYLOAD_BOUND\nFILE_2_STRING_16_LINE=138\nFILE_2_STRING_16_VALUE=REMOTE_TIMEOUT\nFILE_2_STRING_17_LINE=143\nFILE_2_STRING_17_VALUE=REMOTE_CAP\nFILE_3_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\nFILE_3_BYTES=4627\nFILE_3_MODE=0o400\nFILE_3_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b\nFILE_3_KEYWORD_SCORE=9\nFILE_3_AST_DEF_COUNT=1\nFILE_3_DEF_1_LINE=11\nFILE_3_DEF_1_NAME=_remote_sha\nFILE_3_AST_IMPORT_COUNT=0\nFILE_3_AST_STRING_COUNT=3\nFILE_3_STRING_1_LINE=48\nFILE_3_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-\nFILE_3_STRING_2_LINE=66\nFILE_3_STRING_2_VALUE=payload.bin\nFILE_3_STRING_3_LINE=70\nFILE_3_STRING_3_VALUE=QEMU_PAYLOAD_MISSING\nFILE_4_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nFILE_4_BYTES=4097\nFILE_4_MODE=0o400\nFILE_4_SHA256=a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96\nFILE_4_KEYWORD_SCORE=9\nFILE_4_AST_DEF_COUNT=0\nFILE_4_AST_IMPORT_COUNT=0\nFILE_4_AST_STRING_COUNT=9\nFILE_4_STRING_1_LINE=44\nFILE_4_STRING_1_VALUE=last_success_payload_sha256\nFILE_4_STRING_2_LINE=45\nFILE_4_STRING_2_VALUE=last_success_manifest_sha256\nFILE_4_STRING_3_LINE=45\nFILE_4_STRING_3_VALUE=last_success_replicas\nFILE_4_STRING_4_LINE=37\nFILE_4_STRING_4_VALUE=payload_sha256\nFILE_4_STRING_5_LINE=37\nFILE_4_STRING_5_VALUE=last_success_payload_sha256\nFILE_4_STRING_6_LINE=38\nFILE_4_STRING_6_VALUE=manifest_sha256\nFILE_4_STRING_7_LINE=38\nFILE_4_STRING_7_VALUE=last_success_manifest_sha256\nFILE_4_STRING_8_LINE=38\nFILE_4_STRING_8_VALUE=replicas\nFILE_4_STRING_9_LINE=38\nFILE_4_STRING_9_VALUE=last_success_replicas\nFILE_5_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nFILE_5_BYTES=3449\nFILE_5_MODE=0o400\nFILE_5_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3\nFILE_5_KEYWORD_SCORE=7\nFILE_5_AST_DEF_COUNT=0\nFILE_5_AST_IMPORT_COUNT=0\nFILE_5_AST_STRING_COUNT=2\nFILE_5_STRING_1_LINE=4\nFILE_5_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411\nFILE_5_STRING_2_LINE=45\nFILE_5_STRING_2_VALUE=payload.bin\nFILE_6_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nFILE_6_BYTES=2320\nFILE_6_MODE=0o400\nFILE_6_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011\nFILE_6_KEYWORD_SCORE=3\nFILE_6_AST_DEF_COUNT=0\nFILE_6_AST_IMPORT_COUNT=0\nFILE_6_AST_STRING_COUNT=1\nFILE_6_STRING_1_LINE=4\nFILE_6_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nCTX_1_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_1_START_LINE=15\nCTX_1_END_LINE=21\nCTX_1_L15=}\nCTX_1_L16=\nCTX_1_L17=def _sha(p):\nCTX_1_L18= h=hashlib.sha256()\nCTX_1_L19= with open(p,'rb',buffering=0) as f:\nCTX_1_L20= while True:\nCTX_1_L21= b=f.read(1<<20)\nCTX_2_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_2_START_LINE=34\nCTX_2_END_LINE=40\nCTX_2_L34=\nCTX_2_L35=class _GlobalsProxy:\nCTX_2_L36= __slots__=('_g',)\nCTX_2_L37= def __init__(self,g): object.__setattr__(self,'_g',g)\nCTX_2_L38= def __getattr__(self,n):\nCTX_2_L39= try: return self._g[n]\nCTX_2_L40= except KeyError as e: raise AttributeError(n) from e\nCTX_3_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_3_START_LINE=59\nCTX_3_END_LINE=72\nCTX_3_L59= if len(found)!=1:\nCTX_3_L60= raise RuntimeError('LEGACY_PROVENANCE_CARDINALITY')\nCTX_3_L61= g=next(iter(found.values()))\nCTX_3_L62= required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',\nCTX_3_L63= '_default_unprivileged_lxc','mapped_scratch_probe','_stream_argv_to_local','run',\nCTX_3_L64= 'choose_due_target','write_state','epoch')\nCTX_3_L65= if any(not callable(g.get(n)) for n in required):\nCTX_3_L66= raise RuntimeError('LEGACY_PROVENANCE_API')\nCTX_3_L67= original=g['capture_pve_guest']\nCTX_3_L68= proxy=_GlobalsProxy(g)\nCTX_3_L69= if not isinstance(g.get('SCP'),str) or not g['SCP'].startswith('/'):\nCTX_3_L70= raise RuntimeError('LEGACY_SCP_API')\nCTX_3_L71= qemu_patched=qemu_adapter.bind(proxy,original)\nCTX_3_L72= if not callable(qemu_patched):\nCTX_4_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_4_START_LINE=75\nCTX_4_END_LINE=82\nCTX_4_L75= if not callable(patched):\nCTX_4_L76= raise RuntimeError('LXC_ADAPTER_BIND_RESULT')\nCTX_4_L77= g['capture_pve_guest']=patched\nCTX_4_L78= scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])\nCTX_4_L79= if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:\nCTX_4_L80= raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')\nCTX_4_L81= return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}\nCTX_4_L82=\nCTX_5_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_5_START_LINE=96\nCTX_5_END_LINE=117\nCTX_5_L96= wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)\nCTX_5_L97= return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired\nCTX_5_L98=\nCTX_5_L99=def _target(wrapper,lid):\nCTX_5_L100= rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]\nCTX_5_L101= if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')\nCTX_5_L102= return hits[0]\nCTX_5_L103=\nCTX_5_L104=def selftest():\nCTX_5_L105= wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()\nCTX_5_L106= if wired['legacy_globals'].get('capture_pve_guest') is not wired['patched_capture']:\nCTX_5_L107= raise RuntimeError('PATCH_BINDING')\nCTX_5_L108= if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:\nCTX_5_L109= raise RuntimeError('SCHEDULER_CHOOSE_BINDING')\nCTX_5_L110= if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:\nCTX_5_L111= raise RuntimeError('SCHEDULER_WRITE_BINDING')\nCTX_5_L112= if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:\nCTX_5_L113= raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')\nCTX_5_L114= if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):\nCTX_5_L115= raise RuntimeError('WRAPPER_PUBLIC_API')\nCTX_5_L116= print('SELFTEST_OVERLAY504=PASS',flush=True)\nCTX_5_L117= return 0\nCTX_6_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py\nCTX_6_START_LINE=125\nCTX_6_END_LINE=187\nCTX_6_L125= if argv==['scheduler-proof']:\nCTX_6_L126= import tempfile\nCTX_6_L127= legacy=wired['legacy']; g=wired['legacy_globals']\nCTX_6_L128= old_root=g.get('STATE_ROOT'); old_epoch=g.get('epoch')\nCTX_6_L129= if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')\nCTX_6_L130= now=[1000]\nCTX_6_L131= try:\nCTX_6_L132= with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td:\nCTX_6_L133= g['STATE_ROOT']=pathlib.Path(td); (g['STATE_ROOT']/'state').mkdir(mode=0o700)\nCTX_6_L134= g['epoch']=lambda: now[0]\nCTX_6_L135= common={'payload_sha256':'a'*64,'manifest_sha256':'b'*64,'replicas':['proof-r1','proof-r2']}\nCTX_6_L136= legacy.write_state('proof-a','SUCCESS',generation='proof-a-good',**common)\nCTX_6_L137= legacy.write_state('proof-b','SUCCESS',generation='proof-b-good',**common)\nCTX_6_L138= now[0]=100000\nCTX_6_L139= legacy.write_state('proof-a','FAIL',generation='proof-a-bad',reason='PROOF_FAILURE',sealed=False)\nCTX_6_L140= state=legacy.load_state_all(); a=state['proof-a']\nCTX_6_L141= targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}]\nCTX_6_L142= first=legacy.choose_due_target(targets,state,now[0])\nCTX_6_L143= if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED')\nCTX_6_L144= retry=int(a.get('retry_after_epoch',0)); preserved=int(a.get('last_success_epoch',0))\nCTX_6_L145= if preserved!=1000 or a.get('last_success_generation')!='proof-a-good' or int(a.get('consecutive_failures',0))!=1 or retry!=101800:\nCTX_6_L146= raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE')\nCTX_6_L147= now[0]=retry+1\nCTX_6_L148= second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0])\nCTX_6_L149= if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE')\nCTX_6_L150= legacy.write_state('proof-a','SUCCESS',generation='proof-a-recovered',**common)\nCTX_6_L151= recovered=legacy.load_state_all()['proof-a']\nCTX_6_L152= if int(recovered.get('consecutive_failures',-1))!=0 or int(recovered.get('retry_after_epoch',-1))!=0:\nCTX_6_L153= raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET')\nCTX_6_L154= 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}\nCTX_6_L155= print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True)\nCTX_6_L156= return 0\nCTX_6_L157= finally:\nCTX_6_L158= g['STATE_ROOT']=old_root; g['epoch']=old_epoch\nCTX_6_L159= if argv==['scheduler-select-live']:\nCTX_6_L160= state=legacy.load_state_all(); targets=wrapper.load_targets()\nCTX_6_L161= chosen=legacy.choose_due_target(targets,state)\nCTX_6_L162= if chosen is None:\nCTX_6_L163= print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True)\nCTX_6_L164= else:\nCTX_6_L165= 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)\nCTX_6_L166= return 0\nCTX_6_L167= if len(argv)==2 and argv[0]=='plan-lxc':\nCTX_6_L168= t=_target(wrapper,argv[1])\nCTX_6_L169= if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112':\nCTX_6_L170= raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC')\nCTX_6_L171= out=lxc_adapter.plan_only(legacy,t)\nCTX_6_L172= 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)\nCTX_6_L173= return 0\nCTX_6_L174= if len(argv)==2 and argv[0]=='verify-target':\nCTX_6_L175= t=_target(wrapper,argv[1])\nCTX_6_L176= if t.get('logical_id')=='guest-pve01-lxc-112':\nCTX_6_L177= raise RuntimeError('VERIFY_SYNTHETIC_CT112_FORBIDDEN')\nCTX_6_L178= try:\nCTX_6_L179= out=wrapper.backup_target(t,True)\nCTX_6_L180= except legacy.BackupError as e:\nCTX_6_L181= print('VERIFY_TARGET_RESULT=FAIL',flush=True)\nCTX_6_L182= print('VERIFY_TARGET_REASON='+str(e.code),flush=True)\nCTX_6_L183= return 2\nCTX_6_L184= print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True)\nCTX_6_L185= return 0\nCTX_6_L186= return wrapper.main([sys.argv[0],*argv])\nCTX_6_L187=\nCTX_7_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_7_START_LINE=20\nCTX_7_END_LINE=26\nCTX_7_L20= except Exception as e: raise AdapterError(code) from e\nCTX_7_L21=\nCTX_7_L22=def _sha_file(p):\nCTX_7_L23= h=hashlib.sha256()\nCTX_7_L24= with open(p,'rb',buffering=0) as f:\nCTX_7_L25= for b in iter(lambda:f.read(1<<20),b''): h.update(b)\nCTX_7_L26= return h.hexdigest()\nCTX_8_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_8_START_LINE=32\nCTX_8_END_LINE=62\nCTX_8_L32= if n<=0: raise AdapterError('WRITE_FAILED')\nCTX_8_L33= view=view[n:]\nCTX_8_L34=\nCTX_8_L35=def _remote_sha(legacy,node,path):\nCTX_8_L36= p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)\nCTX_8_L37= parts=p.stdout.decode('ascii','strict').strip().split()\nCTX_8_L38= _need(len(parts)>=2 and parts[1]==path,'TOOL_SHA_OUTPUT')\nCTX_8_L39= return parts[0]\nCTX_8_L40=\nCTX_8_L41=def _live_inputs(legacy,node,vmid,scratch):\nCTX_8_L42= _need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')\nCTX_8_L43= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')\nCTX_8_L44= rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')\nCTX_8_L45= stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')\nCTX_8_L46= _need(type(rows) is list and type(stores) is list,'PVE_LIST_SCHEMA')\nCTX_8_L47= configs=[]\nCTX_8_L48= for r in rows:\nCTX_8_L49= if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue\nCTX_8_L50= try: rid=int(r.get('vmid'))\nCTX_8_L51= except Exception: raise AdapterError('RESOURCE_VMID')\nCTX_8_L52= cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r[\"type\"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')\nCTX_8_L53= _need(type(cfg) is dict,'CONFIG_SCHEMA')\nCTX_8_L54= configs.append([rid,cfg])\nCTX_8_L55= tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')\nCTX_8_L56= _need(type(tasks) is list and len(tasks)<1000,'TASKS_SCHEMA')\nCTX_8_L57= q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)\nCTX_8_L58= defaults=None\nCTX_8_L59= if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout\nCTX_8_L60= elif q.returncode!=1: raise AdapterError('DEFAULTS_PROBE')\nCTX_8_L61= st=os.statvfs('/mnt/staging'); free=int(st.f_bavail*st.f_frsize)\nCTX_8_L62= return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,\nCTX_9_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_9_START_LINE=85\nCTX_9_END_LINE=91\nCTX_9_L85= a=_helper(_live_inputs(legacy,node,vmid,scratch)); b=_helper(_live_inputs(legacy,node,vmid,scratch))\nCTX_9_L86= _need(_stable_job(a['job'])==_stable_job(b['job']),'FRESH_PLAN_UNSTABLE')\nCTX_9_L87= _need(a['argv']==b['argv'],'FRESH_ARGV_UNSTABLE')\nCTX_9_L88= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_POST')\nCTX_9_L89= return b\nCTX_9_L90=\nCTX_9_L91=def _execute_local(legacy,node,argv,dest,cap,timeout):\nCTX_10_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_10_START_LINE=94\nCTX_10_END_LINE=109\nCTX_10_L94= data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode()\nCTX_10_L95= p=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV)\nCTX_10_L96= if p.stderr or not p.stdout or len(p.stdout)>262144:\nCTX_10_L97= raise ExecFailure('LOCAL_HELPER_PROTOCOL',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)})\nCTX_10_L98= try: out=json.loads(p.stdout)\nCTX_10_L99= except Exception:\nCTX_10_L100= raise ExecFailure('LOCAL_HELPER_JSON',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)})\nCTX_10_L101= summary={'executor':'local-proven-pve270','helper_rc':p.returncode,'exception_class':out.get('exception_class'),'exception_message_sha256':out.get('exception_message_sha256')}\nCTX_10_L102= if isinstance(out.get('process'),dict): summary.update(out['process'])\nCTX_10_L103= if p.returncode!=0 or out.get('status')!='OK': raise ExecFailure('LOCAL_PRODUCER_FAILED',summary)\nCTX_10_L104= result=out.get('result'); _need(type(result) is dict,'LOCAL_RESULT_SCHEMA')\nCTX_10_L105= _need(pathlib.Path(dest).is_file() and pathlib.Path(dest).stat().st_size==int(result.get('size',-1)),'LOCAL_RESULT_FILE')\nCTX_10_L106= return summary|{'size':result['size'],'sha256':result['sha256'],'producer_rc':result.get('producer_rc')}\nCTX_10_L107=\nCTX_10_L108=def _kill(p):\nCTX_10_L109= try: os.killpg(p.pid,signal.SIGTERM)\nCTX_11_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_11_START_LINE=114\nCTX_11_END_LINE=166\nCTX_11_L114= except ProcessLookupError: pass\nCTX_11_L115= p.wait()\nCTX_11_L116=\nCTX_11_L117=def _execute_remote(legacy,node,argv,dest,cap,timeout):\nCTX_11_L118= _need(re.fullmatch(r'pve0[123]',str(node)) is not None and node!='pve01','REMOTE_NODE')\nCTX_11_L119= _need(type(argv) is list and argv and argv[0]=='/usr/bin/vzdump' and all(type(x) is str and '\\x00' not in x for x in argv),'REMOTE_ARGV')\nCTX_11_L120= _need('--node' in argv and argv[argv.index('--node')+1]==node,'REMOTE_ARGV_NODE')\nCTX_11_L121= _need(type(cap) is int and 0=deadline: raise ExecFailure('REMOTE_TIMEOUT',{})\nCTX_11_L139= for key,_ in sel.select(min(.2,max(0,deadline-now))):\nCTX_11_L140= b=os.read(key.fileobj.fileno(),65536)\nCTX_11_L141= if not b: sel.unregister(key.fileobj); continue\nCTX_11_L142= if key.fileobj is p.stdout:\nCTX_11_L143= if total+len(b)>cap: raise ExecFailure('REMOTE_CAP',{})\nCTX_11_L144= _write_all(fd,b); digest.update(b); total+=len(b)\nCTX_11_L145= else:\nCTX_11_L146= err_total+=len(b); eh.update(b); keep=b[:max(0,MAX_STDERR-err_kept)]\nCTX_11_L147= if keep: _write_all(efd,keep); err_kept+=len(keep)\nCTX_11_L148= left=deadline-time.monotonic()\nCTX_11_L149= if left<=0: raise ExecFailure('REMOTE_TIMEOUT',{})\nCTX_11_L150= rc=p.wait(timeout=left)\nCTX_11_L151= if rc!=0: raise ExecFailure('REMOTE_RC',{})\nCTX_11_L152= if total<=0: raise ExecFailure('REMOTE_EMPTY',{})\nCTX_11_L153= stf=os.fstat(fd); named=os.stat(dest,follow_symlinks=False)\nCTX_11_L154= if (stf.st_dev,stf.st_ino)!=(initial.st_dev,initial.st_ino) or (named.st_dev,named.st_ino)!=(initial.st_dev,initial.st_ino) or stf.st_nlink!=1 or stf.st_size!=total:\nCTX_11_L155= raise ExecFailure('REMOTE_FILE_IDENTITY',{})\nCTX_11_L156= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_EXEC_POST')\nCTX_11_L157= os.fchmod(fd,0o400); os.fsync(fd); os.fsync(efd); good=True\nCTX_11_L158= return {'executor':'remote-bounded-ssh-cwd-root','producer_rc':rc,'size':total,'sha256':digest.hexdigest(),\nCTX_11_L159= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}\nCTX_11_L160= except ExecFailure as e:\nCTX_11_L161= if p is not None and p.poll() is None: _kill(p)\nCTX_11_L162= summary={'executor':'remote-bounded-ssh-cwd-root','producer_rc':None if p is None else p.returncode,'archive_bytes':total,\nCTX_11_L163= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}\nCTX_11_L164= summary.update(e.summary); raise ExecFailure(e.code,summary)\nCTX_11_L165= finally:\nCTX_11_L166= if p is not None:\nCTX_12_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_12_START_LINE=171\nCTX_12_END_LINE=178\nCTX_12_L171= try: os.fsync(fd); os.fsync(efd)\nCTX_12_L172= except OSError: pass\nCTX_12_L173= os.close(fd); os.close(efd)\nCTX_12_L174= summary={'process_started':p is not None,'producer_rc':None if p is None else p.returncode,'capture_success':good,'archive_bytes':total,\nCTX_12_L175= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest(),'raw_stderr_exported':False,'cwd':'/'}\nCTX_12_L176= try:\nCTX_12_L177= mb=(json.dumps(summary,separators=(',',':'),sort_keys=True)+'\\n').encode()\nCTX_12_L178= mfd=os.open(metap,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)\nCTX_13_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_13_START_LINE=182\nCTX_13_END_LINE=188\nCTX_13_L182=\nCTX_13_L183=def _emit_diag(node,summary):\nCTX_13_L184= safe={'node':node}\nCTX_13_L185= for k in ('executor','failure_code','helper_rc','producer_rc','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','exception_class','exception_message_sha256'):\nCTX_13_L186= if k in summary: safe[k]=summary[k]\nCTX_13_L187= print('LXC_EXECUTION_DIAG='+json.dumps(safe,separators=(',',':'),sort_keys=True),flush=True)\nCTX_13_L188=\nCTX_14_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py\nCTX_14_START_LINE=196\nCTX_14_END_LINE=218\nCTX_14_L196= _need(typ==t.get('guest_type')=='lxc','PVE_GUEST_TYPE_DRIFT')\nCTX_14_L197= legacy._default_unprivileged_lxc(node,vmid)\nCTX_14_L198= scratch=f'/var/tmp/homelab-vzdump-v2-{gen}'\nCTX_14_L199= legacy.ssh_remote(node,['install','-d','-m','710','-o','0','-g','100000',scratch],timeout=30)\nCTX_14_L200= q=legacy.ssh_remote(node,['stat','-c','%a:%u:%g',scratch],timeout=30)\nCTX_14_L201= _need(q.stdout.decode().strip()=='710:0:100000','PVE_MAPPED_SCRATCH_ACCESS_CONTRACT')\nCTX_14_L202= try:\nCTX_14_L203= legacy.mapped_scratch_probe(node,scratch)\nCTX_14_L204= p=plan_only(legacy,t,scratch); local=pathlib.Path(work)/'payload.bin'; cap=int(p['job']['archive_cap_bytes'])\nCTX_14_L205= try:\nCTX_14_L206= result=_execute_local(legacy,node,p['argv'],local,cap,7200) if node=='pve01' else _execute_remote(legacy,node,p['argv'],local,cap,7200)\nCTX_14_L207= except ExecFailure as e:\nCTX_14_L208= _emit_diag(node,e.summary|{'failure_code':e.code})\nCTX_14_L209= raise legacy.BackupError('LXC_PRODUCER_FAILED') from None\nCTX_14_L210= _need(local.is_file() and 0=2 and parts[1]==path,'QEMU_TOOL_SHA_OUTPUT')\nCTX_15_L15= return parts[0]\nCTX_15_L16=\nCTX_15_L17=def _select_qemu_outputs(vmid,files):\nCTX_15_L18= _need(type(vmid) is int and vmid>0,'QEMU_VMID')\nCTX_15_L19= _need(type(files) is list and files and all(type(x) is str and x.startswith('/') and '\\x00' not in x for x in files),'QEMU_OUTPUT_LIST')\nCTX_15_L20= _need(len(files)==len(set(files)),'QEMU_OUTPUT_DUPLICATE')\nCTX_15_L21= 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$')\nCTX_15_L22= archives=[]\nCTX_15_L23= for f in files:\nCTX_15_L24= name=pathlib.PurePosixPath(f).name\nCTX_15_L25= m=pat.fullmatch(name)\nCTX_15_L26= if m: archives.append((f,m.group(1)))\nCTX_15_L27= _need(len(archives)==1,'QEMU_ARCHIVE_NOT_UNIQUE')\nCTX_15_L28= archive,stamp=archives[0]; parent=pathlib.PurePosixPath(archive).parent\nCTX_15_L29= expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log'\nCTX_15_L30= allowed={archive}; log=None\nCTX_15_L31= if str(expected_log) in files:\nCTX_15_L32= log=str(expected_log); allowed.add(log)\nCTX_15_L33= _need(set(files)==allowed,'QEMU_OUTPUT_UNEXPECTED_FILE')\nCTX_15_L34= return archive,log\nCTX_15_L35=\nCTX_15_L36=def _emit_diag(**kw):\nCTX_15_L37= print('QEMU_EXECUTION_DIAG='+json.dumps(kw,separators=(',',':'),sort_keys=True),flush=True)\nCTX_16_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py\nCTX_16_START_LINE=44\nCTX_16_END_LINE=78\nCTX_16_L44= _need(len(rows)==1,'PVE_GUEST_NOT_UNIQUE')\nCTX_16_L45= row=rows[0]; node=row.get('node'); typ=row.get('type')\nCTX_16_L46= _need(typ==t.get('guest_type')=='qemu','PVE_GUEST_TYPE_DRIFT')\nCTX_16_L47= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')\nCTX_16_L48= srcdir=f'/var/tmp/homelab-vzdump-v2-{gen}'\nCTX_16_L49= legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)\nCTX_16_L50= try:\nCTX_16_L51= vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)\nCTX_16_L52= if vp.returncode!=0:\nCTX_16_L53= _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)\nCTX_16_L54= raise legacy.BackupError('QEMU_VZDUMP_FAILED')\nCTX_16_L55= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')\nCTX_16_L56= p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\\n'],timeout=30)\nCTX_16_L57= files=[x for x in p.stdout.decode('utf-8','strict').splitlines() if x]\nCTX_16_L58= try: src,log=_select_qemu_outputs(vmid,files)\nCTX_16_L59= except QemuAdapterError as e:\nCTX_16_L60= _emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))\nCTX_16_L61= raise legacy.BackupError(str(e)) from None\nCTX_16_L62= q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)\nCTX_16_L63= raw=q.stdout.decode('ascii','strict').strip()\nCTX_16_L64= _need(raw.isdigit() and int(raw)>0,'QEMU_ARCHIVE_STAT')\nCTX_16_L65= size=int(raw)\nCTX_16_L66= local=pathlib.Path(work)/'payload.bin'\nCTX_16_L67= if node=='pve01': local=pathlib.Path(src)\nCTX_16_L68= else:\nCTX_16_L69= legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)\nCTX_16_L70= _need(pathlib.Path(local).is_file() and pathlib.Path(local).stat().st_size==size,'QEMU_PAYLOAD_MISSING')\nCTX_16_L71= _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)\nCTX_16_L72= except Exception:\nCTX_16_L73= legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise\nCTX_16_L74= cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}\nCTX_16_L75= meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),\nCTX_16_L76= 'producer_contract':'strict-qemu-vma-zst-plus-matching-log-overlay503'}\nCTX_16_L77= return pathlib.Path(local),meta,cleanup\nCTX_16_L78= capture_pve_guest.__name__='capture_pve_guest'\nCTX_17_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_17_START_LINE=20\nCTX_17_END_LINE=28\nCTX_17_L20= n=max(1,_as_nonneg_int(consecutive_failures,1))\nCTX_17_L21= return min(MAX_BACKOFF,MIN_BACKOFF*(2**min(n-1,4)))\nCTX_17_L22=\nCTX_17_L23=def _read_prior(legacy,logical_id):\nCTX_17_L24= root=pathlib.Path(legacy.STATE_ROOT)/'state'\nCTX_17_L25= p=root/(str(logical_id)+'.json')\nCTX_17_L26= try:\nCTX_17_L27= if not p.is_file(): return {}\nCTX_17_L28= d=json.loads(p.read_text(encoding='utf-8'))\nCTX_18_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_18_START_LINE=34\nCTX_18_END_LINE=48\nCTX_18_L34= if not isinstance(prior,dict): return {}\nCTX_18_L35= if prior.get('result')=='SUCCESS':\nCTX_18_L36= out={'last_success_epoch':_as_nonneg_int(prior.get('last_success_epoch'),0)}\nCTX_18_L37= mapping=(('generation','last_success_generation'),('payload_sha256','last_success_payload_sha256'),\nCTX_18_L38= ('manifest_sha256','last_success_manifest_sha256'),('replicas','last_success_replicas'),\nCTX_18_L39= ('green_verified','last_success_green_verified'))\nCTX_18_L40= for src,dst in mapping:\nCTX_18_L41= if src in prior: out[dst]=prior[src]\nCTX_18_L42= return out\nCTX_18_L43= out={}\nCTX_18_L44= for k in ('last_success_epoch','last_success_generation','last_success_payload_sha256',\nCTX_18_L45= 'last_success_manifest_sha256','last_success_replicas','last_success_green_verified'):\nCTX_18_L46= if k in prior: out[k]=prior[k]\nCTX_18_L47= return out\nCTX_18_L48=\nCTX_19_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_19_START_LINE=50\nCTX_19_END_LINE=65\nCTX_19_L50= _need(callable(original_choose),'ORIGINAL_CHOOSE_REQUIRED')\nCTX_19_L51= _need(callable(original_write),'ORIGINAL_WRITE_REQUIRED')\nCTX_19_L52= _need(callable(getattr(legacy,'epoch',None)),'LEGACY_EPOCH_REQUIRED')\nCTX_19_L53= _need(hasattr(legacy,'STATE_ROOT'),'LEGACY_STATE_ROOT_REQUIRED')\nCTX_19_L54=\nCTX_19_L55= def choose_due_target(targets,state,now=None):\nCTX_19_L56= now=_as_nonneg_int(legacy.epoch() if now is None else now,0)\nCTX_19_L57= _need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA')\nCTX_19_L58= due=[]\nCTX_19_L59= for order,t in enumerate(targets):\nCTX_19_L60= if not isinstance(t,dict) or t.get('enabled') is not True: continue\nCTX_19_L61= lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0)\nCTX_19_L62= _need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA')\nCTX_19_L63= s=state.get(lid,{})\nCTX_19_L64= if not isinstance(s,dict): s={}\nCTX_19_L65= retry_after=_as_nonneg_int(s.get('retry_after_epoch'),0)\nCTX_20_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py\nCTX_20_START_LINE=72\nCTX_20_END_LINE=93\nCTX_20_L72= if not due: return None\nCTX_20_L73= return max(due,key=lambda x:(x[0],x[1]))[2]\nCTX_20_L74=\nCTX_20_L75= def write_state(logical_id,result,**kw):\nCTX_20_L76= now=_as_nonneg_int(legacy.epoch(),0)\nCTX_20_L77= prior=_read_prior(legacy,logical_id)\nCTX_20_L78= if result=='SUCCESS':\nCTX_20_L79= clean=dict(kw)\nCTX_20_L80= clean.update({'last_attempt_epoch':now,'consecutive_failures':0,'retry_after_epoch':0,'failure_backoff_seconds':0})\nCTX_20_L81= return original_write(logical_id,result,**clean)\nCTX_20_L82= failures=_as_nonneg_int(prior.get('consecutive_failures'),0)+1\nCTX_20_L83= backoff=backoff_seconds(failures)\nCTX_20_L84= clean=dict(kw)\nCTX_20_L85= clean.update(_success_snapshot(prior))\nCTX_20_L86= clean.update({'last_attempt_epoch':now,'consecutive_failures':failures,\nCTX_20_L87= 'retry_after_epoch':now+backoff,'failure_backoff_seconds':backoff})\nCTX_20_L88= return original_write(logical_id,result,**clean)\nCTX_20_L89=\nCTX_20_L90= legacy.choose_due_target=choose_due_target\nCTX_20_L91= legacy.write_state=write_state\nCTX_20_L92= return {'choose_due_target':choose_due_target,'write_state':write_state,\nCTX_20_L93= 'original_choose':original_choose,'original_write':original_write}\nCTX_21_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_21_START_LINE=7\nCTX_21_END_LINE=13\nCTX_21_L7=MAX_INPUT=262144\nCTX_21_L8=\nCTX_21_L9=def sha_file(p:pathlib.Path)->str:\nCTX_21_L10= h=hashlib.sha256()\nCTX_21_L11= with open(p,'rb',buffering=0) as f:\nCTX_21_L12= for b in iter(lambda:f.read(1<<20),b''): h.update(b)\nCTX_21_L13= return h.hexdigest()\nCTX_22_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_22_START_LINE=20\nCTX_22_END_LINE=33\nCTX_22_L20= if not p.is_file() or p.is_symlink(): return None\nCTX_22_L21= try: d=json.loads(p.read_bytes())\nCTX_22_L22= except Exception: return {'summary_read':'FAILED'}\nCTX_22_L23= keys=('process_started','producer_rc','capture_success','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','raw_stderr_exported','child_umask')\nCTX_22_L24= return {k:d.get(k) for k in keys if k in d}\nCTX_22_L25=\nCTX_22_L26=def selftest()->int:\nCTX_22_L27= if sha_file(VZDUMP)!=VZDUMP_SHA: fail('VZDUMP_IDENTITY')\nCTX_22_L28= sys.path.insert(0,str(BASE))\nCTX_22_L29= import adapter\nCTX_22_L30= adapter.verify_sources(); adapter.load_graph()\nCTX_22_L31= print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)\nCTX_22_L32= return 0\nCTX_22_L33=\nCTX_23_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py\nCTX_23_START_LINE=42\nCTX_23_END_LINE=66\nCTX_23_L42= argv=x['argv']; dest=pathlib.Path(x['dest']); cap=x['cap']; seconds=x['seconds']\nCTX_23_L43= 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')\nCTX_23_L44= if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH')\nCTX_23_L45= if not (dest.is_absolute() and dest.name=='payload.bin' and '..' not in dest.parts): fail('DEST')\nCTX_23_L46= if not (type(cap) is int and 0str:\nCTX_25_L9= return hashlib.sha256(p.read_bytes()).hexdigest()\nCTX_25_L10=\nCTX_25_L11=def fail(code:str):\nCTX_25_L12= raise RuntimeError(code)\nCTX_26_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nCTX_26_START_LINE=17\nCTX_26_END_LINE=23\nCTX_26_L17= if not p.is_file() or p.is_symlink() or sha(p)!=PVE265_SHA: fail('PVE265_IDENTITY')\nCTX_26_L18= sys.path.insert(0,str(C411))\nCTX_26_L19= import adapter\nCTX_26_L20= adapter.verify_sources()\nCTX_26_L21= guest266,pve265,_pve270,_pve282=adapter.load_graph()\nCTX_26_L22= data=sys.stdin.buffer.read(4_000_001)\nCTX_26_L23= if not data or len(data)>4_000_000: fail('INPUT_BOUND')\nCTX_27_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py\nCTX_27_START_LINE=36\nCTX_27_END_LINE=42\nCTX_27_L36= if job.get('configured_full_cycle_fits') is not True or job.get('compression_dependent') is not False: fail('JOB_CAPACITY_POLICY')\nCTX_27_L37= guest266.no_active_tasks(raw.get('tasks'),vmid)\nCTX_27_L38= argv=pve265.dump_argv(job,'/usr/bin/vzdump',scratch,now)\nCTX_27_L39= 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')\nCTX_27_L40= out={'schema':1,'argv':argv,'job':{k:job.get(k) for k in keep}}\nCTX_27_L41= sys.stdout.write(json.dumps(out,separators=(',',':'),sort_keys=True)+'\\n')\nCTX_27_L42= return 0\nUSA_STATE_FULL_SAFE_BEGIN=true\nUSA_STATE_FIELD=$.consecutive_failures=0\nUSA_STATE_FIELD=$.failure_backoff_seconds=0\nUSA_STATE_FIELD=$.generation=v2-md-relay-20260919T070058Z-0e409ea129e2\nUSA_STATE_FIELD=$.green_verified=False\nUSA_STATE_FIELD=$.last_attempt_epoch=1789801278\nUSA_STATE_FIELD=$.last_success_epoch=1789801278\nUSA_STATE_FIELD=$.logical_id=md-relay\nUSA_STATE_FIELD=$.manifest_sha256=6887c5423640738aeb2bc1d104d515df1d1a21e2cd2d3291481475aa81cb6838\nUSA_STATE_FIELD=$.payload_sha256=187401a5fbf6c29b4dfd77e5d272db77951aa45003d0d80e0be834235571f32f\nUSA_STATE_FIELD=$.replicas[0].crypt=pve03-mail-04-crypt\nUSA_STATE_FIELD=$.replicas[0].physical=pve03-mail-04\nUSA_STATE_FIELD=$.replicas[1].crypt=pve03-mail-01-crypt\nUSA_STATE_FIELD=$.replicas[1].physical=pve03-mail-01\nUSA_STATE_FIELD=$.result=SUCCESS\nUSA_STATE_FIELD=$.retry_after_epoch=0\nUSA_STATE_FIELD=$.schema=1\nUSA_STATE_FIELD=$.updated_at_utc=2026-09-19T07:01:18Z\nUSA_STATE_FULL_SAFE_END=true\nMOLDOVA_STATE_FULL_SAFE_BEGIN=true\nMOLDOVA_STATE_FIELD=$.consecutive_failures=6\nMOLDOVA_STATE_FIELD=$.failure_backoff_seconds=21600\nMOLDOVA_STATE_FIELD=$.generation=v2-us-netbird-20260920T000652Z-7ecdcfcafc12\nMOLDOVA_STATE_FIELD=$.last_attempt_epoch=1789862827\nMOLDOVA_STATE_FIELD=$.last_success_epoch=1789704670\nMOLDOVA_STATE_FIELD=$.last_success_generation=v2-us-netbird-20260918T041032Z-d7648be4c16b\nMOLDOVA_STATE_FIELD=$.last_success_green_verified=False\nMOLDOVA_STATE_FIELD=$.last_success_manifest_sha256=f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5\nMOLDOVA_STATE_FIELD=$.last_success_payload_sha256=e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf\nMOLDOVA_STATE_FIELD=$.last_success_replicas[0].crypt=pve01-mail-05-crypt\nMOLDOVA_STATE_FIELD=$.last_success_replicas[0].physical=pve01-mail-05\nMOLDOVA_STATE_FIELD=$.last_success_replicas[1].crypt=pve03-mail-04-crypt\nMOLDOVA_STATE_FIELD=$.last_success_replicas[1].physical=pve03-mail-04\nMOLDOVA_STATE_FIELD=$.logical_id=us-netbird\nMOLDOVA_STATE_FIELD=$.reason=PIPE_FAILED\nMOLDOVA_STATE_FIELD=$.result=FAIL\nMOLDOVA_STATE_FIELD=$.retry_after_epoch=1789884427\nMOLDOVA_STATE_FIELD=$.schema=1\nMOLDOVA_STATE_FIELD=$.sealed=False\nMOLDOVA_STATE_FIELD=$.updated_at_utc=2026-09-20T00:07:07Z\nMOLDOVA_STATE_FULL_SAFE_END=true\nHAS_RCLONE_SOURCE=false\nHAS_GENERATION_MANIFEST_PAYLOAD_SOURCE=true\nHAS_REMOTE_REPLICA_SOURCE=true\nDECISION=HOLD_BACKUP207_PRODUCER_CONTRACT_INCOMPLETE\nNEXT_GATE=READ_ONLY_TARGETED_MODULE_FOLLOWUP\nCLOUD_READS=0\nCLOUD_WRITES=0\nVPS_SSH_ATTEMPTS=0\nMESSENGERS214_CLOSED=false\nMAJOR_STAGES_REMAINING=8\nNEWFI207_END=true\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index f6a989b3..692b5cb9 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,208 +1,779 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=SUPPORT-260920-PVEPRO-RUSSIAN-PRODUCTION-PROMOTION-737R3 +COMMAND_ID=NEWFI-260920-NEWFDOM-MESSENGERS214-PRODUCER207 STATUS=OK RC=0 HOST=pve01 -MODE=change -COMPONENT=pvepro-russian-production-promotion +MODE=read-only +COMPONENT=newfi-newfdom-messengers214-backupv2-producer-contract-readonly-audit REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 -COMMAND_SHA256=ef9665faee60b4d430fb1b80fac16a3185b76d6defdb96b3b0f7805ea5e73408 +COMMAND_SHA256=ead8fdf05c4cb0a9b8b49f67777a3e68a7a96170d3e4b5061fa03171a66917da DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true -CHANGE_DECLARED=true +CHANGE_DECLARED=false RESULT_CONTRACT_VALID=true -RESULT_CONTRACT_STATUS=OK +RESULT_CONTRACT_STATUS=NOT_APPLICABLE RESULT_CONTRACT_ERROR=NONE COMMAND_RC=0 -CHANGES_MADE=true +CHANGES_MADE=false ROLLBACK_STARTED=false ROLLBACK_RESTORED=null -MUTATION_OUTCOME=MUTATED +MUTATION_OUTCOME=NO_MUTATION SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=3df50151bcdef254b90951adba906dde1344ddf15c5f2a414f792dc462232eb1 -SANITIZED_OUTPUT_SHA256=3df50151bcdef254b90951adba906dde1344ddf15c5f2a414f792dc462232eb1 +RAW_EVIDENCE_SHA256=99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec +SANITIZED_OUTPUT_SHA256=99d8dcf2767bb4aeb57e414153ec37f086162257482529c3dcce3939c780c5ec OUTPUT_BEGIN -RU_ARCHIVE_BYTES=298309 -RU_ARCHIVE_SHA256=68e0308b23a30dadd6399032fbef22e09693220a97a602ee6ef8a8c5492bce6b -PROD_QGA_TRIES_PRE=1 -VERIFY_TRANSPORT_RC=0 -VERIFY_EXITCODE=0 -VERIFY_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -VERIFY_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -PHP_RC=0 -PHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -PHP_OUTPUT_BEGIN -DEFAULT_LANGUAGE_ID=1 -RU_COUNT=0 -LANGUAGE_COUNT=1 -ENGLISH_ID1_EXISTS=1 -RU_PHRASE_COUNT=0 -PHRASE_MAP_LANG2_COUNT=0 -MANUAL_JOB_COUNT=0 -LANGUAGE_REBUILD_COUNT=0 -THREAD_COUNT=44 -POST_COUNT=44 -ADMIN_COUNT=1 -BOARD_ACTIVE=true -REGISTRATION_ENABLED=false -PHP_OUTPUT_END -VERIFY_OUTPUT_END -PROD_PREFLIGHT_STATE={"XF_SHA":"d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219","PHP_RC":"0","PHP_STDERR_SHA256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","DEFAULT_LANGUAGE_ID":"1","RU_COUNT":"0","LANGUAGE_COUNT":"1","ENGLISH_ID1_EXISTS":"1","RU_PHRASE_COUNT":"0","PHRASE_MAP_LANG2_COUNT":"0","MANUAL_JOB_COUNT":"0","LANGUAGE_REBUILD_COUNT":"0","THREAD_COUNT":"44","POST_COUNT":"44","ADMIN_COUNT":"1","BOARD_ACTIVE":"true","REGISTRATION_ENABLED":"false"} -PROD_PREFLIGHT_PRISTINE=true -PROD_SNAPSHOT_RC=0 -PROD_QGA_POST_SNAPSHOT_TRIES=1 -PREFLIGHT_TRANSPORT_RC=0 -PREFLIGHT_EXITCODE=0 -PREFLIGHT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -PREFLIGHT_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -PRE_8de7be8a08_EXISTS=true -PRE_c77f45df09_EXISTS=true -PRE_83b35b44e3_EXISTS=true -PRE_5dcfee669e_EXISTS=true -WWW_DATA_UID=33 -WWW_DATA_GID=33 -PREFLIGHT_OUTPUT_END -WRITE_ZIP_TRANSPORT_RC=0 -WRITE_ZIP_EXITCODE=0 -WRITE_ZIP_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -WRITE_ZIP_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -ZIP_STDIN_BYTES=298309 -ZIP_STDIN_SHA256=68e0308b23a30dadd6399032fbef22e09693220a97a602ee6ef8a8c5492bce6b -WRITE_ZIP_OUTPUT_END -EXTRACT_TRANSPORT_RC=0 -EXTRACT_EXITCODE=0 -EXTRACT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -EXTRACT_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -ZIP_XML_COUNT=1 -EXTRACTED_XML_BYTES=2240918 -EXTRACTED_XML_SHA256=36e02066e1d3f81827acb009937e79fcecbd686148bbbfe977dfeb3f5b000a63 -EXTRACT_OUTPUT_END -IMPORT_TRANSPORT_RC=0 -IMPORT_EXITCODE=0 -IMPORT_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -IMPORT_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -PHP_RC=0 -PHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -PHP_OUTPUT_BEGIN -RU_LANGUAGE_ID=2 -RU_PHRASE_COUNT=11142 -MANUAL_JOB_COUNT_AFTER_IMPORT=1 -LANGUAGE_REBUILD_COUNT_AFTER_IMPORT=1 -SET_DEFAULT_RU=true -SET_PROD_BOARD_ACTIVE=true -PHP_OUTPUT_END -IMPORT_OUTPUT_END -LANGUAGE_REBUILD_MANUAL_JOB_BEFORE=1 -RUN_MANUAL_JOB_TRANSPORT_RC=0 -RUN_MANUAL_JOB_EXITCODE=0 -RUN_MANUAL_JOB_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -RUN_MANUAL_JOB_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -RUN_JOBS_RC=0 -RUN_JOBS_STDOUT=All outstanding jobs have run. -RUN_JOBS_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -RUN_MANUAL_JOB_OUTPUT_END -VERIFY_TRANSPORT_RC=0 -VERIFY_EXITCODE=0 -VERIFY_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -VERIFY_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -PHP_RC=0 -PHP_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -PHP_OUTPUT_BEGIN -DEFAULT_LANGUAGE_ID=2 -RU_COUNT=1 -LANGUAGE_COUNT=2 -ENGLISH_ID1_EXISTS=1 -RU_PHRASE_COUNT=11142 -PHRASE_MAP_LANG2_COUNT=11194 -MANUAL_JOB_COUNT=0 -LANGUAGE_REBUILD_COUNT=0 -THREAD_COUNT=44 -POST_COUNT=44 -ADMIN_COUNT=1 -BOARD_ACTIVE=true -REGISTRATION_ENABLED=false -PHP_OUTPUT_END -VERIFY_OUTPUT_END -EXPECTED_PHRASE_MAP_LANG2_COUNT=11194 -ACTUAL_PHRASE_MAP_LANG2_COUNT=11194 -PROD_POST_JOB_STATE_OK=true -CURL_TRANSPORT_RC=0 -CURL_EXITCODE=0 -CURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -CURL_RC=0 -CURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_BODY_BYTES=77563 -CURL_BODY_SHA256=75c3f6fe94b0bb9a256453e1ee6c2ddeb25922081d49df3766f2b919ea440597 -CURL_META=200|77562|http://127.0.0.1/index.php -CURL_HAS_PVEPRO=true -CURL_HAS_RUSSIAN=true -CURL_OUTPUT_END -CURL_TRANSPORT_RC=0 -CURL_EXITCODE=0 -CURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -CURL_RC=0 -CURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_BODY_BYTES=77563 -CURL_BODY_SHA256=c0223dd51c6bf730b7fa8b9796fe550c87dd86331e09ab31b0ba83903deddd5c -CURL_META=200|77562|http://127.0.0.1/index.php -CURL_HAS_PVEPRO=true -CURL_HAS_RUSSIAN=true -CURL_OUTPUT_END -CURL_TRANSPORT_RC=0 -CURL_EXITCODE=0 -CURL_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -CURL_RC=0 -CURL_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CURL_BODY_BYTES=77563 -CURL_BODY_SHA256=75604368701d0f4e0d64de59972ce520d51eada71fa7f1128fd816cd44ba9b3c -CURL_META=200|77562|http://127.0.0.1/index.php -CURL_HAS_PVEPRO=true -CURL_HAS_RUSSIAN=true -CURL_OUTPUT_END -PROD_LOCAL_RENDER_SAMPLES=[{"sample":1,"meta":"200|77562|http://127.0.0.1/index.php","bytes":"77563","pvepro":"true","russian":"true","ok":true},{"sample":2,"meta":"200|77562|http://127.0.0.1/index.php","bytes":"77563","pvepro":"true","russian":"true","ok":true},{"sample":3,"meta":"200|77562|http://127.0.0.1/index.php","bytes":"77563","pvepro":"true","russian":"true","ok":true}] -PROD_LOCAL_RENDER_GOOD_SAMPLES=3 -PROD_LOCAL_RUSSIAN_RENDER_OK=true -PUBLIC_RUSSIAN_SAMPLES=[{"rc":0,"bytes":77564,"meta":"200|77564|https://pvepro.ru/index.php","pvepro":true,"russian":true,"sha256":"88298b0df6320f72c44ece92107db37a346846be560414c8750d4d001ddfbb9c","stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","ok":true,"sample":1},{"rc":0,"bytes":77564,"meta":"200|77564|https://pvepro.ru/index.php","pvepro":true,"russian":true,"sha256":"6c71d16e595e848b2a922a92152f1799d731704f159eb104e3bed4f7f5f2b4d7","stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","ok":true,"sample":2},{"rc":0,"bytes":77564,"meta":"200|77564|https://pvepro.ru/index.php","pvepro":true,"russian":true,"sha256":"64c95996b161f134cc827ba7026d145ae62140847c61bcddb09080704fe71f48","stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","ok":true,"sample":3},{"rc":0,"bytes":77564,"meta":"200|77564|https://pvepro.ru/index.php","pvepro":true,"russian":true,"sha256":"53560fc2a5614663d1c88f49a9d411dd13bb0630ce575c9f80669aefcd651deb","stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","ok":true,"sample":4},{"rc":0,"bytes":77564,"meta":"200|77564|https://pvepro.ru/index.php","pvepro":true,"russian":true,"sha256":"e07eda0b107e5b8e5054295587b63d2ededa5b5f512fc5336510677486045ac5","stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","ok":true,"sample":5}] -PUBLIC_RUSSIAN_GOOD_SAMPLES=5 -PUBLIC_RUSSIAN_STABLE=true -CLEANUP_TRANSPORT_RC=0 -CLEANUP_EXITCODE=0 -CLEANUP_TRANSPORT_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -CLEANUP_OUTPUT_BEGIN -XF_SHA=d0c10d91d743e0a541d9a1b201080491dae0a8b1757866f113ef707b83403219 -TEMP_FILES_REMOVED=true -CLEANUP_OUTPUT_END -PROD_SNAPSHOT_DELETE_RC=0 -STAGING_MUTATED=false -PRODUCTION_LANGUAGE_PROMOTED=true -DEFAULT_LANGUAGE_ID=2 -RUSSIAN_LANGUAGE_CODE=ru-RU -RUSSIAN_PHRASE_COUNT=11142 -RUSSIAN_PHRASE_MAP_COUNT=11194 -ENGLISH_FALLBACK_RETAINED=true -REGISTRATION_PUBLIC_LAUNCH=CLOSED -RUSSIAN_CORE_CHECKPOINT_COMPLETE=true -TASK_COMPLETE=true -TASK_RESULT=PASS_PVEPRO_RUSSIAN_PRODUCTION_PROMOTION -HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260920-PVEPRO-RUSSIAN-PRODUCTION-PROMOTION-737R3","status":"OK","changes_made":true,"rollback_started":false,"rollback_restored":null} +NEWFI207_BEGIN=true +MODE=read-only +IMMUTABLE_PLAN_CHECK=PASS +CHANGES_MADE=false +MUTATION_OUTCOME=NO_MUTATION +PIN_CHECK=PASS +ACCEPTED_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b +RELEASE_FILE_COUNT=6 +INTERESTING_FILE_COUNT=6 +FILE_1_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +FILE_1_BYTES=10566 +FILE_1_MODE=0o400 +FILE_1_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793 +FILE_1_KEYWORD_SCORE=13 +FILE_1_AST_DEF_COUNT=0 +FILE_1_AST_IMPORT_COUNT=0 +FILE_1_AST_STRING_COUNT=7 +FILE_1_STRING_1_LINE=4 +FILE_1_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1 +FILE_1_STRING_2_LINE=62 +FILE_1_STRING_2_VALUE=backup_target +FILE_1_STRING_3_LINE=62 +FILE_1_STRING_3_VALUE=ssh_remote +FILE_1_STRING_4_LINE=135 +FILE_1_STRING_4_VALUE=payload_sha256 +FILE_1_STRING_5_LINE=135 +FILE_1_STRING_5_VALUE=manifest_sha256 +FILE_1_STRING_6_LINE=135 +FILE_1_STRING_6_VALUE=replicas +FILE_1_STRING_7_LINE=132 +FILE_1_STRING_7_VALUE=homelab-scheduler-proof- +FILE_2_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +FILE_2_BYTES=13825 +FILE_2_MODE=0o400 +FILE_2_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d +FILE_2_KEYWORD_SCORE=9 +FILE_2_AST_DEF_COUNT=2 +FILE_2_DEF_1_LINE=35 +FILE_2_DEF_1_NAME=_remote_sha +FILE_2_DEF_2_LINE=117 +FILE_2_DEF_2_NAME=_execute_remote +FILE_2_AST_IMPORT_COUNT=0 +FILE_2_AST_STRING_COUNT=17 +FILE_2_STRING_1_LINE=79 +FILE_2_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2-plan-only +FILE_2_STRING_2_LINE=118 +FILE_2_STRING_2_VALUE=REMOTE_NODE +FILE_2_STRING_3_LINE=119 +FILE_2_STRING_3_VALUE=REMOTE_ARGV +FILE_2_STRING_4_LINE=120 +FILE_2_STRING_4_VALUE=REMOTE_ARGV_NODE +FILE_2_STRING_5_LINE=121 +FILE_2_STRING_5_VALUE=REMOTE_CAP_VALUE +FILE_2_STRING_6_LINE=124 +FILE_2_STRING_6_VALUE=REMOTE_WORKDIR +FILE_2_STRING_7_LINE=158 +FILE_2_STRING_7_VALUE=remote-bounded-ssh-cwd-root +FILE_2_STRING_8_LINE=198 +FILE_2_STRING_8_VALUE=/var/tmp/homelab-vzdump-v2- +FILE_2_STRING_9_LINE=149 +FILE_2_STRING_9_VALUE=REMOTE_TIMEOUT +FILE_2_STRING_10_LINE=151 +FILE_2_STRING_10_VALUE=REMOTE_RC +FILE_2_STRING_11_LINE=152 +FILE_2_STRING_11_VALUE=REMOTE_EMPTY +FILE_2_STRING_12_LINE=155 +FILE_2_STRING_12_VALUE=REMOTE_FILE_IDENTITY +FILE_2_STRING_13_LINE=162 +FILE_2_STRING_13_VALUE=remote-bounded-ssh-cwd-root +FILE_2_STRING_14_LINE=204 +FILE_2_STRING_14_VALUE=payload.bin +FILE_2_STRING_15_LINE=210 +FILE_2_STRING_15_VALUE=VZDUMP_PAYLOAD_BOUND +FILE_2_STRING_16_LINE=138 +FILE_2_STRING_16_VALUE=REMOTE_TIMEOUT +FILE_2_STRING_17_LINE=143 +FILE_2_STRING_17_VALUE=REMOTE_CAP +FILE_3_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py +FILE_3_BYTES=4627 +FILE_3_MODE=0o400 +FILE_3_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b +FILE_3_KEYWORD_SCORE=9 +FILE_3_AST_DEF_COUNT=1 +FILE_3_DEF_1_LINE=11 +FILE_3_DEF_1_NAME=_remote_sha +FILE_3_AST_IMPORT_COUNT=0 +FILE_3_AST_STRING_COUNT=3 +FILE_3_STRING_1_LINE=48 +FILE_3_STRING_1_VALUE=/var/tmp/homelab-vzdump-v2- +FILE_3_STRING_2_LINE=66 +FILE_3_STRING_2_VALUE=payload.bin +FILE_3_STRING_3_LINE=70 +FILE_3_STRING_3_VALUE=QEMU_PAYLOAD_MISSING +FILE_4_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +FILE_4_BYTES=4097 +FILE_4_MODE=0o400 +FILE_4_SHA256=a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96 +FILE_4_KEYWORD_SCORE=9 +FILE_4_AST_DEF_COUNT=0 +FILE_4_AST_IMPORT_COUNT=0 +FILE_4_AST_STRING_COUNT=9 +FILE_4_STRING_1_LINE=44 +FILE_4_STRING_1_VALUE=last_success_payload_sha256 +FILE_4_STRING_2_LINE=45 +FILE_4_STRING_2_VALUE=last_success_manifest_sha256 +FILE_4_STRING_3_LINE=45 +FILE_4_STRING_3_VALUE=last_success_replicas +FILE_4_STRING_4_LINE=37 +FILE_4_STRING_4_VALUE=payload_sha256 +FILE_4_STRING_5_LINE=37 +FILE_4_STRING_5_VALUE=last_success_payload_sha256 +FILE_4_STRING_6_LINE=38 +FILE_4_STRING_6_VALUE=manifest_sha256 +FILE_4_STRING_7_LINE=38 +FILE_4_STRING_7_VALUE=last_success_manifest_sha256 +FILE_4_STRING_8_LINE=38 +FILE_4_STRING_8_VALUE=replicas +FILE_4_STRING_9_LINE=38 +FILE_4_STRING_9_VALUE=last_success_replicas +FILE_5_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +FILE_5_BYTES=3449 +FILE_5_MODE=0o400 +FILE_5_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3 +FILE_5_KEYWORD_SCORE=7 +FILE_5_AST_DEF_COUNT=0 +FILE_5_AST_IMPORT_COUNT=0 +FILE_5_AST_STRING_COUNT=2 +FILE_5_STRING_1_LINE=4 +FILE_5_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411 +FILE_5_STRING_2_LINE=45 +FILE_5_STRING_2_VALUE=payload.bin +FILE_6_PATH=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +FILE_6_BYTES=2320 +FILE_6_MODE=0o400 +FILE_6_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011 +FILE_6_KEYWORD_SCORE=3 +FILE_6_AST_DEF_COUNT=0 +FILE_6_AST_IMPORT_COUNT=0 +FILE_6_AST_STRING_COUNT=1 +FILE_6_STRING_1_LINE=4 +FILE_6_STRING_1_VALUE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1 +CTX_1_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_1_START_LINE=15 +CTX_1_END_LINE=21 +CTX_1_L15=} +CTX_1_L16= +CTX_1_L17=def _sha(p): +CTX_1_L18= h=hashlib.sha256() +CTX_1_L19= with open(p,'rb',buffering=0) as f: +CTX_1_L20= while True: +CTX_1_L21= b=f.read(1<<20) +CTX_2_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_2_START_LINE=34 +CTX_2_END_LINE=40 +CTX_2_L34= +CTX_2_L35=class _GlobalsProxy: +CTX_2_L36= __slots__=('_g',) +CTX_2_L37= def __init__(self,g): object.__setattr__(self,'_g',g) +CTX_2_L38= def __getattr__(self,n): +CTX_2_L39= try: return self._g[n] +CTX_2_L40= except KeyError as e: raise AttributeError(n) from e +CTX_3_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_3_START_LINE=59 +CTX_3_END_LINE=72 +CTX_3_L59= if len(found)!=1: +CTX_3_L60= raise RuntimeError('LEGACY_PROVENANCE_CARDINALITY') +CTX_3_L61= g=next(iter(found.values())) +CTX_3_L62= required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote', +CTX_3_L63= '_default_unprivileged_lxc','mapped_scratch_probe','_stream_argv_to_local','run', +CTX_3_L64= 'choose_due_target','write_state','epoch') +CTX_3_L65= if any(not callable(g.get(n)) for n in required): +CTX_3_L66= raise RuntimeError('LEGACY_PROVENANCE_API') +CTX_3_L67= original=g['capture_pve_guest'] +CTX_3_L68= proxy=_GlobalsProxy(g) +CTX_3_L69= if not isinstance(g.get('SCP'),str) or not g['SCP'].startswith('/'): +CTX_3_L70= raise RuntimeError('LEGACY_SCP_API') +CTX_3_L71= qemu_patched=qemu_adapter.bind(proxy,original) +CTX_3_L72= if not callable(qemu_patched): +CTX_4_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_4_START_LINE=75 +CTX_4_END_LINE=82 +CTX_4_L75= if not callable(patched): +CTX_4_L76= raise RuntimeError('LXC_ADAPTER_BIND_RESULT') +CTX_4_L77= g['capture_pve_guest']=patched +CTX_4_L78= scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state']) +CTX_4_L79= if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']: +CTX_4_L80= raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT') +CTX_4_L81= return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired} +CTX_4_L82= +CTX_5_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_5_START_LINE=96 +CTX_5_END_LINE=117 +CTX_5_L96= wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE) +CTX_5_L97= return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired +CTX_5_L98= +CTX_5_L99=def _target(wrapper,lid): +CTX_5_L100= rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid] +CTX_5_L101= if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY') +CTX_5_L102= return hits[0] +CTX_5_L103= +CTX_5_L104=def selftest(): +CTX_5_L105= wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load() +CTX_5_L106= if wired['legacy_globals'].get('capture_pve_guest') is not wired['patched_capture']: +CTX_5_L107= raise RuntimeError('PATCH_BINDING') +CTX_5_L108= if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']: +CTX_5_L109= raise RuntimeError('SCHEDULER_CHOOSE_BINDING') +CTX_5_L110= if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']: +CTX_5_L111= raise RuntimeError('SCHEDULER_WRITE_BINDING') +CTX_5_L112= if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]: +CTX_5_L113= raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT') +CTX_5_L114= if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets): +CTX_5_L115= raise RuntimeError('WRAPPER_PUBLIC_API') +CTX_5_L116= print('SELFTEST_OVERLAY504=PASS',flush=True) +CTX_5_L117= return 0 +CTX_6_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/entry504.py +CTX_6_START_LINE=125 +CTX_6_END_LINE=187 +CTX_6_L125= if argv==['scheduler-proof']: +CTX_6_L126= import tempfile +CTX_6_L127= legacy=wired['legacy']; g=wired['legacy_globals'] +CTX_6_L128= old_root=g.get('STATE_ROOT'); old_epoch=g.get('epoch') +CTX_6_L129= if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE') +CTX_6_L130= now=[1000] +CTX_6_L131= try: +CTX_6_L132= with tempfile.TemporaryDirectory(prefix='homelab-scheduler-proof-',dir='/run') as td: +CTX_6_L133= g['STATE_ROOT']=pathlib.Path(td); (g['STATE_ROOT']/'state').mkdir(mode=0o700) +CTX_6_L134= g['epoch']=lambda: now[0] +CTX_6_L135= common={'payload_sha256':'a'*64,'manifest_sha256':'b'*64,'replicas':['proof-r1','proof-r2']} +CTX_6_L136= legacy.write_state('proof-a','SUCCESS',generation='proof-a-good',**common) +CTX_6_L137= legacy.write_state('proof-b','SUCCESS',generation='proof-b-good',**common) +CTX_6_L138= now[0]=100000 +CTX_6_L139= legacy.write_state('proof-a','FAIL',generation='proof-a-bad',reason='PROOF_FAILURE',sealed=False) +CTX_6_L140= state=legacy.load_state_all(); a=state['proof-a'] +CTX_6_L141= targets=[{'logical_id':'proof-a','enabled':True,'due_seconds':100},{'logical_id':'proof-b','enabled':True,'due_seconds':100}] +CTX_6_L142= first=legacy.choose_due_target(targets,state,now[0]) +CTX_6_L143= if not isinstance(first,dict) or first.get('logical_id')!='proof-b': raise RuntimeError('SCHEDULER_PROOF_PEER_NOT_SELECTED') +CTX_6_L144= retry=int(a.get('retry_after_epoch',0)); preserved=int(a.get('last_success_epoch',0)) +CTX_6_L145= if preserved!=1000 or a.get('last_success_generation')!='proof-a-good' or int(a.get('consecutive_failures',0))!=1 or retry!=101800: +CTX_6_L146= raise RuntimeError('SCHEDULER_PROOF_FAILURE_STATE') +CTX_6_L147= now[0]=retry+1 +CTX_6_L148= second=legacy.choose_due_target(targets,legacy.load_state_all(),now[0]) +CTX_6_L149= if not isinstance(second,dict) or second.get('logical_id')!='proof-a': raise RuntimeError('SCHEDULER_PROOF_RETRY_NOT_REELIGIBLE') +CTX_6_L150= legacy.write_state('proof-a','SUCCESS',generation='proof-a-recovered',**common) +CTX_6_L151= recovered=legacy.load_state_all()['proof-a'] +CTX_6_L152= if int(recovered.get('consecutive_failures',-1))!=0 or int(recovered.get('retry_after_epoch',-1))!=0: +CTX_6_L153= raise RuntimeError('SCHEDULER_PROOF_SUCCESS_RESET') +CTX_6_L154= 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} +CTX_6_L155= print('SCHEDULER_FAILURE_ISOLATION_PROOF='+json.dumps(proof,separators=(',',':'),sort_keys=True),flush=True) +CTX_6_L156= return 0 +CTX_6_L157= finally: +CTX_6_L158= g['STATE_ROOT']=old_root; g['epoch']=old_epoch +CTX_6_L159= if argv==['scheduler-select-live']: +CTX_6_L160= state=legacy.load_state_all(); targets=wrapper.load_targets() +CTX_6_L161= chosen=legacy.choose_due_target(targets,state) +CTX_6_L162= if chosen is None: +CTX_6_L163= print('SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET',flush=True) +CTX_6_L164= else: +CTX_6_L165= 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) +CTX_6_L166= return 0 +CTX_6_L167= if len(argv)==2 and argv[0]=='plan-lxc': +CTX_6_L168= t=_target(wrapper,argv[1]) +CTX_6_L169= if t.get('guest_type')!='lxc' or t.get('logical_id')=='guest-pve01-lxc-112': +CTX_6_L170= raise RuntimeError('PLAN_TARGET_NOT_LEGACY_LXC') +CTX_6_L171= out=lxc_adapter.plan_only(legacy,t) +CTX_6_L172= 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) +CTX_6_L173= return 0 +CTX_6_L174= if len(argv)==2 and argv[0]=='verify-target': +CTX_6_L175= t=_target(wrapper,argv[1]) +CTX_6_L176= if t.get('logical_id')=='guest-pve01-lxc-112': +CTX_6_L177= raise RuntimeError('VERIFY_SYNTHETIC_CT112_FORBIDDEN') +CTX_6_L178= try: +CTX_6_L179= out=wrapper.backup_target(t,True) +CTX_6_L180= except legacy.BackupError as e: +CTX_6_L181= print('VERIFY_TARGET_RESULT=FAIL',flush=True) +CTX_6_L182= print('VERIFY_TARGET_REASON='+str(e.code),flush=True) +CTX_6_L183= return 2 +CTX_6_L184= print('VERIFY_TARGET_RESULT='+json.dumps(out,separators=(',',':'),sort_keys=True),flush=True) +CTX_6_L185= return 0 +CTX_6_L186= return wrapper.main([sys.argv[0],*argv]) +CTX_6_L187= +CTX_7_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_7_START_LINE=20 +CTX_7_END_LINE=26 +CTX_7_L20= except Exception as e: raise AdapterError(code) from e +CTX_7_L21= +CTX_7_L22=def _sha_file(p): +CTX_7_L23= h=hashlib.sha256() +CTX_7_L24= with open(p,'rb',buffering=0) as f: +CTX_7_L25= for b in iter(lambda:f.read(1<<20),b''): h.update(b) +CTX_7_L26= return h.hexdigest() +CTX_8_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_8_START_LINE=32 +CTX_8_END_LINE=62 +CTX_8_L32= if n<=0: raise AdapterError('WRITE_FAILED') +CTX_8_L33= view=view[n:] +CTX_8_L34= +CTX_8_L35=def _remote_sha(legacy,node,path): +CTX_8_L36= p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30) +CTX_8_L37= parts=p.stdout.decode('ascii','strict').strip().split() +CTX_8_L38= _need(len(parts)>=2 and parts[1]==path,'TOOL_SHA_OUTPUT') +CTX_8_L39= return parts[0] +CTX_8_L40= +CTX_8_L41=def _live_inputs(legacy,node,vmid,scratch): +CTX_8_L42= _need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY') +CTX_8_L43= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY') +CTX_8_L44= rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON') +CTX_8_L45= stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON') +CTX_8_L46= _need(type(rows) is list and type(stores) is list,'PVE_LIST_SCHEMA') +CTX_8_L47= configs=[] +CTX_8_L48= for r in rows: +CTX_8_L49= if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue +CTX_8_L50= try: rid=int(r.get('vmid')) +CTX_8_L51= except Exception: raise AdapterError('RESOURCE_VMID') +CTX_8_L52= cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r["type"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON') +CTX_8_L53= _need(type(cfg) is dict,'CONFIG_SCHEMA') +CTX_8_L54= configs.append([rid,cfg]) +CTX_8_L55= tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON') +CTX_8_L56= _need(type(tasks) is list and len(tasks)<1000,'TASKS_SCHEMA') +CTX_8_L57= q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False) +CTX_8_L58= defaults=None +CTX_8_L59= if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout +CTX_8_L60= elif q.returncode!=1: raise AdapterError('DEFAULTS_PROBE') +CTX_8_L61= st=os.statvfs('/mnt/staging'); free=int(st.f_bavail*st.f_frsize) +CTX_8_L62= return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs, +CTX_9_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_9_START_LINE=85 +CTX_9_END_LINE=91 +CTX_9_L85= a=_helper(_live_inputs(legacy,node,vmid,scratch)); b=_helper(_live_inputs(legacy,node,vmid,scratch)) +CTX_9_L86= _need(_stable_job(a['job'])==_stable_job(b['job']),'FRESH_PLAN_UNSTABLE') +CTX_9_L87= _need(a['argv']==b['argv'],'FRESH_ARGV_UNSTABLE') +CTX_9_L88= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_POST') +CTX_9_L89= return b +CTX_9_L90= +CTX_9_L91=def _execute_local(legacy,node,argv,dest,cap,timeout): +CTX_10_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_10_START_LINE=94 +CTX_10_END_LINE=109 +CTX_10_L94= data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode() +CTX_10_L95= p=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV) +CTX_10_L96= if p.stderr or not p.stdout or len(p.stdout)>262144: +CTX_10_L97= raise ExecFailure('LOCAL_HELPER_PROTOCOL',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)}) +CTX_10_L98= try: out=json.loads(p.stdout) +CTX_10_L99= except Exception: +CTX_10_L100= raise ExecFailure('LOCAL_HELPER_JSON',{'executor':'local-proven-pve270','producer_rc':None,'stderr_stream_sha256':hashlib.sha256(p.stderr).hexdigest(),'stderr_bytes_observed':len(p.stderr)}) +CTX_10_L101= summary={'executor':'local-proven-pve270','helper_rc':p.returncode,'exception_class':out.get('exception_class'),'exception_message_sha256':out.get('exception_message_sha256')} +CTX_10_L102= if isinstance(out.get('process'),dict): summary.update(out['process']) +CTX_10_L103= if p.returncode!=0 or out.get('status')!='OK': raise ExecFailure('LOCAL_PRODUCER_FAILED',summary) +CTX_10_L104= result=out.get('result'); _need(type(result) is dict,'LOCAL_RESULT_SCHEMA') +CTX_10_L105= _need(pathlib.Path(dest).is_file() and pathlib.Path(dest).stat().st_size==int(result.get('size',-1)),'LOCAL_RESULT_FILE') +CTX_10_L106= return summary|{'size':result['size'],'sha256':result['sha256'],'producer_rc':result.get('producer_rc')} +CTX_10_L107= +CTX_10_L108=def _kill(p): +CTX_10_L109= try: os.killpg(p.pid,signal.SIGTERM) +CTX_11_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_11_START_LINE=114 +CTX_11_END_LINE=166 +CTX_11_L114= except ProcessLookupError: pass +CTX_11_L115= p.wait() +CTX_11_L116= +CTX_11_L117=def _execute_remote(legacy,node,argv,dest,cap,timeout): +CTX_11_L118= _need(re.fullmatch(r'pve0[123]',str(node)) is not None and node!='pve01','REMOTE_NODE') +CTX_11_L119= _need(type(argv) is list and argv and argv[0]=='/usr/bin/vzdump' and all(type(x) is str and '\x00' not in x for x in argv),'REMOTE_ARGV') +CTX_11_L120= _need('--node' in argv and argv[argv.index('--node')+1]==node,'REMOTE_ARGV_NODE') +CTX_11_L121= _need(type(cap) is int and 0=deadline: raise ExecFailure('REMOTE_TIMEOUT',{}) +CTX_11_L139= for key,_ in sel.select(min(.2,max(0,deadline-now))): +CTX_11_L140= b=os.read(key.fileobj.fileno(),65536) +CTX_11_L141= if not b: sel.unregister(key.fileobj); continue +CTX_11_L142= if key.fileobj is p.stdout: +CTX_11_L143= if total+len(b)>cap: raise ExecFailure('REMOTE_CAP',{}) +CTX_11_L144= _write_all(fd,b); digest.update(b); total+=len(b) +CTX_11_L145= else: +CTX_11_L146= err_total+=len(b); eh.update(b); keep=b[:max(0,MAX_STDERR-err_kept)] +CTX_11_L147= if keep: _write_all(efd,keep); err_kept+=len(keep) +CTX_11_L148= left=deadline-time.monotonic() +CTX_11_L149= if left<=0: raise ExecFailure('REMOTE_TIMEOUT',{}) +CTX_11_L150= rc=p.wait(timeout=left) +CTX_11_L151= if rc!=0: raise ExecFailure('REMOTE_RC',{}) +CTX_11_L152= if total<=0: raise ExecFailure('REMOTE_EMPTY',{}) +CTX_11_L153= stf=os.fstat(fd); named=os.stat(dest,follow_symlinks=False) +CTX_11_L154= if (stf.st_dev,stf.st_ino)!=(initial.st_dev,initial.st_ino) or (named.st_dev,named.st_ino)!=(initial.st_dev,initial.st_ino) or stf.st_nlink!=1 or stf.st_size!=total: +CTX_11_L155= raise ExecFailure('REMOTE_FILE_IDENTITY',{}) +CTX_11_L156= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_EXEC_POST') +CTX_11_L157= os.fchmod(fd,0o400); os.fsync(fd); os.fsync(efd); good=True +CTX_11_L158= return {'executor':'remote-bounded-ssh-cwd-root','producer_rc':rc,'size':total,'sha256':digest.hexdigest(), +CTX_11_L159= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()} +CTX_11_L160= except ExecFailure as e: +CTX_11_L161= if p is not None and p.poll() is None: _kill(p) +CTX_11_L162= summary={'executor':'remote-bounded-ssh-cwd-root','producer_rc':None if p is None else p.returncode,'archive_bytes':total, +CTX_11_L163= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()} +CTX_11_L164= summary.update(e.summary); raise ExecFailure(e.code,summary) +CTX_11_L165= finally: +CTX_11_L166= if p is not None: +CTX_12_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_12_START_LINE=171 +CTX_12_END_LINE=178 +CTX_12_L171= try: os.fsync(fd); os.fsync(efd) +CTX_12_L172= except OSError: pass +CTX_12_L173= os.close(fd); os.close(efd) +CTX_12_L174= summary={'process_started':p is not None,'producer_rc':None if p is None else p.returncode,'capture_success':good,'archive_bytes':total, +CTX_12_L175= 'stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest(),'raw_stderr_exported':False,'cwd':'/'} +CTX_12_L176= try: +CTX_12_L177= mb=(json.dumps(summary,separators=(',',':'),sort_keys=True)+'\n').encode() +CTX_12_L178= mfd=os.open(metap,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) +CTX_13_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_13_START_LINE=182 +CTX_13_END_LINE=188 +CTX_13_L182= +CTX_13_L183=def _emit_diag(node,summary): +CTX_13_L184= safe={'node':node} +CTX_13_L185= for k in ('executor','failure_code','helper_rc','producer_rc','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','exception_class','exception_message_sha256'): +CTX_13_L186= if k in summary: safe[k]=summary[k] +CTX_13_L187= print('LXC_EXECUTION_DIAG='+json.dumps(safe,separators=(',',':'),sort_keys=True),flush=True) +CTX_13_L188= +CTX_14_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/lxc_adapter.py +CTX_14_START_LINE=196 +CTX_14_END_LINE=218 +CTX_14_L196= _need(typ==t.get('guest_type')=='lxc','PVE_GUEST_TYPE_DRIFT') +CTX_14_L197= legacy._default_unprivileged_lxc(node,vmid) +CTX_14_L198= scratch=f'/var/tmp/homelab-vzdump-v2-{gen}' +CTX_14_L199= legacy.ssh_remote(node,['install','-d','-m','710','-o','0','-g','100000',scratch],timeout=30) +CTX_14_L200= q=legacy.ssh_remote(node,['stat','-c','%a:%u:%g',scratch],timeout=30) +CTX_14_L201= _need(q.stdout.decode().strip()=='710:0:100000','PVE_MAPPED_SCRATCH_ACCESS_CONTRACT') +CTX_14_L202= try: +CTX_14_L203= legacy.mapped_scratch_probe(node,scratch) +CTX_14_L204= p=plan_only(legacy,t,scratch); local=pathlib.Path(work)/'payload.bin'; cap=int(p['job']['archive_cap_bytes']) +CTX_14_L205= try: +CTX_14_L206= result=_execute_local(legacy,node,p['argv'],local,cap,7200) if node=='pve01' else _execute_remote(legacy,node,p['argv'],local,cap,7200) +CTX_14_L207= except ExecFailure as e: +CTX_14_L208= _emit_diag(node,e.summary|{'failure_code':e.code}) +CTX_14_L209= raise legacy.BackupError('LXC_PRODUCER_FAILED') from None +CTX_14_L210= _need(local.is_file() and 0=2 and parts[1]==path,'QEMU_TOOL_SHA_OUTPUT') +CTX_15_L15= return parts[0] +CTX_15_L16= +CTX_15_L17=def _select_qemu_outputs(vmid,files): +CTX_15_L18= _need(type(vmid) is int and vmid>0,'QEMU_VMID') +CTX_15_L19= _need(type(files) is list and files and all(type(x) is str and x.startswith('/') and '\x00' not in x for x in files),'QEMU_OUTPUT_LIST') +CTX_15_L20= _need(len(files)==len(set(files)),'QEMU_OUTPUT_DUPLICATE') +CTX_15_L21= 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$') +CTX_15_L22= archives=[] +CTX_15_L23= for f in files: +CTX_15_L24= name=pathlib.PurePosixPath(f).name +CTX_15_L25= m=pat.fullmatch(name) +CTX_15_L26= if m: archives.append((f,m.group(1))) +CTX_15_L27= _need(len(archives)==1,'QEMU_ARCHIVE_NOT_UNIQUE') +CTX_15_L28= archive,stamp=archives[0]; parent=pathlib.PurePosixPath(archive).parent +CTX_15_L29= expected_log=parent/f'vzdump-qemu-{vmid}-{stamp}.log' +CTX_15_L30= allowed={archive}; log=None +CTX_15_L31= if str(expected_log) in files: +CTX_15_L32= log=str(expected_log); allowed.add(log) +CTX_15_L33= _need(set(files)==allowed,'QEMU_OUTPUT_UNEXPECTED_FILE') +CTX_15_L34= return archive,log +CTX_15_L35= +CTX_15_L36=def _emit_diag(**kw): +CTX_15_L37= print('QEMU_EXECUTION_DIAG='+json.dumps(kw,separators=(',',':'),sort_keys=True),flush=True) +CTX_16_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/qemu_adapter.py +CTX_16_START_LINE=44 +CTX_16_END_LINE=78 +CTX_16_L44= _need(len(rows)==1,'PVE_GUEST_NOT_UNIQUE') +CTX_16_L45= row=rows[0]; node=row.get('node'); typ=row.get('type') +CTX_16_L46= _need(typ==t.get('guest_type')=='qemu','PVE_GUEST_TYPE_DRIFT') +CTX_16_L47= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE') +CTX_16_L48= srcdir=f'/var/tmp/homelab-vzdump-v2-{gen}' +CTX_16_L49= legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30) +CTX_16_L50= try: +CTX_16_L51= vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False) +CTX_16_L52= if vp.returncode!=0: +CTX_16_L53= _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) +CTX_16_L54= raise legacy.BackupError('QEMU_VZDUMP_FAILED') +CTX_16_L55= _need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST') +CTX_16_L56= p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\n'],timeout=30) +CTX_16_L57= files=[x for x in p.stdout.decode('utf-8','strict').splitlines() if x] +CTX_16_L58= try: src,log=_select_qemu_outputs(vmid,files) +CTX_16_L59= except QemuAdapterError as e: +CTX_16_L60= _emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e)) +CTX_16_L61= raise legacy.BackupError(str(e)) from None +CTX_16_L62= q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30) +CTX_16_L63= raw=q.stdout.decode('ascii','strict').strip() +CTX_16_L64= _need(raw.isdigit() and int(raw)>0,'QEMU_ARCHIVE_STAT') +CTX_16_L65= size=int(raw) +CTX_16_L66= local=pathlib.Path(work)/'payload.bin' +CTX_16_L67= if node=='pve01': local=pathlib.Path(src) +CTX_16_L68= else: +CTX_16_L69= legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200) +CTX_16_L70= _need(pathlib.Path(local).is_file() and pathlib.Path(local).stat().st_size==size,'QEMU_PAYLOAD_MISSING') +CTX_16_L71= _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) +CTX_16_L72= except Exception: +CTX_16_L73= legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise +CTX_16_L74= cleanup={'kind':'pve_source_dir','node':node,'path':srcdir} +CTX_16_L75= meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'), +CTX_16_L76= 'producer_contract':'strict-qemu-vma-zst-plus-matching-log-overlay503'} +CTX_16_L77= return pathlib.Path(local),meta,cleanup +CTX_16_L78= capture_pve_guest.__name__='capture_pve_guest' +CTX_17_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_17_START_LINE=20 +CTX_17_END_LINE=28 +CTX_17_L20= n=max(1,_as_nonneg_int(consecutive_failures,1)) +CTX_17_L21= return min(MAX_BACKOFF,MIN_BACKOFF*(2**min(n-1,4))) +CTX_17_L22= +CTX_17_L23=def _read_prior(legacy,logical_id): +CTX_17_L24= root=pathlib.Path(legacy.STATE_ROOT)/'state' +CTX_17_L25= p=root/(str(logical_id)+'.json') +CTX_17_L26= try: +CTX_17_L27= if not p.is_file(): return {} +CTX_17_L28= d=json.loads(p.read_text(encoding='utf-8')) +CTX_18_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_18_START_LINE=34 +CTX_18_END_LINE=48 +CTX_18_L34= if not isinstance(prior,dict): return {} +CTX_18_L35= if prior.get('result')=='SUCCESS': +CTX_18_L36= out={'last_success_epoch':_as_nonneg_int(prior.get('last_success_epoch'),0)} +CTX_18_L37= mapping=(('generation','last_success_generation'),('payload_sha256','last_success_payload_sha256'), +CTX_18_L38= ('manifest_sha256','last_success_manifest_sha256'),('replicas','last_success_replicas'), +CTX_18_L39= ('green_verified','last_success_green_verified')) +CTX_18_L40= for src,dst in mapping: +CTX_18_L41= if src in prior: out[dst]=prior[src] +CTX_18_L42= return out +CTX_18_L43= out={} +CTX_18_L44= for k in ('last_success_epoch','last_success_generation','last_success_payload_sha256', +CTX_18_L45= 'last_success_manifest_sha256','last_success_replicas','last_success_green_verified'): +CTX_18_L46= if k in prior: out[k]=prior[k] +CTX_18_L47= return out +CTX_18_L48= +CTX_19_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_19_START_LINE=50 +CTX_19_END_LINE=65 +CTX_19_L50= _need(callable(original_choose),'ORIGINAL_CHOOSE_REQUIRED') +CTX_19_L51= _need(callable(original_write),'ORIGINAL_WRITE_REQUIRED') +CTX_19_L52= _need(callable(getattr(legacy,'epoch',None)),'LEGACY_EPOCH_REQUIRED') +CTX_19_L53= _need(hasattr(legacy,'STATE_ROOT'),'LEGACY_STATE_ROOT_REQUIRED') +CTX_19_L54= +CTX_19_L55= def choose_due_target(targets,state,now=None): +CTX_19_L56= now=_as_nonneg_int(legacy.epoch() if now is None else now,0) +CTX_19_L57= _need(isinstance(targets,list) and isinstance(state,dict),'SCHEDULER_INPUT_SCHEMA') +CTX_19_L58= due=[] +CTX_19_L59= for order,t in enumerate(targets): +CTX_19_L60= if not isinstance(t,dict) or t.get('enabled') is not True: continue +CTX_19_L61= lid=t.get('logical_id'); seconds=_as_nonneg_int(t.get('due_seconds'),0) +CTX_19_L62= _need(isinstance(lid,str) and lid and seconds>0,'SCHEDULER_TARGET_SCHEMA') +CTX_19_L63= s=state.get(lid,{}) +CTX_19_L64= if not isinstance(s,dict): s={} +CTX_19_L65= retry_after=_as_nonneg_int(s.get('retry_after_epoch'),0) +CTX_20_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/scheduler_adapter.py +CTX_20_START_LINE=72 +CTX_20_END_LINE=93 +CTX_20_L72= if not due: return None +CTX_20_L73= return max(due,key=lambda x:(x[0],x[1]))[2] +CTX_20_L74= +CTX_20_L75= def write_state(logical_id,result,**kw): +CTX_20_L76= now=_as_nonneg_int(legacy.epoch(),0) +CTX_20_L77= prior=_read_prior(legacy,logical_id) +CTX_20_L78= if result=='SUCCESS': +CTX_20_L79= clean=dict(kw) +CTX_20_L80= clean.update({'last_attempt_epoch':now,'consecutive_failures':0,'retry_after_epoch':0,'failure_backoff_seconds':0}) +CTX_20_L81= return original_write(logical_id,result,**clean) +CTX_20_L82= failures=_as_nonneg_int(prior.get('consecutive_failures'),0)+1 +CTX_20_L83= backoff=backoff_seconds(failures) +CTX_20_L84= clean=dict(kw) +CTX_20_L85= clean.update(_success_snapshot(prior)) +CTX_20_L86= clean.update({'last_attempt_epoch':now,'consecutive_failures':failures, +CTX_20_L87= 'retry_after_epoch':now+backoff,'failure_backoff_seconds':backoff}) +CTX_20_L88= return original_write(logical_id,result,**clean) +CTX_20_L89= +CTX_20_L90= legacy.choose_due_target=choose_due_target +CTX_20_L91= legacy.write_state=write_state +CTX_20_L92= return {'choose_due_target':choose_due_target,'write_state':write_state, +CTX_20_L93= 'original_choose':original_choose,'original_write':original_write} +CTX_21_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_21_START_LINE=7 +CTX_21_END_LINE=13 +CTX_21_L7=MAX_INPUT=262144 +CTX_21_L8= +CTX_21_L9=def sha_file(p:pathlib.Path)->str: +CTX_21_L10= h=hashlib.sha256() +CTX_21_L11= with open(p,'rb',buffering=0) as f: +CTX_21_L12= for b in iter(lambda:f.read(1<<20),b''): h.update(b) +CTX_21_L13= return h.hexdigest() +CTX_22_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_22_START_LINE=20 +CTX_22_END_LINE=33 +CTX_22_L20= if not p.is_file() or p.is_symlink(): return None +CTX_22_L21= try: d=json.loads(p.read_bytes()) +CTX_22_L22= except Exception: return {'summary_read':'FAILED'} +CTX_22_L23= keys=('process_started','producer_rc','capture_success','archive_bytes','stderr_bytes_observed','stderr_bytes_retained','stderr_truncated','stderr_stream_sha256','raw_stderr_exported','child_umask') +CTX_22_L24= return {k:d.get(k) for k in keys if k in d} +CTX_22_L25= +CTX_22_L26=def selftest()->int: +CTX_22_L27= if sha_file(VZDUMP)!=VZDUMP_SHA: fail('VZDUMP_IDENTITY') +CTX_22_L28= sys.path.insert(0,str(BASE)) +CTX_22_L29= import adapter +CTX_22_L30= adapter.verify_sources(); adapter.load_graph() +CTX_22_L31= print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True) +CTX_22_L32= return 0 +CTX_22_L33= +CTX_23_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/producer_exec_helper.py +CTX_23_START_LINE=42 +CTX_23_END_LINE=66 +CTX_23_L42= argv=x['argv']; dest=pathlib.Path(x['dest']); cap=x['cap']; seconds=x['seconds'] +CTX_23_L43= 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') +CTX_23_L44= if argv[0]!='/usr/bin/vzdump': fail('VZDUMP_PATH') +CTX_23_L45= if not (dest.is_absolute() and dest.name=='payload.bin' and '..' not in dest.parts): fail('DEST') +CTX_23_L46= if not (type(cap) is int and 0str: +CTX_25_L9= return hashlib.sha256(p.read_bytes()).hexdigest() +CTX_25_L10= +CTX_25_L11=def fail(code:str): +CTX_25_L12= raise RuntimeError(code) +CTX_26_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +CTX_26_START_LINE=17 +CTX_26_END_LINE=23 +CTX_26_L17= if not p.is_file() or p.is_symlink() or sha(p)!=PVE265_SHA: fail('PVE265_IDENTITY') +CTX_26_L18= sys.path.insert(0,str(C411)) +CTX_26_L19= import adapter +CTX_26_L20= adapter.verify_sources() +CTX_26_L21= guest266,pve265,_pve270,_pve282=adapter.load_graph() +CTX_26_L22= data=sys.stdin.buffer.read(4_000_001) +CTX_26_L23= if not data or len(data)>4_000_000: fail('INPUT_BOUND') +CTX_27_FILE=/opt/homelab-backup-v2/releases/backup-v2-overlay-504r1-ca6876fa9c3b/fresh_lxc_helper.py +CTX_27_START_LINE=36 +CTX_27_END_LINE=42 +CTX_27_L36= if job.get('configured_full_cycle_fits') is not True or job.get('compression_dependent') is not False: fail('JOB_CAPACITY_POLICY') +CTX_27_L37= guest266.no_active_tasks(raw.get('tasks'),vmid) +CTX_27_L38= argv=pve265.dump_argv(job,'/usr/bin/vzdump',scratch,now) +CTX_27_L39= 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') +CTX_27_L40= out={'schema':1,'argv':argv,'job':{k:job.get(k) for k in keep}} +CTX_27_L41= sys.stdout.write(json.dumps(out,separators=(',',':'),sort_keys=True)+'\n') +CTX_27_L42= return 0 +USA_STATE_FULL_SAFE_BEGIN=true +USA_STATE_FIELD=$.consecutive_failures=0 +USA_STATE_FIELD=$.failure_backoff_seconds=0 +USA_STATE_FIELD=$.generation=v2-md-relay-20260919T070058Z-0e409ea129e2 +USA_STATE_FIELD=$.green_verified=False +USA_STATE_FIELD=$.last_attempt_epoch=1789801278 +USA_STATE_FIELD=$.last_success_epoch=1789801278 +USA_STATE_FIELD=$.logical_id=md-relay +USA_STATE_FIELD=$.manifest_sha256=6887c5423640738aeb2bc1d104d515df1d1a21e2cd2d3291481475aa81cb6838 +USA_STATE_FIELD=$.payload_sha256=187401a5fbf6c29b4dfd77e5d272db77951aa45003d0d80e0be834235571f32f +USA_STATE_FIELD=$.replicas[0].crypt=pve03-mail-04-crypt +USA_STATE_FIELD=$.replicas[0].physical=pve03-mail-04 +USA_STATE_FIELD=$.replicas[1].crypt=pve03-mail-01-crypt +USA_STATE_FIELD=$.replicas[1].physical=pve03-mail-01 +USA_STATE_FIELD=$.result=SUCCESS +USA_STATE_FIELD=$.retry_after_epoch=0 +USA_STATE_FIELD=$.schema=1 +USA_STATE_FIELD=$.updated_at_utc=2026-09-19T07:01:18Z +USA_STATE_FULL_SAFE_END=true +MOLDOVA_STATE_FULL_SAFE_BEGIN=true +MOLDOVA_STATE_FIELD=$.consecutive_failures=6 +MOLDOVA_STATE_FIELD=$.failure_backoff_seconds=21600 +MOLDOVA_STATE_FIELD=$.generation=v2-us-netbird-20260920T000652Z-7ecdcfcafc12 +MOLDOVA_STATE_FIELD=$.last_attempt_epoch=1789862827 +MOLDOVA_STATE_FIELD=$.last_success_epoch=1789704670 +MOLDOVA_STATE_FIELD=$.last_success_generation=v2-us-netbird-20260918T041032Z-d7648be4c16b +MOLDOVA_STATE_FIELD=$.last_success_green_verified=False +MOLDOVA_STATE_FIELD=$.last_success_manifest_sha256=f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5 +MOLDOVA_STATE_FIELD=$.last_success_payload_sha256=e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf +MOLDOVA_STATE_FIELD=$.last_success_replicas[0].crypt=pve01-mail-05-crypt +MOLDOVA_STATE_FIELD=$.last_success_replicas[0].physical=pve01-mail-05 +MOLDOVA_STATE_FIELD=$.last_success_replicas[1].crypt=pve03-mail-04-crypt +MOLDOVA_STATE_FIELD=$.last_success_replicas[1].physical=pve03-mail-04 +MOLDOVA_STATE_FIELD=$.logical_id=us-netbird +MOLDOVA_STATE_FIELD=$.reason=PIPE_FAILED +MOLDOVA_STATE_FIELD=$.result=FAIL +MOLDOVA_STATE_FIELD=$.retry_after_epoch=1789884427 +MOLDOVA_STATE_FIELD=$.schema=1 +MOLDOVA_STATE_FIELD=$.sealed=False +MOLDOVA_STATE_FIELD=$.updated_at_utc=2026-09-20T00:07:07Z +MOLDOVA_STATE_FULL_SAFE_END=true +HAS_RCLONE_SOURCE=false +HAS_GENERATION_MANIFEST_PAYLOAD_SOURCE=true +HAS_REMOTE_REPLICA_SOURCE=true +DECISION=HOLD_BACKUP207_PRODUCER_CONTRACT_INCOMPLETE +NEXT_GATE=READ_ONLY_TARGETED_MODULE_FOLLOWUP +CLOUD_READS=0 +CLOUD_WRITES=0 +VPS_SSH_ATTEMPTS=0 +MESSENGERS214_CLOSED=false +MAJOR_STAGES_REMAINING=8 +NEWFI207_END=true OUTPUT_END CHAT_OUTPUT_END