CHAT_OUTPUT_BEGIN
COMMAND_ID=SUPPORT-260918-INFRA-PVE1-MOLDOVA-OVERLAY504-TRANSPORT-READONLY-557R3
STATUS=OK
RC=0
HOST=pve01
MODE=read-only
COMPONENT=infra-pve1-moldova-overlay504-transport-readonly
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0
COMMAND_SHA256=7f9a19052a0b35d999a1d13fd46c335e82b069a6b5a3f06d5b760c4f88083520
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=e28442fce699135a678d87f47199ecead0bb39ff250c5f9b54c7acbfe40c08d7
SANITIZED_OUTPUT_SHA256=e28442fce699135a678d87f47199ecead0bb39ff250c5f9b54c7acbfe40c08d7
OUTPUT_BEGIN
ERROR_REGISTER_CHECK=OK
REFERENCE_CHECK=OK
AUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED
OVERLAY_ROOT_PRESENT=True
OVERLAY_FILE_COUNT=6
OVERLAY_FILE_01_PATH=entry504.py
OVERLAY_FILE_01_MODE=0o400
OVERLAY_FILE_01_UID=0
OVERLAY_FILE_01_GID=0
OVERLAY_FILE_01_SIZE=10566
OVERLAY_FILE_01_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793
OVERLAY_FILE_02_PATH=fresh_lxc_helper.py
OVERLAY_FILE_02_MODE=0o400
OVERLAY_FILE_02_UID=0
OVERLAY_FILE_02_GID=0
OVERLAY_FILE_02_SIZE=2320
OVERLAY_FILE_02_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011
OVERLAY_FILE_03_PATH=lxc_adapter.py
OVERLAY_FILE_03_MODE=0o400
OVERLAY_FILE_03_UID=0
OVERLAY_FILE_03_GID=0
OVERLAY_FILE_03_SIZE=13825
OVERLAY_FILE_03_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d
OVERLAY_FILE_04_PATH=producer_exec_helper.py
OVERLAY_FILE_04_MODE=0o400
OVERLAY_FILE_04_UID=0
OVERLAY_FILE_04_GID=0
OVERLAY_FILE_04_SIZE=3449
OVERLAY_FILE_04_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3
OVERLAY_FILE_05_PATH=qemu_adapter.py
OVERLAY_FILE_05_MODE=0o400
OVERLAY_FILE_05_UID=0
OVERLAY_FILE_05_GID=0
OVERLAY_FILE_05_SIZE=4627
OVERLAY_FILE_05_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b
OVERLAY_FILE_06_PATH=scheduler_adapter.py
OVERLAY_FILE_06_MODE=0o400
OVERLAY_FILE_06_UID=0
OVERLAY_FILE_06_GID=0
OVERLAY_FILE_06_SIZE=4097
OVERLAY_FILE_06_SHA256=a6f67159a64067773323f028126e3109e15cf17a8142cea5e6129970f1d4da96
OVERLAY_MATCH_FILE=entry504.py
OVERLAY_MATCH_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793
OVERLAY_MATCH_LINE_COUNT=13
OVERLAY_MATCH_LINES=4,7,43,44,62,78,80,93,96,97,105,112,123
OVERLAY_CONTEXT_entry504_py_01_RANGE=1-15
OVERLAY_CONTEXT_entry504_py_01_LINE_0001=from __future__ import annotations
OVERLAY_CONTEXT_entry504_py_01_LINE_0002=import hashlib, importlib, json, os, pathlib, stat, sys, types
OVERLAY_CONTEXT_entry504_py_01_LINE_0003=
OVERLAY_CONTEXT_entry504_py_01_LINE_0004=BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')
OVERLAY_CONTEXT_entry504_py_01_LINE_0005=HERE=pathlib.Path(__file__).resolve().parent
OVERLAY_CONTEXT_entry504_py_01_LINE_0006=BASE_EXPECTED={
OVERLAY_CONTEXT_entry504_py_01_LINE_0007='legacy_engine.py':'b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7',
OVERLAY_CONTEXT_entry504_py_01_LINE_0008='wrapper.py':'2b5eb4fc0f6f466a0d3e5a007af987092b6c17baa3ff9241a6afc2c2e97df1d5',
OVERLAY_CONTEXT_entry504_py_01_LINE_0009='ct112_handler.py':'8cac6e627d5e7abe5d3163cdd24911995a1e3f45c776f9373c2aa68784f5ec6c',
OVERLAY_CONTEXT_entry504_py_01_LINE_0010='representative_driver.py':'b3050a8f95e6d9826a4f0786cd3ca32012b6ab10486d10e4981b50b8a0affff2',
OVERLAY_CONTEXT_entry504_py_01_LINE_0011='candidate411/adapter.py':'18eb29cef165371b48bcb78e1a456e1939e6eff253787218133162cc89ab9fa3',
OVERLAY_CONTEXT_entry504_py_01_LINE_0012='candidate411/pve265.py':'cd2f634414a8e38a3789015aeca5a9b47821f77d7d1fa61dcdbdc866172963be',
OVERLAY_CONTEXT_entry504_py_01_LINE_0013='candidate411/pve270.py':'97015277a4f3f8129c0fd11eb70c06293026366f1f8232a97feeed513a2dbcef',
OVERLAY_CONTEXT_entry504_py_01_LINE_0014='candidate411/pve282.py':'73c6cb7773eb8e82d1e7ed5ab4733b4afb88f74ae69c09125d0378d6e480e012',
OVERLAY_CONTEXT_entry504_py_01_LINE_0015=}
OVERLAY_CONTEXT_entry504_py_02_RANGE=39-52
OVERLAY_CONTEXT_entry504_py_02_LINE_0039=try: return self._g[n]
OVERLAY_CONTEXT_entry504_py_02_LINE_0040=except KeyError as e: raise AttributeError(n) from e
OVERLAY_CONTEXT_entry504_py_02_LINE_0041=def __setattr__(self,n,v): self._g[n]=v
OVERLAY_CONTEXT_entry504_py_02_LINE_0042=
OVERLAY_CONTEXT_entry504_py_02_LINE_0043=def _wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,base=BASE):
OVERLAY_CONTEXT_entry504_py_02_LINE_0044=legacy_path=(pathlib.Path(base)/'legacy_engine.py').resolve()
OVERLAY_CONTEXT_entry504_py_02_LINE_0045=found={}
OVERLAY_CONTEXT_entry504_py_02_LINE_0046=for value in vars(wrapper).values():
OVERLAY_CONTEXT_entry504_py_02_LINE_0047=if isinstance(value,types.ModuleType):
OVERLAY_CONTEXT_entry504_py_02_LINE_0048=g=vars(value); raw=g.get('__file__')
OVERLAY_CONTEXT_entry504_py_02_LINE_0049=elif isinstance(value,types.FunctionType):
OVERLAY_CONTEXT_entry504_py_02_LINE_0050=g=value.__globals__; raw=g.get('__file__')
OVERLAY_CONTEXT_entry504_py_02_LINE_0051=else:
OVERLAY_CONTEXT_entry504_py_02_LINE_0052=continue
OVERLAY_CONTEXT_entry504_py_03_RANGE=58-70
OVERLAY_CONTEXT_entry504_py_03_LINE_0058=found[id(g)]=g
OVERLAY_CONTEXT_entry504_py_03_LINE_0059=if len(found)!=1:
OVERLAY_CONTEXT_entry504_py_03_LINE_0060=raise RuntimeError('LEGACY_PROVENANCE_CARDINALITY')
OVERLAY_CONTEXT_entry504_py_03_LINE_0061=g=next(iter(found.values()))
OVERLAY_CONTEXT_entry504_py_03_LINE_0062=required=('capture_pve_guest','backup_target','load_targets','cluster_inventory','ssh_remote',
OVERLAY_CONTEXT_entry504_py_03_LINE_0063='_default_unprivileged_lxc','mapped_scratch_probe','_stream_argv_to_local','run',
OVERLAY_CONTEXT_entry504_py_03_LINE_0064='choose_due_target','write_state','epoch')
OVERLAY_CONTEXT_entry504_py_03_LINE_0065=if any(not callable(g.get(n)) for n in required):
OVERLAY_CONTEXT_entry504_py_03_LINE_0066=raise RuntimeError('LEGACY_PROVENANCE_API')
OVERLAY_CONTEXT_entry504_py_03_LINE_0067=original=g['capture_pve_guest']
OVERLAY_CONTEXT_entry504_py_03_LINE_0068=proxy=_GlobalsProxy(g)
OVERLAY_CONTEXT_entry504_py_03_LINE_0069=if not isinstance(g.get('SCP'),str) or not g['SCP'].startswith('/'):
OVERLAY_CONTEXT_entry504_py_03_LINE_0070=raise RuntimeError('LEGACY_SCP_API')
OVERLAY_CONTEXT_entry504_py_04_RANGE=74-131
OVERLAY_CONTEXT_entry504_py_04_LINE_0074=patched=lxc_adapter.bind(proxy,qemu_patched)
OVERLAY_CONTEXT_entry504_py_04_LINE_0075=if not callable(patched):
OVERLAY_CONTEXT_entry504_py_04_LINE_0076=raise RuntimeError('LXC_ADAPTER_BIND_RESULT')
OVERLAY_CONTEXT_entry504_py_04_LINE_0077=g['capture_pve_guest']=patched
OVERLAY_CONTEXT_entry504_py_04_LINE_0078=scheduler_wired=scheduler_adapter.bind(proxy,g['choose_due_target'],g['write_state'])
OVERLAY_CONTEXT_entry504_py_04_LINE_0079=if g.get('choose_due_target') is not scheduler_wired['choose_due_target'] or g.get('write_state') is not scheduler_wired['write_state']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0080=raise RuntimeError('SCHEDULER_ADAPTER_BIND_RESULT')
OVERLAY_CONTEXT_entry504_py_04_LINE_0081=return {'legacy_globals':g,'legacy':proxy,'original_capture':original,'qemu_patched_capture':qemu_patched,'patched_capture':patched,'scheduler_wired':scheduler_wired}
OVERLAY_CONTEXT_entry504_py_04_LINE_0082=
OVERLAY_CONTEXT_entry504_py_04_LINE_0083=def _load():
OVERLAY_CONTEXT_entry504_py_04_LINE_0084=_verify_base()
OVERLAY_CONTEXT_entry504_py_04_LINE_0085=sys.dont_write_bytecode=True
OVERLAY_CONTEXT_entry504_py_04_LINE_0086=sys.path.insert(0,str(BASE))
OVERLAY_CONTEXT_entry504_py_04_LINE_0087=wrapper=importlib.import_module('wrapper')
OVERLAY_CONTEXT_entry504_py_04_LINE_0088=# Baseline accepted wrapper selftest stays the compatibility gate; no full old legacy selftest is reintroduced.
OVERLAY_CONTEXT_entry504_py_04_LINE_0089=wrapper.selftest()
OVERLAY_CONTEXT_entry504_py_04_LINE_0090=sys.path.insert(0,str(HERE))
OVERLAY_CONTEXT_entry504_py_04_LINE_0091=lxc_adapter=importlib.import_module('lxc_adapter')
OVERLAY_CONTEXT_entry504_py_04_LINE_0092=qemu_adapter=importlib.import_module('qemu_adapter')
OVERLAY_CONTEXT_entry504_py_04_LINE_0093=scheduler_adapter=importlib.import_module('scheduler_adapter')
OVERLAY_CONTEXT_entry504_py_04_LINE_0094=if _sha(HERE/'lxc_adapter.py')!='3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d':
OVERLAY_CONTEXT_entry504_py_04_LINE_0095=raise RuntimeError('LXC_502_BYTE_IDENTITY')
OVERLAY_CONTEXT_entry504_py_04_LINE_0096=wired=_wire(wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,BASE)
OVERLAY_CONTEXT_entry504_py_04_LINE_0097=return wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired
OVERLAY_CONTEXT_entry504_py_04_LINE_0098=
OVERLAY_CONTEXT_entry504_py_04_LINE_0099=def _target(wrapper,lid):
OVERLAY_CONTEXT_entry504_py_04_LINE_0100=rows=wrapper.load_targets(); hits=[x for x in rows if x.get('logical_id')==lid]
OVERLAY_CONTEXT_entry504_py_04_LINE_0101=if len(hits)!=1: raise RuntimeError('TARGET_CARDINALITY')
OVERLAY_CONTEXT_entry504_py_04_LINE_0102=return hits[0]
OVERLAY_CONTEXT_entry504_py_04_LINE_0103=
OVERLAY_CONTEXT_entry504_py_04_LINE_0104=def selftest():
OVERLAY_CONTEXT_entry504_py_04_LINE_0105=wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()
OVERLAY_CONTEXT_entry504_py_04_LINE_0106=if wired['legacy_globals'].get('capture_pve_guest') is not wired['patched_capture']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0107=raise RuntimeError('PATCH_BINDING')
OVERLAY_CONTEXT_entry504_py_04_LINE_0108=if wired['legacy_globals'].get('choose_due_target') is not wired['scheduler_wired']['choose_due_target']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0109=raise RuntimeError('SCHEDULER_CHOOSE_BINDING')
OVERLAY_CONTEXT_entry504_py_04_LINE_0110=if wired['legacy_globals'].get('write_state') is not wired['scheduler_wired']['write_state']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0111=raise RuntimeError('SCHEDULER_WRITE_BINDING')
OVERLAY_CONTEXT_entry504_py_04_LINE_0112=if [scheduler_adapter.backoff_seconds(n) for n in range(1,7)]!=[1800,3600,7200,14400,21600,21600]:
OVERLAY_CONTEXT_entry504_py_04_LINE_0113=raise RuntimeError('SCHEDULER_BACKOFF_CONTRACT')
OVERLAY_CONTEXT_entry504_py_04_LINE_0114=if not callable(wrapper.backup_target) or not callable(wrapper.main) or not callable(wrapper.load_targets):
OVERLAY_CONTEXT_entry504_py_04_LINE_0115=raise RuntimeError('WRAPPER_PUBLIC_API')
OVERLAY_CONTEXT_entry504_py_04_LINE_0116=print('SELFTEST_OVERLAY504=PASS',flush=True)
OVERLAY_CONTEXT_entry504_py_04_LINE_0117=return 0
OVERLAY_CONTEXT_entry504_py_04_LINE_0118=
OVERLAY_CONTEXT_entry504_py_04_LINE_0119=def main(argv=None):
OVERLAY_CONTEXT_entry504_py_04_LINE_0120=argv=list(sys.argv[1:] if argv is None else argv)
OVERLAY_CONTEXT_entry504_py_04_LINE_0121=if argv==['selftest']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0122=return selftest()
OVERLAY_CONTEXT_entry504_py_04_LINE_0123=wrapper,lxc_adapter,qemu_adapter,scheduler_adapter,wired=_load()
OVERLAY_CONTEXT_entry504_py_04_LINE_0124=legacy=wired['legacy']
OVERLAY_CONTEXT_entry504_py_04_LINE_0125=if argv==['scheduler-proof']:
OVERLAY_CONTEXT_entry504_py_04_LINE_0126=import tempfile
OVERLAY_CONTEXT_entry504_py_04_LINE_0127=legacy=wired['legacy']; g=wired['legacy_globals']
OVERLAY_CONTEXT_entry504_py_04_LINE_0128=old_root=g.get('STATE_ROOT'); old_epoch=g.get('epoch')
OVERLAY_CONTEXT_entry504_py_04_LINE_0129=if old_root is None or not callable(old_epoch): raise RuntimeError('SCHEDULER_PROOF_BASE')
OVERLAY_CONTEXT_entry504_py_04_LINE_0130=now=[1000]
OVERLAY_CONTEXT_entry504_py_04_LINE_0131=try:
OVERLAY_MATCH_FILE=fresh_lxc_helper.py
OVERLAY_MATCH_SHA256=dbb3e6dbb71b10797df736431d9501a752a0f8c439163c9a0bddb7f76747f011
OVERLAY_MATCH_LINE_COUNT=1
OVERLAY_MATCH_LINES=4
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_RANGE=1-12
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0001=from __future__ import annotations
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0002=import base64, hashlib, json, pathlib, sys
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0003=
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0004=BASE_RELEASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1')
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0005=C411=BASE_RELEASE/'candidate411'
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0006=PVE265_SHA='cd2f634414a8e38a3789015aeca5a9b47821f77d7d1fa61dcdbdc866172963be'
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0007=
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0008=def sha(p:pathlib.Path)->str:
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0009=return hashlib.sha256(p.read_bytes()).hexdigest()
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0010=
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0011=def fail(code:str):
OVERLAY_CONTEXT_fresh_lxc_helper_py_01_LINE_0012=raise RuntimeError(code)
OVERLAY_MATCH_FILE=lxc_adapter.py
OVERLAY_MATCH_SHA256=3fa7d194010d76f7c8bc95035ae8876262e9337903e310f45f45df88c266dc8d
OVERLAY_MATCH_LINE_COUNT=19
OVERLAY_MATCH_LINES=2,7,36,44,45,52,55,57,59,68,95,112,130,133,158,162,199,200,213
OVERLAY_CONTEXT_lxc_adapter_py_01_RANGE=1-15
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0001=from __future__ import annotations
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0002=import base64, hashlib, json, os, pathlib, re, selectors, shlex, signal, stat, subprocess, sys, time
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0003=
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0004=PVESH_SHA='9ed13d4c2d82e7864ff0192c428da7669af263f81dfcc84d5a981ca98fee8439'
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0005=VZDUMP_SHA='21339d009afd55cb7ec613b64c1f493b2a7dbd18b85b4d712909ef6d6710f4ea'
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0006=HELPER=pathlib.Path(__file__).resolve().parent/'fresh_lxc_helper.py'
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0007=EXEC_HELPER=pathlib.Path(__file__).resolve().parent/'producer_exec_helper.py'
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0008=MAX_STDERR=262144
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0009=ENV={'PATH':'/usr/sbin:/usr/bin:/sbin:/bin','LC_ALL':'C','LANG':'C','HOME':'/root','PYTHONDONTWRITEBYTECODE':'1'}
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0010=
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0011=class AdapterError(RuntimeError): pass
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0012=class ExecFailure(AdapterError):
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0013=def __init__(self,code,summary): super().__init__(code); self.code=code; self.summary=summary
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0014=
OVERLAY_CONTEXT_lxc_adapter_py_01_LINE_0015=def _need(ok:bool,code:str):
OVERLAY_CONTEXT_lxc_adapter_py_02_RANGE=32-76
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0032=if n<=0: raise AdapterError('WRITE_FAILED')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0033=view=view[n:]
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0034=
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0035=def _remote_sha(legacy,node,path):
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0036=p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0037=parts=p.stdout.decode('ascii','strict').strip().split()
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0038=_need(len(parts)>=2 and parts[1]==path,'TOOL_SHA_OUTPUT')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0039=return parts[0]
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0040=
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0041=def _live_inputs(legacy,node,vmid,scratch):
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0042=_need(_remote_sha(legacy,node,'/usr/bin/pvesh')==PVESH_SHA,'PVESH_IDENTITY')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0043=_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0044=rows=_j(legacy.ssh_remote(node,['pvesh','get','/cluster/resources','--type','vm','--output-format','json'],timeout=60),'RESOURCES_JSON')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0045=stores=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/storage','--output-format','json'],timeout=60),'STORAGE_JSON')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0046=_need(type(rows) is list and type(stores) is list,'PVE_LIST_SCHEMA')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0047=configs=[]
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0048=for r in rows:
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0049=if not isinstance(r,dict) or r.get('node')!=node or r.get('type') not in ('lxc','qemu'): continue
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0050=try: rid=int(r.get('vmid'))
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0051=except Exception: raise AdapterError('RESOURCE_VMID')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0052=cfg=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/{r["type"]}/{rid}/config','--output-format','json'],timeout=60),'CONFIG_JSON')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0053=_need(type(cfg) is dict,'CONFIG_SCHEMA')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0054=configs.append([rid,cfg])
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0055=tasks=_j(legacy.ssh_remote(node,['pvesh','get',f'/nodes/{node}/tasks','--limit','999','--output-format','json'],timeout=60),'TASKS_JSON')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0056=_need(type(tasks) is list and len(tasks)<1000,'TASKS_SCHEMA')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0057=q=legacy.ssh_remote(node,['test','-f','/etc/vzdump.conf'],timeout=30,check=False)
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0058=defaults=None
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0059=if q.returncode==0: defaults=legacy.ssh_remote(node,['cat','--','/etc/vzdump.conf'],timeout=30).stdout
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0060=elif q.returncode!=1: raise AdapterError('DEFAULTS_PROBE')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0061=st=os.statvfs('/mnt/staging'); free=int(st.f_bavail*st.f_frsize)
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0062=return {'node':node,'vmid':vmid,'scratch':scratch,'now':int(time.time()),'rows':rows,'storage_rows':stores,'configs':configs,
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0063='defaults_b64':None if defaults is None else base64.b64encode(defaults).decode('ascii'),'staging_free':free,'tasks':tasks}
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0064=
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0065=def _helper(inp):
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0066=data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode('utf-8')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0067=_need(0<len(data)<=4_000_000,'FRESH_HELPER_INPUT_BOUND')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0068=p=subprocess.run(['/usr/bin/python3','-I','-B',str(HELPER)],input=data,capture_output=True,timeout=120,cwd='/',env=ENV)
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0069=_need(p.returncode==0 and not p.stderr and 0<len(p.stdout)<=262144,'FRESH_HELPER_FAILED')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0070=try: out=json.loads(p.stdout)
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0071=except Exception as e: raise AdapterError('FRESH_HELPER_JSON') from e
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0072=_need(type(out) is dict and out.get('schema')==1 and type(out.get('argv')) is list and type(out.get('job')) is dict,'FRESH_HELPER_SCHEMA')
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0073=return out
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0074=
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0075=def _stable_job(job):
OVERLAY_CONTEXT_lxc_adapter_py_02_LINE_0076=_need(type(job) is dict,'JOB_SCHEMA')
OVERLAY_CONTEXT_lxc_adapter_py_03_RANGE=91-103
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0091=def _execute_local(legacy,node,argv,dest,cap,timeout):
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0092=_need(node=='pve01','LOCAL_NODE')
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0093=inp={'argv':argv,'dest':str(dest),'cap':int(cap),'seconds':int(timeout)}
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0094=data=json.dumps(inp,separators=(',',':'),sort_keys=True).encode()
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0095=p=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV)
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0096=if p.stderr or not p.stdout or len(p.stdout)>262144:
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0097=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)})
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0098=try: out=json.loads(p.stdout)
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0099=except Exception:
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0100=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)})
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0101=summary={'executor':'local-proven-pve270','helper_rc':p.returncode,'exception_class':out.get('exception_class'),'exception_message_sha256':out.get('exception_message_sha256')}
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0102=if isinstance(out.get('process'),dict): summary.update(out['process'])
OVERLAY_CONTEXT_lxc_adapter_py_03_LINE_0103=if p.returncode!=0 or out.get('status')!='OK': raise ExecFailure('LOCAL_PRODUCER_FAILED',summary)
OVERLAY_CONTEXT_lxc_adapter_py_04_RANGE=108-120
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0108=def _kill(p):
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0109=try: os.killpg(p.pid,signal.SIGTERM)
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0110=except ProcessLookupError: pass
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0111=try: p.wait(timeout=10)
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0112=except subprocess.TimeoutExpired:
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0113=try: os.killpg(p.pid,signal.SIGKILL)
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0114=except ProcessLookupError: pass
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0115=p.wait()
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0116=
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0117=def _execute_remote(legacy,node,argv,dest,cap,timeout):
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0118=_need(re.fullmatch(r'pve0[123]',str(node)) is not None and node!='pve01','REMOTE_NODE')
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0119=_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')
OVERLAY_CONTEXT_lxc_adapter_py_04_LINE_0120=_need('--node' in argv and argv[argv.index('--node')+1]==node,'REMOTE_ARGV_NODE')
OVERLAY_CONTEXT_lxc_adapter_py_05_RANGE=126-141
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0126=fd=os.open(dest,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600); efd=os.open(errp,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0127=initial=os.fstat(fd)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0128=digest=hashlib.sha256(); eh=hashlib.sha256(); total=err_total=err_kept=0; p=None; sel=None; good=False
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0129=remote='cd / && exec '+shlex.join(argv)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0130=ssh=['/usr/bin/ssh','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','ConnectTimeout=15',f'root@{node}',remote]
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0131=deadline=time.monotonic()+timeout
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0132=try:
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0133=p=subprocess.Popen(ssh,stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd='/',env=ENV,start_new_session=True,close_fds=True)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0134=sel=selectors.DefaultSelector()
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0135=for pipe in (p.stdout,p.stderr): os.set_blocking(pipe.fileno(),False); sel.register(pipe,selectors.EVENT_READ)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0136=while sel.get_map():
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0137=now=time.monotonic()
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0138=if now>=deadline: raise ExecFailure('REMOTE_TIMEOUT',{})
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0139=for key,_ in sel.select(min(.2,max(0,deadline-now))):
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0140=b=os.read(key.fileobj.fileno(),65536)
OVERLAY_CONTEXT_lxc_adapter_py_05_LINE_0141=if not b: sel.unregister(key.fileobj); continue
OVERLAY_CONTEXT_lxc_adapter_py_06_RANGE=154-170
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0154=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:
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0155=raise ExecFailure('REMOTE_FILE_IDENTITY',{})
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0156=_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'VZDUMP_IDENTITY_EXEC_POST')
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0157=os.fchmod(fd,0o400); os.fsync(fd); os.fsync(efd); good=True
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0158=return {'executor':'remote-bounded-ssh-cwd-root','producer_rc':rc,'size':total,'sha256':digest.hexdigest(),
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0159='stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0160=except ExecFailure as e:
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0161=if p is not None and p.poll() is None: _kill(p)
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0162=summary={'executor':'remote-bounded-ssh-cwd-root','producer_rc':None if p is None else p.returncode,'archive_bytes':total,
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0163='stderr_bytes_observed':err_total,'stderr_bytes_retained':err_kept,'stderr_truncated':err_total>err_kept,'stderr_stream_sha256':eh.hexdigest()}
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0164=summary.update(e.summary); raise ExecFailure(e.code,summary)
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0165=finally:
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0166=if p is not None:
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0167=if p.poll() is None: _kill(p)
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0168=if p.stdout: p.stdout.close()
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0169=if p.stderr: p.stderr.close()
OVERLAY_CONTEXT_lxc_adapter_py_06_LINE_0170=if sel is not None: sel.close()
OVERLAY_CONTEXT_lxc_adapter_py_07_RANGE=195-218
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0195=row=rows[0]; node=row.get('node'); typ=row.get('type')
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0196=_need(typ==t.get('guest_type')=='lxc','PVE_GUEST_TYPE_DRIFT')
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0197=legacy._default_unprivileged_lxc(node,vmid)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0198=scratch=f'/var/tmp/homelab-vzdump-v2-{gen}'
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0199=legacy.ssh_remote(node,['install','-d','-m','710','-o','0','-g','100000',scratch],timeout=30)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0200=q=legacy.ssh_remote(node,['stat','-c','%a:%u:%g',scratch],timeout=30)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0201=_need(q.stdout.decode().strip()=='710:0:100000','PVE_MAPPED_SCRATCH_ACCESS_CONTRACT')
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0202=try:
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0203=legacy.mapped_scratch_probe(node,scratch)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0204=p=plan_only(legacy,t,scratch); local=pathlib.Path(work)/'payload.bin'; cap=int(p['job']['archive_cap_bytes'])
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0205=try:
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0206=result=_execute_local(legacy,node,p['argv'],local,cap,7200) if node=='pve01' else _execute_remote(legacy,node,p['argv'],local,cap,7200)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0207=except ExecFailure as e:
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0208=_emit_diag(node,e.summary|{'failure_code':e.code})
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0209=raise legacy.BackupError('LXC_PRODUCER_FAILED') from None
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0210=_need(local.is_file() and 0<local.stat().st_size<=cap,'VZDUMP_PAYLOAD_BOUND')
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0211=_emit_diag(node,result)
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0212=except Exception:
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0213=legacy.ssh_remote(node,['rm','-rf','--',scratch],timeout=60,check=False); raise
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0214=cleanup={'kind':'pve_source_dir','node':node,'path':scratch}
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0215=meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'lxc','node':node,'status':row.get('status'),
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0216='producer_contract':'fresh-pve265-plan-bounded-producer-overlay502'}
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0217=return local,meta,cleanup
OVERLAY_CONTEXT_lxc_adapter_py_07_LINE_0218=capture_pve_guest.__name__='capture_pve_guest'; return capture_pve_guest
OVERLAY_MATCH_FILE=producer_exec_helper.py
OVERLAY_MATCH_SHA256=b3b97099bcd7126670f866e81faae6a42a96d869d9989e6a67f6ea6c871c90b3
OVERLAY_MATCH_LINE_COUNT=2
OVERLAY_MATCH_LINES=4,31
OVERLAY_CONTEXT_producer_exec_helper_py_01_RANGE=1-12
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0001=from __future__ import annotations
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0002=import hashlib, json, os, pathlib, sys
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0003=
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0004=BASE=pathlib.Path('/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411')
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0005=VZDUMP=pathlib.Path('/usr/bin/vzdump')
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0006=VZDUMP_SHA='21339d009afd55cb7ec613b64c1f493b2a7dbd18b85b4d712909ef6d6710f4ea'
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0007=MAX_INPUT=262144
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0008=
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0009=def sha_file(p:pathlib.Path)->str:
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0010=h=hashlib.sha256()
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0011=with open(p,'rb',buffering=0) as f:
OVERLAY_CONTEXT_producer_exec_helper_py_01_LINE_0012=for b in iter(lambda:f.read(1<<20),b''): h.update(b)
OVERLAY_CONTEXT_producer_exec_helper_py_02_RANGE=27-39
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0027=if sha_file(VZDUMP)!=VZDUMP_SHA: fail('VZDUMP_IDENTITY')
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0028=sys.path.insert(0,str(BASE))
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0029=import adapter
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0030=adapter.verify_sources(); adapter.load_graph()
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0031=print('PRODUCER_EXEC_HELPER_SELFTEST=PASS',flush=True)
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0032=return 0
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0033=
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0034=def main()->int:
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0035=if sys.argv[1:]==['selftest']: return selftest()
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0036=if sys.argv[1:]: fail('ARGC')
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0037=raw=sys.stdin.buffer.read(MAX_INPUT+1)
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0038=if not raw or len(raw)>MAX_INPUT: fail('INPUT_BOUND')
OVERLAY_CONTEXT_producer_exec_helper_py_02_LINE_0039=try: x=json.loads(raw)
OVERLAY_MATCH_FILE=qemu_adapter.py
OVERLAY_MATCH_SHA256=1906db42bd34bbe85eb46fd9797b3572d46e0a41c29d1c29be5f9df5e448f15b
OVERLAY_MATCH_LINE_COUNT=7
OVERLAY_MATCH_LINES=12,49,51,56,62,69,73
OVERLAY_CONTEXT_qemu_adapter_py_01_RANGE=8-20
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0008=def _need(ok,code):
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0009=if not ok: raise QemuAdapterError(code)
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0010=
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0011=def _remote_sha(legacy,node,path):
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0012=p=legacy.ssh_remote(node,['sha256sum','--',path],timeout=30)
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0013=parts=p.stdout.decode('ascii','strict').strip().split()
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0014=_need(len(parts)>=2 and parts[1]==path,'QEMU_TOOL_SHA_OUTPUT')
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0015=return parts[0]
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0016=
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0017=def _select_qemu_outputs(vmid,files):
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0018=_need(type(vmid) is int and vmid>0,'QEMU_VMID')
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0019=_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')
OVERLAY_CONTEXT_qemu_adapter_py_01_LINE_0020=_need(len(files)==len(set(files)),'QEMU_OUTPUT_DUPLICATE')
OVERLAY_CONTEXT_qemu_adapter_py_02_RANGE=45-79
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0045=row=rows[0]; node=row.get('node'); typ=row.get('type')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0046=_need(typ==t.get('guest_type')=='qemu','PVE_GUEST_TYPE_DRIFT')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0047=_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_PRE')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0048=srcdir=f'/var/tmp/homelab-vzdump-v2-{gen}'
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0049=legacy.ssh_remote(node,['install','-d','-m','700','-o','0','-g','0',srcdir],timeout=30)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0050=try:
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0051=vp=legacy.ssh_remote(node,['vzdump',str(vmid),'--mode','snapshot','--compress','zstd','--dumpdir',srcdir],timeout=7200,check=False)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0052=if vp.returncode!=0:
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0053=_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)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0054=raise legacy.BackupError('QEMU_VZDUMP_FAILED')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0055=_need(_remote_sha(legacy,node,'/usr/bin/vzdump')==VZDUMP_SHA,'QEMU_VZDUMP_IDENTITY_POST')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0056=p=legacy.ssh_remote(node,['find',srcdir,'-maxdepth','1','-type','f','-printf','%p\n'],timeout=30)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0057=files=[x for x in p.stdout.decode('utf-8','strict').splitlines() if x]
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0058=try: src,log=_select_qemu_outputs(vmid,files)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0059=except QemuAdapterError as e:
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0060=_emit_diag(vmid=vmid,node=node,producer_rc=0,regular_file_count=len(files),archive_selected=False,selector_error=str(e))
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0061=raise legacy.BackupError(str(e)) from None
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0062=q=legacy.ssh_remote(node,['stat','-c','%s','--',src],timeout=30)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0063=raw=q.stdout.decode('ascii','strict').strip()
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0064=_need(raw.isdigit() and int(raw)>0,'QEMU_ARCHIVE_STAT')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0065=size=int(raw)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0066=local=pathlib.Path(work)/'payload.bin'
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0067=if node=='pve01': local=pathlib.Path(src)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0068=else:
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0069=legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0070=_need(pathlib.Path(local).is_file() and pathlib.Path(local).stat().st_size==size,'QEMU_PAYLOAD_MISSING')
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0071=_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)
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0072=except Exception:
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0073=legacy.ssh_remote(node,['rm','-rf','--',srcdir],timeout=60,check=False); raise
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0074=cleanup={'kind':'pve_source_dir','node':node,'path':srcdir}
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0075=meta={'generation':gen,'source_class':'pve_guest','vmid':vmid,'guest_type':'qemu','node':node,'status':row.get('status'),
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0076='producer_contract':'strict-qemu-vma-zst-plus-matching-log-overlay503'}
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0077=return pathlib.Path(local),meta,cleanup
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0078=capture_pve_guest.__name__='capture_pve_guest'
OVERLAY_CONTEXT_qemu_adapter_py_02_LINE_0079=return capture_pve_guest
OVERLAY_AST_FILE=entry504.py
OVERLAY_AST_FUNCTION_COUNT=2
OVERLAY_AST_FUNCTION_01_LINE=99
OVERLAY_AST_FUNCTION_01_NAME=_target
OVERLAY_AST_FUNCTION_02_LINE=119
OVERLAY_AST_FUNCTION_02_NAME=main
OVERLAY_AST_IMPORT_COUNT=10
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=hashlib
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=importlib
OVERLAY_AST_IMPORT_04_LINE=2
OVERLAY_AST_IMPORT_04_NAME=json
OVERLAY_AST_IMPORT_05_LINE=2
OVERLAY_AST_IMPORT_05_NAME=os
OVERLAY_AST_IMPORT_06_LINE=2
OVERLAY_AST_IMPORT_06_NAME=pathlib
OVERLAY_AST_IMPORT_07_LINE=2
OVERLAY_AST_IMPORT_07_NAME=stat
OVERLAY_AST_IMPORT_08_LINE=2
OVERLAY_AST_IMPORT_08_NAME=sys
OVERLAY_AST_IMPORT_09_LINE=2
OVERLAY_AST_IMPORT_09_NAME=types
OVERLAY_AST_IMPORT_10_LINE=126
OVERLAY_AST_IMPORT_10_NAME=tempfile
OVERLAY_AST_CALL_COUNT=4
OVERLAY_AST_CALL_01_LINE=87
OVERLAY_AST_CALL_01_KIND=import_module
OVERLAY_AST_CALL_01_TEXT=importlib.import_module('wrapper')
OVERLAY_AST_CALL_02_LINE=91
OVERLAY_AST_CALL_02_KIND=import_module
OVERLAY_AST_CALL_02_TEXT=importlib.import_module('lxc_adapter')
OVERLAY_AST_CALL_03_LINE=92
OVERLAY_AST_CALL_03_KIND=import_module
OVERLAY_AST_CALL_03_TEXT=importlib.import_module('qemu_adapter')
OVERLAY_AST_CALL_04_LINE=93
OVERLAY_AST_CALL_04_KIND=import_module
OVERLAY_AST_CALL_04_TEXT=importlib.import_module('scheduler_adapter')
OVERLAY_AST_FILE=fresh_lxc_helper.py
OVERLAY_AST_FUNCTION_COUNT=1
OVERLAY_AST_FUNCTION_01_LINE=14
OVERLAY_AST_FUNCTION_01_NAME=main
OVERLAY_AST_IMPORT_COUNT=7
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=base64
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=hashlib
OVERLAY_AST_IMPORT_04_LINE=2
OVERLAY_AST_IMPORT_04_NAME=json
OVERLAY_AST_IMPORT_05_LINE=2
OVERLAY_AST_IMPORT_05_NAME=pathlib
OVERLAY_AST_IMPORT_06_LINE=2
OVERLAY_AST_IMPORT_06_NAME=sys
OVERLAY_AST_IMPORT_07_LINE=19
OVERLAY_AST_IMPORT_07_NAME=adapter
OVERLAY_AST_CALL_COUNT=0
OVERLAY_AST_FILE=lxc_adapter.py
OVERLAY_AST_FUNCTION_COUNT=1
OVERLAY_AST_FUNCTION_01_LINE=191
OVERLAY_AST_FUNCTION_01_NAME=capture_pve_guest
OVERLAY_AST_IMPORT_COUNT=14
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=base64
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=hashlib
OVERLAY_AST_IMPORT_04_LINE=2
OVERLAY_AST_IMPORT_04_NAME=json
OVERLAY_AST_IMPORT_05_LINE=2
OVERLAY_AST_IMPORT_05_NAME=os
OVERLAY_AST_IMPORT_06_LINE=2
OVERLAY_AST_IMPORT_06_NAME=pathlib
OVERLAY_AST_IMPORT_07_LINE=2
OVERLAY_AST_IMPORT_07_NAME=re
OVERLAY_AST_IMPORT_08_LINE=2
OVERLAY_AST_IMPORT_08_NAME=selectors
OVERLAY_AST_IMPORT_09_LINE=2
OVERLAY_AST_IMPORT_09_NAME=shlex
OVERLAY_AST_IMPORT_10_LINE=2
OVERLAY_AST_IMPORT_10_NAME=signal
OVERLAY_AST_IMPORT_11_LINE=2
OVERLAY_AST_IMPORT_11_NAME=stat
OVERLAY_AST_IMPORT_12_LINE=2
OVERLAY_AST_IMPORT_12_NAME=subprocess
OVERLAY_AST_IMPORT_13_LINE=2
OVERLAY_AST_IMPORT_13_NAME=sys
OVERLAY_AST_IMPORT_14_LINE=2
OVERLAY_AST_IMPORT_14_NAME=time
OVERLAY_AST_CALL_COUNT=3
OVERLAY_AST_CALL_01_LINE=68
OVERLAY_AST_CALL_01_KIND=run
OVERLAY_AST_CALL_01_TEXT=subprocess.run(['/usr/bin/python3','-I','-B',str(HELPER)],input=data,capture_output=True,timeout=120,cwd='/',env=ENV)
OVERLAY_AST_CALL_02_LINE=95
OVERLAY_AST_CALL_02_KIND=run
OVERLAY_AST_CALL_02_TEXT=subprocess.run(['/usr/bin/python3','-I','-B',str(EXEC_HELPER)],input=data,capture_output=True,timeout=timeout+120,cwd='/',env=ENV)
OVERLAY_AST_CALL_03_LINE=133
OVERLAY_AST_CALL_03_KIND=Popen
OVERLAY_AST_CALL_03_TEXT=subprocess.Popen(ssh,stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd='/',env=ENV,start_new_session=True,close_fds=True)
OVERLAY_AST_FILE=producer_exec_helper.py
OVERLAY_AST_FUNCTION_COUNT=1
OVERLAY_AST_FUNCTION_01_LINE=34
OVERLAY_AST_FUNCTION_01_NAME=main
OVERLAY_AST_IMPORT_COUNT=8
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=hashlib
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=json
OVERLAY_AST_IMPORT_04_LINE=2
OVERLAY_AST_IMPORT_04_NAME=os
OVERLAY_AST_IMPORT_05_LINE=2
OVERLAY_AST_IMPORT_05_NAME=pathlib
OVERLAY_AST_IMPORT_06_LINE=2
OVERLAY_AST_IMPORT_06_NAME=sys
OVERLAY_AST_IMPORT_07_LINE=29
OVERLAY_AST_IMPORT_07_NAME=adapter
OVERLAY_AST_IMPORT_08_LINE=50
OVERLAY_AST_IMPORT_08_NAME=adapter
OVERLAY_AST_CALL_COUNT=0
OVERLAY_AST_FILE=qemu_adapter.py
OVERLAY_AST_FUNCTION_COUNT=1
OVERLAY_AST_FUNCTION_01_LINE=41
OVERLAY_AST_FUNCTION_01_NAME=capture_pve_guest
OVERLAY_AST_IMPORT_COUNT=5
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=hashlib
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=json
OVERLAY_AST_IMPORT_04_LINE=2
OVERLAY_AST_IMPORT_04_NAME=pathlib
OVERLAY_AST_IMPORT_05_LINE=2
OVERLAY_AST_IMPORT_05_NAME=re
OVERLAY_AST_CALL_COUNT=1
OVERLAY_AST_CALL_01_LINE=69
OVERLAY_AST_CALL_01_KIND=run
OVERLAY_AST_CALL_01_TEXT=legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)
OVERLAY_AST_FILE=scheduler_adapter.py
OVERLAY_AST_FUNCTION_COUNT=1
OVERLAY_AST_FUNCTION_01_LINE=55
OVERLAY_AST_FUNCTION_01_NAME=choose_due_target
OVERLAY_AST_IMPORT_COUNT=3
OVERLAY_AST_IMPORT_01_LINE=1
OVERLAY_AST_IMPORT_01_NAME=__future__.annotations
OVERLAY_AST_IMPORT_02_LINE=2
OVERLAY_AST_IMPORT_02_NAME=json
OVERLAY_AST_IMPORT_03_LINE=2
OVERLAY_AST_IMPORT_03_NAME=pathlib
OVERLAY_AST_CALL_COUNT=0
OVERLAY_REFERENCED_PATH_COUNT=2
OVERLAY_REF_01_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1
OVERLAY_REF_01_EXISTS=True
OVERLAY_REF_01_IS_FILE=False
OVERLAY_REF_02_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411
OVERLAY_REF_02_EXISTS=True
OVERLAY_REF_02_IS_FILE=False
OVERLAY_TRANSPORT_SIGNATURE_COUNT=2
OVERLAY_TRANSPORT_SIG_01_FILE=lxc_adapter.py
OVERLAY_TRANSPORT_SIG_01_LINE=130
OVERLAY_TRANSPORT_SIG_01_TEXT=ssh=['/usr/bin/ssh','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','ConnectTimeout=15',f'root@{node}',remote]
OVERLAY_TRANSPORT_SIG_02_FILE=qemu_adapter.py
OVERLAY_TRANSPORT_SIG_02_LINE=69
OVERLAY_TRANSPORT_SIG_02_TEXT=legacy.run([legacy.SCP,'-q','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','root@'+node+':'+src,str(local)],timeout=7200)
VPS557R3_DECISION=OVERLAY504_DELEGATES_TO_BASE_ENGINE
VPS557R3_NEXT_GATE=READ_OVERLAY504_BASE_ENGINE_BINDING
HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-INFRA-PVE1-MOLDOVA-OVERLAY504-TRANSPORT-READONLY-557R3","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null}

OUTPUT_END
CHAT_OUTPUT_END
