From c9f66bafbe95f23a449bdaa87d554ddad02d747a Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Fri, 18 Sep 2026 20:39:36 +0000 Subject: [PATCH] runtime: publish SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1 --- ...VE1-MOLDOVA-KEYMAPPING-READONLY-552R1.json | 38 +++ ...PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.txt | 253 +++++++++++++++++ runtime/latest.json | 16 +- runtime/latest.txt | 264 +++++++++++++++--- 4 files changed, 520 insertions(+), 51 deletions(-) create mode 100644 runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.json create mode 100644 runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.txt diff --git a/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.json b/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.json new file mode 100644 index 00000000..b3eb570e --- /dev/null +++ b/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "infra-pve1-moldova-keymapping-readonly", + "started_at_utc": "2026-09-18T20:39:36Z", + "finished_at_utc": "2026-09-18T20:39:36Z", + "reference_register_checked": true, + "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", + "error_register_checked": true, + "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", + "command_sha256": "0fadfaf45ded2524c42751f3efe29300f054f11e12b445ef897607a6f6b3e448", + "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": "b3e7cbda886dbd253274af0d4c726c89e54425e5b793e9e1f149ea8412962c14", + "sanitized_output_sha256": "be1cde014d4680574aba7cefa652231f34f1db8d57c07b09e171b79b88530186", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "ERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nACCEPTED_ENGINE_PRESENT=True\nACCEPTED_ENGINE_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7\nKEYMAPPING_MATCH_LINE_COUNT=17\nKEYMAPPING_MATCH_LINES=14,16,158,160,389,552,568,591,603,612,621,662,666,851,852,875,877\nKEYMAPPING_CONTEXT_01_RANGE=9-24\nKEYMAPPING_CONTEXT_01_LINE_0009=WORK_ROOT=pathlib.Path('/mnt/staging/homelab-backup-v2')\nKEYMAPPING_CONTEXT_01_LINE_0010=ENGINE_PATH=pathlib.Path('/usr/local/sbin/homelab-backup-v2')\nKEYMAPPING_CONTEXT_01_LINE_0011=RCLONE=shutil.which('rclone') or '/usr/bin/rclone'\nKEYMAPPING_CONTEXT_01_LINE_0012=SSH=shutil.which('ssh') or '/usr/bin/ssh'\nKEYMAPPING_CONTEXT_01_LINE_0013=SCP=shutil.which('scp') or '/usr/bin/scp'\nKEYMAPPING_CONTEXT_01_LINE_0014=SSH_KEYSCAN=shutil.which('ssh-keyscan') or '/usr/bin/ssh-keyscan'\nKEYMAPPING_CONTEXT_01_LINE_0015=SSHPASS=shutil.which('sshpass') or '/usr/bin/sshpass'\nKEYMAPPING_CONTEXT_01_LINE_0016=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH]\nKEYMAPPING_CONTEXT_01_LINE_0017=VPS_KNOWN_HOSTS=CONFIG_ROOT/'vps_known_hosts'\nKEYMAPPING_CONTEXT_01_LINE_0018=ROUTER_KNOWN_HOSTS=CONFIG_ROOT/'router_known_hosts'\nKEYMAPPING_CONTEXT_01_LINE_0019=ROUTER_LEGACY_SCRIPT=pathlib.Path('/usr/local/sbin/homelab-router-running-config-mail-cloud')\nKEYMAPPING_CONTEXT_01_LINE_0020=ROUTER_LEGACY_SHA='a0aeb0e1ec7e2714b3d6147c13c2af04d8d8118219541ec60b66df6919858dc7'\nKEYMAPPING_CONTEXT_01_LINE_0021=ROUTER_TARGET_SHA='4f9da1283166a1e9f4e6bc7dd240c76aef85772177f717f92abb6e8e2bb8de90'\nKEYMAPPING_CONTEXT_01_LINE_0022=ROUTER_FINGERPRINT='SHA256:2Tw4CU4kvwtXSIiym+699Y6W2VJVWzRUD4opXrSfOIs'\nKEYMAPPING_CONTEXT_01_LINE_0023=ROUTER_KNOWN_HOSTS_SHA='02d4e1dad1620937b7a67416a73aa182f9e80ea9c4b11f777161bc7455cf234d'\nKEYMAPPING_CONTEXT_01_LINE_0024=OPERATOR_KEY_FINGERPRINT='SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0'\nKEYMAPPING_CONTEXT_02_RANGE=153-168\nKEYMAPPING_CONTEXT_02_LINE_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]:\nKEYMAPPING_CONTEXT_02_LINE_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112})\nKEYMAPPING_CONTEXT_02_LINE_0155=for node in ('pve01','pve02','pve03'):\nKEYMAPPING_CONTEXT_02_LINE_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'})\nKEYMAPPING_CONTEXT_02_LINE_0157=out += [\nKEYMAPPING_CONTEXT_02_LINE_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0162=]\nKEYMAPPING_CONTEXT_02_LINE_0163=sites=[\nKEYMAPPING_CONTEXT_02_LINE_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'),\nKEYMAPPING_CONTEXT_03_RANGE=384-397\nKEYMAPPING_CONTEXT_03_LINE_0384=if not names: raise BackupError('TAR_ZST_EMPTY')\nKEYMAPPING_CONTEXT_03_LINE_0385=if required_member and required_member not in names: raise BackupError('REQUIRED_MEMBER_MISSING')\nKEYMAPPING_CONTEXT_03_LINE_0386=\nKEYMAPPING_CONTEXT_03_LINE_0387=def validate_payload(t,path):\nKEYMAPPING_CONTEXT_03_LINE_0388=typ=t['type']\nKEYMAPPING_CONTEXT_03_LINE_0389=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'):\nKEYMAPPING_CONTEXT_03_LINE_0390=validate_tar_zst(path)\nKEYMAPPING_CONTEXT_03_LINE_0391=elif typ=='pve_guest':\nKEYMAPPING_CONTEXT_03_LINE_0392=if t['guest_type']=='lxc': validate_tar_zst(path)\nKEYMAPPING_CONTEXT_03_LINE_0393=else:\nKEYMAPPING_CONTEXT_03_LINE_0394=# Green set is intentionally CT-only. Scheduled QEMU backups still get dual remote byte readback.\nKEYMAPPING_CONTEXT_03_LINE_0395=run([shutil.which('zstd') or '/usr/bin/zstd','-t','-q',str(path)],timeout=600)\nKEYMAPPING_CONTEXT_03_LINE_0396=elif typ=='xenforo':\nKEYMAPPING_CONTEXT_03_LINE_0397=validate_tar_zst(path,'db.sql')\nKEYMAPPING_CONTEXT_04_RANGE=547-560\nKEYMAPPING_CONTEXT_04_LINE_0547=m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s)\nKEYMAPPING_CONTEXT_04_LINE_0548=if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH')\nKEYMAPPING_CONTEXT_04_LINE_0549=return m.group(1)\nKEYMAPPING_CONTEXT_04_LINE_0550=\nKEYMAPPING_CONTEXT_04_LINE_0551=def scan_hostkey_line(host,port,expected):\nKEYMAPPING_CONTEXT_04_LINE_0552=p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15)\nKEYMAPPING_CONTEXT_04_LINE_0553=lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')]\nKEYMAPPING_CONTEXT_04_LINE_0554=good=[]\nKEYMAPPING_CONTEXT_04_LINE_0555=for line in lines:\nKEYMAPPING_CONTEXT_04_LINE_0556=f=line.split()\nKEYMAPPING_CONTEXT_04_LINE_0557=if len(f)<3 or f[1]!='ssh-ed25519': continue\nKEYMAPPING_CONTEXT_04_LINE_0558=try: blob=base64.b64decode(f[2])\nKEYMAPPING_CONTEXT_04_LINE_0559=except Exception: continue\nKEYMAPPING_CONTEXT_04_LINE_0560=fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=')\nKEYMAPPING_CONTEXT_05_RANGE=563-576\nKEYMAPPING_CONTEXT_05_LINE_0563=return good[0]\nKEYMAPPING_CONTEXT_05_LINE_0564=\nKEYMAPPING_CONTEXT_05_LINE_0565=def ensure_vps_known_hosts(targets):\nKEYMAPPING_CONTEXT_05_LINE_0566=lines=[]\nKEYMAPPING_CONTEXT_05_LINE_0567=for t in targets:\nKEYMAPPING_CONTEXT_05_LINE_0568=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue\nKEYMAPPING_CONTEXT_05_LINE_0569=lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint']))\nKEYMAPPING_CONTEXT_05_LINE_0570=atomic_write(VPS_KNOWN_HOSTS,('\\n'.join(lines)+'\\n').encode(),0o600)\nKEYMAPPING_CONTEXT_05_LINE_0571=\nKEYMAPPING_CONTEXT_05_LINE_0572=def vps_ssh_argv(t, *, use_agent=False):\nKEYMAPPING_CONTEXT_05_LINE_0573=a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15']\nKEYMAPPING_CONTEXT_05_LINE_0574=if use_agent:\nKEYMAPPING_CONTEXT_05_LINE_0575=a += ['-o','IdentitiesOnly=no']\nKEYMAPPING_CONTEXT_05_LINE_0576=else:\nKEYMAPPING_CONTEXT_06_RANGE=586-629\nKEYMAPPING_CONTEXT_06_LINE_0586=operator_key_fingerprint()\nKEYMAPPING_CONTEXT_06_LINE_0587=ensure_vps_known_hosts(targets)\nKEYMAPPING_CONTEXT_06_LINE_0588=pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\\n'\nKEYMAPPING_CONTEXT_06_LINE_0589=results={}\nKEYMAPPING_CONTEXT_06_LINE_0590=for t in targets:\nKEYMAPPING_CONTEXT_06_LINE_0591=if t['type'] not in ('vps_md','vps_spb'): continue\nKEYMAPPING_CONTEXT_06_LINE_0592=probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False)\nKEYMAPPING_CONTEXT_06_LINE_0593=if probe.returncode==0:\nKEYMAPPING_CONTEXT_06_LINE_0594=results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue\nKEYMAPPING_CONTEXT_06_LINE_0595=if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP')\nKEYMAPPING_CONTEXT_06_LINE_0596=script=b\"umask 077; mkdir -p \\\"$HOME/.ssh\\\"; chmod 700 \\\"$HOME/.ssh\\\"; touch \\\"$HOME/.ssh/authorized_keys\\\"; chmod 600 \\\"$HOME/.ssh/authorized_keys\\\"; IFS= read -r k; if grep -qF -- \\\"$k\\\" \\\"$HOME/.ssh/authorized_keys\\\"; then printf 'ALREADY\\\\n'; else printf '%s\\\\n' \\\"$k\\\" >> \\\"$HOME/.ssh/authorized_keys\\\"; printf 'ADDED\\\\n'; fi\"\nKEYMAPPING_CONTEXT_06_LINE_0597=p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True)\nKEYMAPPING_CONTEXT_06_LINE_0598=tag=p.stdout.decode().strip()\nKEYMAPPING_CONTEXT_06_LINE_0599=if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT')\nKEYMAPPING_CONTEXT_06_LINE_0600=vps_run(t,['true'],timeout=30,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0601=results[t['logical_id']]=tag\nKEYMAPPING_CONTEXT_06_LINE_0602=# US was already operator-key based; prove it agentless too.\nKEYMAPPING_CONTEXT_06_LINE_0603=us=[x for x in targets if x['type']=='vps_us'][0]\nKEYMAPPING_CONTEXT_06_LINE_0604=vps_run(us,['true'],timeout=30,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0605=results[us['logical_id']]='ALREADY_US_OPERATOR_KEY'\nKEYMAPPING_CONTEXT_06_LINE_0606=return results\nKEYMAPPING_CONTEXT_06_LINE_0607=\nKEYMAPPING_CONTEXT_06_LINE_0608=def remote_hashset(t,command):\nKEYMAPPING_CONTEXT_06_LINE_0609=p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0610=return sha256_bytes(p.stdout)\nKEYMAPPING_CONTEXT_06_LINE_0611=\nKEYMAPPING_CONTEXT_06_LINE_0612=def capture_vps_md(t,gen,work):\nKEYMAPPING_CONTEXT_06_LINE_0613=files=['etc/netbird/install.conf','var/lib/netbird/state.json','var/lib/netbird/service.json','var/lib/netbird/active_profile.json','var/lib/netbird/default.json']\nKEYMAPPING_CONTEXT_06_LINE_0614=cmd=\"sudo -n sha256sum -- \"+' '.join(shlex.quote('/'+x) for x in files)\nKEYMAPPING_CONTEXT_06_LINE_0615=pre=remote_hashset(t,cmd)\nKEYMAPPING_CONTEXT_06_LINE_0616=remote=shlex.join(['sudo','-n','tar','--numeric-owner','-C','/','-cf','-']+files)\nKEYMAPPING_CONTEXT_06_LINE_0617=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_06_LINE_0618=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=600)\nKEYMAPPING_CONTEXT_06_LINE_0619=post=remote_hashset(t,cmd)\nKEYMAPPING_CONTEXT_06_LINE_0620=if pre!=post: raise BackupError('MD_SOURCE_CHANGED_DURING_CAPTURE')\nKEYMAPPING_CONTEXT_06_LINE_0621=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None\nKEYMAPPING_CONTEXT_06_LINE_0622=\nKEYMAPPING_CONTEXT_06_LINE_0623=def capture_vps_spb(t,gen,work):\nKEYMAPPING_CONTEXT_06_LINE_0624=hcmd=\"find /etc/nginx -xdev -type f -print0 | sort -z | xargs -0 sha256sum\"\nKEYMAPPING_CONTEXT_06_LINE_0625=pre=remote_hashset(t,hcmd)\nKEYMAPPING_CONTEXT_06_LINE_0626=remote=shlex.join(['tar','--numeric-owner','-C','/','-cf','-','etc/nginx'])\nKEYMAPPING_CONTEXT_06_LINE_0627=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_06_LINE_0628=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=900)\nKEYMAPPING_CONTEXT_06_LINE_0629=post=remote_hashset(t,hcmd)\nKEYMAPPING_CONTEXT_07_RANGE=657-674\nKEYMAPPING_CONTEXT_07_LINE_0657=if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33)\nKEYMAPPING_CONTEXT_07_LINE_0658=b=dst.serialize(); dst.close(); src.close()\nKEYMAPPING_CONTEXT_07_LINE_0659=ti=tarfile.TarInfo(name=('sqlite-backups/'+name)); ti.size=len(b); ti.mode=0o600; ti.mtime=int(time.time()); tf.addfile(ti,io.BytesIO(b))\nKEYMAPPING_CONTEXT_07_LINE_0660='''\nKEYMAPPING_CONTEXT_07_LINE_0661=\nKEYMAPPING_CONTEXT_07_LINE_0662=def capture_vps_us(t,gen,work):\nKEYMAPPING_CONTEXT_07_LINE_0663=remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT])\nKEYMAPPING_CONTEXT_07_LINE_0664=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_07_LINE_0665=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200)\nKEYMAPPING_CONTEXT_07_LINE_0666=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None\nKEYMAPPING_CONTEXT_07_LINE_0667=\nKEYMAPPING_CONTEXT_07_LINE_0668=def _simple_shell_assignments(text):\nKEYMAPPING_CONTEXT_07_LINE_0669=vals={}\nKEYMAPPING_CONTEXT_07_LINE_0670=for line in text.splitlines():\nKEYMAPPING_CONTEXT_07_LINE_0671=m=re.match(r'^\\s*(?:export\\s+)?([A-Z_][A-Z0-9_]*)=(.*)$',line)\nKEYMAPPING_CONTEXT_07_LINE_0672=if not m: continue\nKEYMAPPING_CONTEXT_07_LINE_0673=v=m.group(2).strip()\nKEYMAPPING_CONTEXT_07_LINE_0674=if len(v)>=2 and v[0]==v[-1] and v[0] in ('\\\"',\"'\"): v=v[1:-1]\nKEYMAPPING_CONTEXT_08_RANGE=846-860\nKEYMAPPING_CONTEXT_08_LINE_0846=return local,{'generation':gen,'source_class':'xenforo','site':t['slug'],'vmid':t['vmid'],'node':t['node'],'dump_strategy':t['dump_strategy'],'db_dump_bytes':j.get('db_bytes')},None\nKEYMAPPING_CONTEXT_08_LINE_0847=\nKEYMAPPING_CONTEXT_08_LINE_0848=def node_bundle_paths(node):\nKEYMAPPING_CONTEXT_08_LINE_0849=p=['etc/network/interfaces','etc/hosts','etc/resolv.conf','etc/hostname','etc/pve/corosync.conf','etc/pve/storage.cfg','etc/pve/user.cfg','etc/pve/datacenter.cfg','etc/pve/firewall','etc/pve/nodes/'+node,'etc/apt/sources.list.d']\nKEYMAPPING_CONTEXT_08_LINE_0850=if node=='pve01':\nKEYMAPPING_CONTEXT_08_LINE_0851=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator')\nKEYMAPPING_CONTEXT_08_LINE_0852=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub')\nKEYMAPPING_CONTEXT_08_LINE_0853=return p\nKEYMAPPING_CONTEXT_08_LINE_0854=\nKEYMAPPING_CONTEXT_08_LINE_0855=def capture_node_bundle(t,gen,work):\nKEYMAPPING_CONTEXT_08_LINE_0856=node=t['node']; raw=node_bundle_paths(node); paths=[]\nKEYMAPPING_CONTEXT_08_LINE_0857=for rel in raw:\nKEYMAPPING_CONTEXT_08_LINE_0858=if node=='pve01': ok=(pathlib.Path('/')/rel).exists()\nKEYMAPPING_CONTEXT_08_LINE_0859=else: ok=(ssh_remote(node,['test','-e','/'+rel],timeout=20,check=False).returncode==0)\nKEYMAPPING_CONTEXT_08_LINE_0860=if ok: paths.append(rel)\nKEYMAPPING_CONTEXT_09_RANGE=870-885\nKEYMAPPING_CONTEXT_09_LINE_0870=\nKEYMAPPING_CONTEXT_09_LINE_0871=def capture_target(t,gen,work):\nKEYMAPPING_CONTEXT_09_LINE_0872=typ=t['type']\nKEYMAPPING_CONTEXT_09_LINE_0873=if typ=='pve_guest': return capture_pve_guest(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0874=if typ=='pve_node_bundle': return capture_node_bundle(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0875=if typ=='vps_md': return capture_vps_md(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0876=if typ=='vps_spb': return capture_vps_spb(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0877=if typ=='vps_us': return capture_vps_us(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0878=if typ=='router': return capture_router(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0879=if typ=='xenforo': return capture_xenforo(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0880=raise BackupError('CAPTURE_TYPE_UNKNOWN')\nKEYMAPPING_CONTEXT_09_LINE_0881=\nKEYMAPPING_CONTEXT_09_LINE_0882=def cleanup_source(cleanup):\nKEYMAPPING_CONTEXT_09_LINE_0883=if not cleanup: return\nKEYMAPPING_CONTEXT_09_LINE_0884=if cleanup.get('kind')=='pve_source_dir':\nKEYMAPPING_CONTEXT_09_LINE_0885=ssh_remote(cleanup['node'],['rm','-rf','--',cleanup['path']],timeout=60)\nKEYMAPPING_RELEVANT_LINE_COUNT=15\nKEYMAPPING_RELEVANT_01_LINE=16\nKEYMAPPING_RELEVANT_01_TEXT=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH]\nKEYMAPPING_RELEVANT_02_LINE=158\nKEYMAPPING_RELEVANT_02_TEXT={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_RELEVANT_03_LINE=160\nKEYMAPPING_RELEVANT_03_TEXT={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_RELEVANT_04_LINE=389\nKEYMAPPING_RELEVANT_04_TEXT=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'):\nKEYMAPPING_RELEVANT_05_LINE=568\nKEYMAPPING_RELEVANT_05_TEXT=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue\nKEYMAPPING_RELEVANT_06_LINE=591\nKEYMAPPING_RELEVANT_06_TEXT=if t['type'] not in ('vps_md','vps_spb'): continue\nKEYMAPPING_RELEVANT_07_LINE=603\nKEYMAPPING_RELEVANT_07_TEXT=us=[x for x in targets if x['type']=='vps_us'][0]\nKEYMAPPING_RELEVANT_08_LINE=612\nKEYMAPPING_RELEVANT_08_TEXT=def capture_vps_md(t,gen,work):\nKEYMAPPING_RELEVANT_09_LINE=621\nKEYMAPPING_RELEVANT_09_TEXT=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None\nKEYMAPPING_RELEVANT_10_LINE=662\nKEYMAPPING_RELEVANT_10_TEXT=def capture_vps_us(t,gen,work):\nKEYMAPPING_RELEVANT_11_LINE=666\nKEYMAPPING_RELEVANT_11_TEXT=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None\nKEYMAPPING_RELEVANT_12_LINE=851\nKEYMAPPING_RELEVANT_12_TEXT=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator')\nKEYMAPPING_RELEVANT_13_LINE=852\nKEYMAPPING_RELEVANT_13_TEXT=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub')\nKEYMAPPING_RELEVANT_14_LINE=875\nKEYMAPPING_RELEVANT_14_TEXT=if typ=='vps_md': return capture_vps_md(t,gen,work)\nKEYMAPPING_RELEVANT_15_LINE=877\nKEYMAPPING_RELEVANT_15_TEXT=if typ=='vps_us': return capture_vps_us(t,gen,work)\nPVE1_KEY_ID_ED25519_PRESENT=True\nPVE1_KEY_ID_ED25519_FP=SHA256:s0CusF0IHQGVJ02oi7ejWkGhH9NkhTWonn3441toe5M\nPVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_PRESENT=True\nPVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_FP=SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0\nVPS552R1_DECISION=HOLD_KEY_MAPPING_AMBIGUOUS\nVPS552R1_NEXT_GATE=PVE1_ACCEPTED_ENGINE_CALLPATH_PARSE\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1\",\"status\":\"OK\",\"changes_made\":false,\"rollback_started\":false,\"rollback_restored\":null}\n" +} diff --git a/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.txt b/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.txt new file mode 100644 index 00000000..83e236a4 --- /dev/null +++ b/runtime/history/SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1.txt @@ -0,0 +1,253 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1 +STATUS=OK +RC=0 +HOST=pve01 +MODE=read-only +COMPONENT=infra-pve1-moldova-keymapping-readonly +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 +COMMAND_SHA256=0fadfaf45ded2524c42751f3efe29300f054f11e12b445ef897607a6f6b3e448 +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=b3e7cbda886dbd253274af0d4c726c89e54425e5b793e9e1f149ea8412962c14 +SANITIZED_OUTPUT_SHA256=be1cde014d4680574aba7cefa652231f34f1db8d57c07b09e171b79b88530186 +OUTPUT_BEGIN +ERROR_REGISTER_CHECK=OK +REFERENCE_CHECK=OK +AUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED +ACCEPTED_ENGINE_PRESENT=True +ACCEPTED_ENGINE_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7 +KEYMAPPING_MATCH_LINE_COUNT=17 +KEYMAPPING_MATCH_LINES=14,16,158,160,389,552,568,591,603,612,621,662,666,851,852,875,877 +KEYMAPPING_CONTEXT_01_RANGE=9-24 +KEYMAPPING_CONTEXT_01_LINE_0009=WORK_ROOT=pathlib.Path('/mnt/staging/homelab-backup-v2') +KEYMAPPING_CONTEXT_01_LINE_0010=ENGINE_PATH=pathlib.Path('/usr/local/sbin/homelab-backup-v2') +KEYMAPPING_CONTEXT_01_LINE_0011=RCLONE=shutil.which('rclone') or '/usr/bin/rclone' +KEYMAPPING_CONTEXT_01_LINE_0012=SSH=shutil.which('ssh') or '/usr/bin/ssh' +KEYMAPPING_CONTEXT_01_LINE_0013=SCP=shutil.which('scp') or '/usr/bin/scp' +KEYMAPPING_CONTEXT_01_LINE_0014=SSH_KEYSCAN=shutil.which('ssh-keyscan') or '/usr/bin/ssh-keyscan' +KEYMAPPING_CONTEXT_01_LINE_0015=SSHPASS=shutil.which('sshpass') or '/usr/bin/sshpass' +KEYMAPPING_CONTEXT_01_LINE_0016=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH] +KEYMAPPING_CONTEXT_01_LINE_0017=VPS_KNOWN_HOSTS=CONFIG_ROOT/'vps_known_hosts' +KEYMAPPING_CONTEXT_01_LINE_0018=ROUTER_KNOWN_HOSTS=CONFIG_ROOT/'router_known_hosts' +KEYMAPPING_CONTEXT_01_LINE_0019=ROUTER_LEGACY_SCRIPT=pathlib.Path('/usr/local/sbin/homelab-router-running-config-mail-cloud') +KEYMAPPING_CONTEXT_01_LINE_0020=ROUTER_LEGACY_SHA='a0aeb0e1ec7e2714b3d6147c13c2af04d8d8118219541ec60b66df6919858dc7' +KEYMAPPING_CONTEXT_01_LINE_0021=ROUTER_TARGET_SHA='4f9da1283166a1e9f4e6bc7dd240c76aef85772177f717f92abb6e8e2bb8de90' +KEYMAPPING_CONTEXT_01_LINE_0022=ROUTER_FINGERPRINT='SHA256:2Tw4CU4kvwtXSIiym+699Y6W2VJVWzRUD4opXrSfOIs' +KEYMAPPING_CONTEXT_01_LINE_0023=ROUTER_KNOWN_HOSTS_SHA='02d4e1dad1620937b7a67416a73aa182f9e80ea9c4b11f777161bc7455cf234d' +KEYMAPPING_CONTEXT_01_LINE_0024=OPERATOR_KEY_FINGERPRINT='SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0' +KEYMAPPING_CONTEXT_02_RANGE=153-168 +KEYMAPPING_CONTEXT_02_LINE_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]: +KEYMAPPING_CONTEXT_02_LINE_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112}) +KEYMAPPING_CONTEXT_02_LINE_0155=for node in ('pve01','pve02','pve03'): +KEYMAPPING_CONTEXT_02_LINE_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'}) +KEYMAPPING_CONTEXT_02_LINE_0157=out += [ +KEYMAPPING_CONTEXT_02_LINE_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0162=] +KEYMAPPING_CONTEXT_02_LINE_0163=sites=[ +KEYMAPPING_CONTEXT_02_LINE_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'), +KEYMAPPING_CONTEXT_03_RANGE=384-397 +KEYMAPPING_CONTEXT_03_LINE_0384=if not names: raise BackupError('TAR_ZST_EMPTY') +KEYMAPPING_CONTEXT_03_LINE_0385=if required_member and required_member not in names: raise BackupError('REQUIRED_MEMBER_MISSING') +KEYMAPPING_CONTEXT_03_LINE_0386= +KEYMAPPING_CONTEXT_03_LINE_0387=def validate_payload(t,path): +KEYMAPPING_CONTEXT_03_LINE_0388=typ=t['type'] +KEYMAPPING_CONTEXT_03_LINE_0389=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'): +KEYMAPPING_CONTEXT_03_LINE_0390=validate_tar_zst(path) +KEYMAPPING_CONTEXT_03_LINE_0391=elif typ=='pve_guest': +KEYMAPPING_CONTEXT_03_LINE_0392=if t['guest_type']=='lxc': validate_tar_zst(path) +KEYMAPPING_CONTEXT_03_LINE_0393=else: +KEYMAPPING_CONTEXT_03_LINE_0394=# Green set is intentionally CT-only. Scheduled QEMU backups still get dual remote byte readback. +KEYMAPPING_CONTEXT_03_LINE_0395=run([shutil.which('zstd') or '/usr/bin/zstd','-t','-q',str(path)],timeout=600) +KEYMAPPING_CONTEXT_03_LINE_0396=elif typ=='xenforo': +KEYMAPPING_CONTEXT_03_LINE_0397=validate_tar_zst(path,'db.sql') +KEYMAPPING_CONTEXT_04_RANGE=547-560 +KEYMAPPING_CONTEXT_04_LINE_0547=m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s) +KEYMAPPING_CONTEXT_04_LINE_0548=if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH') +KEYMAPPING_CONTEXT_04_LINE_0549=return m.group(1) +KEYMAPPING_CONTEXT_04_LINE_0550= +KEYMAPPING_CONTEXT_04_LINE_0551=def scan_hostkey_line(host,port,expected): +KEYMAPPING_CONTEXT_04_LINE_0552=p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15) +KEYMAPPING_CONTEXT_04_LINE_0553=lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')] +KEYMAPPING_CONTEXT_04_LINE_0554=good=[] +KEYMAPPING_CONTEXT_04_LINE_0555=for line in lines: +KEYMAPPING_CONTEXT_04_LINE_0556=f=line.split() +KEYMAPPING_CONTEXT_04_LINE_0557=if len(f)<3 or f[1]!='ssh-ed25519': continue +KEYMAPPING_CONTEXT_04_LINE_0558=try: blob=base64.b64decode(f[2]) +KEYMAPPING_CONTEXT_04_LINE_0559=except Exception: continue +KEYMAPPING_CONTEXT_04_LINE_0560=fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=') +KEYMAPPING_CONTEXT_05_RANGE=563-576 +KEYMAPPING_CONTEXT_05_LINE_0563=return good[0] +KEYMAPPING_CONTEXT_05_LINE_0564= +KEYMAPPING_CONTEXT_05_LINE_0565=def ensure_vps_known_hosts(targets): +KEYMAPPING_CONTEXT_05_LINE_0566=lines=[] +KEYMAPPING_CONTEXT_05_LINE_0567=for t in targets: +KEYMAPPING_CONTEXT_05_LINE_0568=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue +KEYMAPPING_CONTEXT_05_LINE_0569=lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint'])) +KEYMAPPING_CONTEXT_05_LINE_0570=atomic_write(VPS_KNOWN_HOSTS,('\n'.join(lines)+'\n').encode(),0o600) +KEYMAPPING_CONTEXT_05_LINE_0571= +KEYMAPPING_CONTEXT_05_LINE_0572=def vps_ssh_argv(t, *, use_agent=False): +KEYMAPPING_CONTEXT_05_LINE_0573=a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15'] +KEYMAPPING_CONTEXT_05_LINE_0574=if use_agent: +KEYMAPPING_CONTEXT_05_LINE_0575=a += ['-o','IdentitiesOnly=no'] +KEYMAPPING_CONTEXT_05_LINE_0576=else: +KEYMAPPING_CONTEXT_06_RANGE=586-629 +KEYMAPPING_CONTEXT_06_LINE_0586=operator_key_fingerprint() +KEYMAPPING_CONTEXT_06_LINE_0587=ensure_vps_known_hosts(targets) +KEYMAPPING_CONTEXT_06_LINE_0588=pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\n' +KEYMAPPING_CONTEXT_06_LINE_0589=results={} +KEYMAPPING_CONTEXT_06_LINE_0590=for t in targets: +KEYMAPPING_CONTEXT_06_LINE_0591=if t['type'] not in ('vps_md','vps_spb'): continue +KEYMAPPING_CONTEXT_06_LINE_0592=probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False) +KEYMAPPING_CONTEXT_06_LINE_0593=if probe.returncode==0: +KEYMAPPING_CONTEXT_06_LINE_0594=results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue +KEYMAPPING_CONTEXT_06_LINE_0595=if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP') +KEYMAPPING_CONTEXT_06_LINE_0596=script=b"umask 077; mkdir -p \"$HOME/.ssh\"; chmod 700 \"$HOME/.ssh\"; touch \"$HOME/.ssh/authorized_keys\"; chmod 600 \"$HOME/.ssh/authorized_keys\"; IFS= read -r k; if grep -qF -- \"$k\" \"$HOME/.ssh/authorized_keys\"; then printf 'ALREADY\\n'; else printf '%s\\n' \"$k\" >> \"$HOME/.ssh/authorized_keys\"; printf 'ADDED\\n'; fi" +KEYMAPPING_CONTEXT_06_LINE_0597=p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True) +KEYMAPPING_CONTEXT_06_LINE_0598=tag=p.stdout.decode().strip() +KEYMAPPING_CONTEXT_06_LINE_0599=if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT') +KEYMAPPING_CONTEXT_06_LINE_0600=vps_run(t,['true'],timeout=30,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0601=results[t['logical_id']]=tag +KEYMAPPING_CONTEXT_06_LINE_0602=# US was already operator-key based; prove it agentless too. +KEYMAPPING_CONTEXT_06_LINE_0603=us=[x for x in targets if x['type']=='vps_us'][0] +KEYMAPPING_CONTEXT_06_LINE_0604=vps_run(us,['true'],timeout=30,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0605=results[us['logical_id']]='ALREADY_US_OPERATOR_KEY' +KEYMAPPING_CONTEXT_06_LINE_0606=return results +KEYMAPPING_CONTEXT_06_LINE_0607= +KEYMAPPING_CONTEXT_06_LINE_0608=def remote_hashset(t,command): +KEYMAPPING_CONTEXT_06_LINE_0609=p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0610=return sha256_bytes(p.stdout) +KEYMAPPING_CONTEXT_06_LINE_0611= +KEYMAPPING_CONTEXT_06_LINE_0612=def capture_vps_md(t,gen,work): +KEYMAPPING_CONTEXT_06_LINE_0613=files=['etc/netbird/install.conf','var/lib/netbird/state.json','var/lib/netbird/service.json','var/lib/netbird/active_profile.json','var/lib/netbird/default.json'] +KEYMAPPING_CONTEXT_06_LINE_0614=cmd="sudo -n sha256sum -- "+' '.join(shlex.quote('/'+x) for x in files) +KEYMAPPING_CONTEXT_06_LINE_0615=pre=remote_hashset(t,cmd) +KEYMAPPING_CONTEXT_06_LINE_0616=remote=shlex.join(['sudo','-n','tar','--numeric-owner','-C','/','-cf','-']+files) +KEYMAPPING_CONTEXT_06_LINE_0617=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_06_LINE_0618=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=600) +KEYMAPPING_CONTEXT_06_LINE_0619=post=remote_hashset(t,cmd) +KEYMAPPING_CONTEXT_06_LINE_0620=if pre!=post: raise BackupError('MD_SOURCE_CHANGED_DURING_CAPTURE') +KEYMAPPING_CONTEXT_06_LINE_0621=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None +KEYMAPPING_CONTEXT_06_LINE_0622= +KEYMAPPING_CONTEXT_06_LINE_0623=def capture_vps_spb(t,gen,work): +KEYMAPPING_CONTEXT_06_LINE_0624=hcmd="find /etc/nginx -xdev -type f -print0 | sort -z | xargs -0 sha256sum" +KEYMAPPING_CONTEXT_06_LINE_0625=pre=remote_hashset(t,hcmd) +KEYMAPPING_CONTEXT_06_LINE_0626=remote=shlex.join(['tar','--numeric-owner','-C','/','-cf','-','etc/nginx']) +KEYMAPPING_CONTEXT_06_LINE_0627=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_06_LINE_0628=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=900) +KEYMAPPING_CONTEXT_06_LINE_0629=post=remote_hashset(t,hcmd) +KEYMAPPING_CONTEXT_07_RANGE=657-674 +KEYMAPPING_CONTEXT_07_LINE_0657=if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33) +KEYMAPPING_CONTEXT_07_LINE_0658=b=dst.serialize(); dst.close(); src.close() +KEYMAPPING_CONTEXT_07_LINE_0659=ti=tarfile.TarInfo(name=('sqlite-backups/'+name)); ti.size=len(b); ti.mode=0o600; ti.mtime=int(time.time()); tf.addfile(ti,io.BytesIO(b)) +KEYMAPPING_CONTEXT_07_LINE_0660=''' +KEYMAPPING_CONTEXT_07_LINE_0661= +KEYMAPPING_CONTEXT_07_LINE_0662=def capture_vps_us(t,gen,work): +KEYMAPPING_CONTEXT_07_LINE_0663=remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT]) +KEYMAPPING_CONTEXT_07_LINE_0664=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_07_LINE_0665=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200) +KEYMAPPING_CONTEXT_07_LINE_0666=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None +KEYMAPPING_CONTEXT_07_LINE_0667= +KEYMAPPING_CONTEXT_07_LINE_0668=def _simple_shell_assignments(text): +KEYMAPPING_CONTEXT_07_LINE_0669=vals={} +KEYMAPPING_CONTEXT_07_LINE_0670=for line in text.splitlines(): +KEYMAPPING_CONTEXT_07_LINE_0671=m=re.match(r'^\s*(?:export\s+)?([A-Z_][A-Z0-9_]*)=(.*)$',line) +KEYMAPPING_CONTEXT_07_LINE_0672=if not m: continue +KEYMAPPING_CONTEXT_07_LINE_0673=v=m.group(2).strip() +KEYMAPPING_CONTEXT_07_LINE_0674=if len(v)>=2 and v[0]==v[-1] and v[0] in ('\"',"'"): v=v[1:-1] +KEYMAPPING_CONTEXT_08_RANGE=846-860 +KEYMAPPING_CONTEXT_08_LINE_0846=return local,{'generation':gen,'source_class':'xenforo','site':t['slug'],'vmid':t['vmid'],'node':t['node'],'dump_strategy':t['dump_strategy'],'db_dump_bytes':j.get('db_bytes')},None +KEYMAPPING_CONTEXT_08_LINE_0847= +KEYMAPPING_CONTEXT_08_LINE_0848=def node_bundle_paths(node): +KEYMAPPING_CONTEXT_08_LINE_0849=p=['etc/network/interfaces','etc/hosts','etc/resolv.conf','etc/hostname','etc/pve/corosync.conf','etc/pve/storage.cfg','etc/pve/user.cfg','etc/pve/datacenter.cfg','etc/pve/firewall','etc/pve/nodes/'+node,'etc/apt/sources.list.d'] +KEYMAPPING_CONTEXT_08_LINE_0850=if node=='pve01': +KEYMAPPING_CONTEXT_08_LINE_0851=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator') +KEYMAPPING_CONTEXT_08_LINE_0852=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub') +KEYMAPPING_CONTEXT_08_LINE_0853=return p +KEYMAPPING_CONTEXT_08_LINE_0854= +KEYMAPPING_CONTEXT_08_LINE_0855=def capture_node_bundle(t,gen,work): +KEYMAPPING_CONTEXT_08_LINE_0856=node=t['node']; raw=node_bundle_paths(node); paths=[] +KEYMAPPING_CONTEXT_08_LINE_0857=for rel in raw: +KEYMAPPING_CONTEXT_08_LINE_0858=if node=='pve01': ok=(pathlib.Path('/')/rel).exists() +KEYMAPPING_CONTEXT_08_LINE_0859=else: ok=(ssh_remote(node,['test','-e','/'+rel],timeout=20,check=False).returncode==0) +KEYMAPPING_CONTEXT_08_LINE_0860=if ok: paths.append(rel) +KEYMAPPING_CONTEXT_09_RANGE=870-885 +KEYMAPPING_CONTEXT_09_LINE_0870= +KEYMAPPING_CONTEXT_09_LINE_0871=def capture_target(t,gen,work): +KEYMAPPING_CONTEXT_09_LINE_0872=typ=t['type'] +KEYMAPPING_CONTEXT_09_LINE_0873=if typ=='pve_guest': return capture_pve_guest(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0874=if typ=='pve_node_bundle': return capture_node_bundle(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0875=if typ=='vps_md': return capture_vps_md(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0876=if typ=='vps_spb': return capture_vps_spb(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0877=if typ=='vps_us': return capture_vps_us(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0878=if typ=='router': return capture_router(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0879=if typ=='xenforo': return capture_xenforo(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0880=raise BackupError('CAPTURE_TYPE_UNKNOWN') +KEYMAPPING_CONTEXT_09_LINE_0881= +KEYMAPPING_CONTEXT_09_LINE_0882=def cleanup_source(cleanup): +KEYMAPPING_CONTEXT_09_LINE_0883=if not cleanup: return +KEYMAPPING_CONTEXT_09_LINE_0884=if cleanup.get('kind')=='pve_source_dir': +KEYMAPPING_CONTEXT_09_LINE_0885=ssh_remote(cleanup['node'],['rm','-rf','--',cleanup['path']],timeout=60) +KEYMAPPING_RELEVANT_LINE_COUNT=15 +KEYMAPPING_RELEVANT_01_LINE=16 +KEYMAPPING_RELEVANT_01_TEXT=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH] +KEYMAPPING_RELEVANT_02_LINE=158 +KEYMAPPING_RELEVANT_02_TEXT={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_RELEVANT_03_LINE=160 +KEYMAPPING_RELEVANT_03_TEXT={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_RELEVANT_04_LINE=389 +KEYMAPPING_RELEVANT_04_TEXT=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'): +KEYMAPPING_RELEVANT_05_LINE=568 +KEYMAPPING_RELEVANT_05_TEXT=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue +KEYMAPPING_RELEVANT_06_LINE=591 +KEYMAPPING_RELEVANT_06_TEXT=if t['type'] not in ('vps_md','vps_spb'): continue +KEYMAPPING_RELEVANT_07_LINE=603 +KEYMAPPING_RELEVANT_07_TEXT=us=[x for x in targets if x['type']=='vps_us'][0] +KEYMAPPING_RELEVANT_08_LINE=612 +KEYMAPPING_RELEVANT_08_TEXT=def capture_vps_md(t,gen,work): +KEYMAPPING_RELEVANT_09_LINE=621 +KEYMAPPING_RELEVANT_09_TEXT=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None +KEYMAPPING_RELEVANT_10_LINE=662 +KEYMAPPING_RELEVANT_10_TEXT=def capture_vps_us(t,gen,work): +KEYMAPPING_RELEVANT_11_LINE=666 +KEYMAPPING_RELEVANT_11_TEXT=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None +KEYMAPPING_RELEVANT_12_LINE=851 +KEYMAPPING_RELEVANT_12_TEXT=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator') +KEYMAPPING_RELEVANT_13_LINE=852 +KEYMAPPING_RELEVANT_13_TEXT=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub') +KEYMAPPING_RELEVANT_14_LINE=875 +KEYMAPPING_RELEVANT_14_TEXT=if typ=='vps_md': return capture_vps_md(t,gen,work) +KEYMAPPING_RELEVANT_15_LINE=877 +KEYMAPPING_RELEVANT_15_TEXT=if typ=='vps_us': return capture_vps_us(t,gen,work) +PVE1_KEY_ID_ED25519_PRESENT=True +PVE1_KEY_ID_ED25519_FP=SHA256:s0CusF0IHQGVJ02oi7ejWkGhH9NkhTWonn3441toe5M +PVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_PRESENT=True +PVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_FP=SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0 +VPS552R1_DECISION=HOLD_KEY_MAPPING_AMBIGUOUS +VPS552R1_NEXT_GATE=PVE1_ACCEPTED_ENGINE_CALLPATH_PARSE +HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null} + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index fb2a45ba..b3eb570e 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "SUPPORT-260918-INFRA-PVE1-MOLDOVA-ACCEPTED-ENGINE-CONTEXT-READONLY-551R2", + "command_id": "SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", - "component": "infra-pve1-moldova-accepted-engine-context-readonly", - "started_at_utc": "2026-09-18T20:37:43Z", - "finished_at_utc": "2026-09-18T20:37:43Z", + "component": "infra-pve1-moldova-keymapping-readonly", + "started_at_utc": "2026-09-18T20:39:36Z", + "finished_at_utc": "2026-09-18T20:39:36Z", "reference_register_checked": true, "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", "error_register_checked": true, "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", - "command_sha256": "466b431b89ae334593305e1fbbdea6c6a21b439a2568b9ccdbb76fa98c59baa9", + "command_sha256": "0fadfaf45ded2524c42751f3efe29300f054f11e12b445ef897607a6f6b3e448", "duplicate_failed_command_blocked": false, "block_reason": null, "execution_started": true, @@ -30,9 +30,9 @@ "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "ddd844d81c397e39417a2eb7724f43b3b134b5e6019653f7704be4a9a981af07", - "sanitized_output_sha256": "ddd844d81c397e39417a2eb7724f43b3b134b5e6019653f7704be4a9a981af07", + "raw_evidence_sha256": "b3e7cbda886dbd253274af0d4c726c89e54425e5b793e9e1f149ea8412962c14", + "sanitized_output_sha256": "be1cde014d4680574aba7cefa652231f34f1db8d57c07b09e171b79b88530186", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "ERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nACCEPTED_ENGINE_PRESENT=True\nACCEPTED_ENGINE_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7\nMOLDOVA_MATCH_LINE_COUNT=1\nMOLDOVA_MATCH_LINES=160\nMOLDOVA_CONTEXT_RANGE=148-172\nMOLDOVA_CONTEXT_0148=\nMOLDOVA_CONTEXT_0149=def default_targets():\nMOLDOVA_CONTEXT_0150=d=86400\nMOLDOVA_CONTEXT_0151=out=[]\nMOLDOVA_CONTEXT_0152=# PVE guests. Source node is resolved live every run.\nMOLDOVA_CONTEXT_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]:\nMOLDOVA_CONTEXT_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112})\nMOLDOVA_CONTEXT_0155=for node in ('pve01','pve02','pve03'):\nMOLDOVA_CONTEXT_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'})\nMOLDOVA_CONTEXT_0157=out += [\nMOLDOVA_CONTEXT_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True},\nMOLDOVA_CONTEXT_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True},\nMOLDOVA_CONTEXT_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True},\nMOLDOVA_CONTEXT_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True},\nMOLDOVA_CONTEXT_0162=]\nMOLDOVA_CONTEXT_0163=sites=[\nMOLDOVA_CONTEXT_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'),\nMOLDOVA_CONTEXT_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'),\nMOLDOVA_CONTEXT_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'),\nMOLDOVA_CONTEXT_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'),\nMOLDOVA_CONTEXT_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'),\nMOLDOVA_CONTEXT_0169=('hkmods',160,'pve02','/var/www/forums/hkmods/public','xf_hkmods','global_read_lock'),\nMOLDOVA_CONTEXT_0170=('zakrutim',160,'pve02','/var/www/forums/zakrutim/public','xf_zakrutim','global_read_lock')]\nMOLDOVA_CONTEXT_0171=for slug,vmid,node,root,db,strategy in sites:\nMOLDOVA_CONTEXT_0172=out.append({'logical_id':'xf-'+slug,'scope':'xenforo','type':'xenforo','slug':slug,'vmid':vmid,'node':node,'app_root':root,'db_name':db,'dump_strategy':strategy,'due_seconds':d,'enabled':True,'green1':slug in ('codevipe','zakrutim')})\nMOLDOVA_MIN_DICT_COUNT=1\nMOLDOVA_DICT_01_LINENO=160\nMOLDOVA_DICT_01_FIELD_HOST=46.16.34.129\nMOLDOVA_DICT_01_FIELD_PORT=22\nMOLDOVA_DICT_01_FIELD_USER=root\nMOLDOVA_DICT_01_FIELD_HOSTKEY_FINGERPRINT=SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE\nMOLDOVA_SAFE_FIELD_COUNT=4\nVPS551R2_DECISION=PASS_ACCEPTED_ENGINE_MOLDOVA_RECORD_FOUND\nVPS551R2_NEXT_GATE=PVE1_MOLDOVA_EXACT_ROUTE_TEST\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-INFRA-PVE1-MOLDOVA-ACCEPTED-ENGINE-CONTEXT-READONLY-551R2\",\"status\":\"OK\",\"changes_made\":false,\"rollback_started\":false,\"rollback_restored\":null}\n" + "output": "ERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nACCEPTED_ENGINE_PRESENT=True\nACCEPTED_ENGINE_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7\nKEYMAPPING_MATCH_LINE_COUNT=17\nKEYMAPPING_MATCH_LINES=14,16,158,160,389,552,568,591,603,612,621,662,666,851,852,875,877\nKEYMAPPING_CONTEXT_01_RANGE=9-24\nKEYMAPPING_CONTEXT_01_LINE_0009=WORK_ROOT=pathlib.Path('/mnt/staging/homelab-backup-v2')\nKEYMAPPING_CONTEXT_01_LINE_0010=ENGINE_PATH=pathlib.Path('/usr/local/sbin/homelab-backup-v2')\nKEYMAPPING_CONTEXT_01_LINE_0011=RCLONE=shutil.which('rclone') or '/usr/bin/rclone'\nKEYMAPPING_CONTEXT_01_LINE_0012=SSH=shutil.which('ssh') or '/usr/bin/ssh'\nKEYMAPPING_CONTEXT_01_LINE_0013=SCP=shutil.which('scp') or '/usr/bin/scp'\nKEYMAPPING_CONTEXT_01_LINE_0014=SSH_KEYSCAN=shutil.which('ssh-keyscan') or '/usr/bin/ssh-keyscan'\nKEYMAPPING_CONTEXT_01_LINE_0015=SSHPASS=shutil.which('sshpass') or '/usr/bin/sshpass'\nKEYMAPPING_CONTEXT_01_LINE_0016=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH]\nKEYMAPPING_CONTEXT_01_LINE_0017=VPS_KNOWN_HOSTS=CONFIG_ROOT/'vps_known_hosts'\nKEYMAPPING_CONTEXT_01_LINE_0018=ROUTER_KNOWN_HOSTS=CONFIG_ROOT/'router_known_hosts'\nKEYMAPPING_CONTEXT_01_LINE_0019=ROUTER_LEGACY_SCRIPT=pathlib.Path('/usr/local/sbin/homelab-router-running-config-mail-cloud')\nKEYMAPPING_CONTEXT_01_LINE_0020=ROUTER_LEGACY_SHA='a0aeb0e1ec7e2714b3d6147c13c2af04d8d8118219541ec60b66df6919858dc7'\nKEYMAPPING_CONTEXT_01_LINE_0021=ROUTER_TARGET_SHA='4f9da1283166a1e9f4e6bc7dd240c76aef85772177f717f92abb6e8e2bb8de90'\nKEYMAPPING_CONTEXT_01_LINE_0022=ROUTER_FINGERPRINT='SHA256:2Tw4CU4kvwtXSIiym+699Y6W2VJVWzRUD4opXrSfOIs'\nKEYMAPPING_CONTEXT_01_LINE_0023=ROUTER_KNOWN_HOSTS_SHA='02d4e1dad1620937b7a67416a73aa182f9e80ea9c4b11f777161bc7455cf234d'\nKEYMAPPING_CONTEXT_01_LINE_0024=OPERATOR_KEY_FINGERPRINT='SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0'\nKEYMAPPING_CONTEXT_02_RANGE=153-168\nKEYMAPPING_CONTEXT_02_LINE_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]:\nKEYMAPPING_CONTEXT_02_LINE_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112})\nKEYMAPPING_CONTEXT_02_LINE_0155=for node in ('pve01','pve02','pve03'):\nKEYMAPPING_CONTEXT_02_LINE_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'})\nKEYMAPPING_CONTEXT_02_LINE_0157=out += [\nKEYMAPPING_CONTEXT_02_LINE_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_CONTEXT_02_LINE_0162=]\nKEYMAPPING_CONTEXT_02_LINE_0163=sites=[\nKEYMAPPING_CONTEXT_02_LINE_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'),\nKEYMAPPING_CONTEXT_02_LINE_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'),\nKEYMAPPING_CONTEXT_03_RANGE=384-397\nKEYMAPPING_CONTEXT_03_LINE_0384=if not names: raise BackupError('TAR_ZST_EMPTY')\nKEYMAPPING_CONTEXT_03_LINE_0385=if required_member and required_member not in names: raise BackupError('REQUIRED_MEMBER_MISSING')\nKEYMAPPING_CONTEXT_03_LINE_0386=\nKEYMAPPING_CONTEXT_03_LINE_0387=def validate_payload(t,path):\nKEYMAPPING_CONTEXT_03_LINE_0388=typ=t['type']\nKEYMAPPING_CONTEXT_03_LINE_0389=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'):\nKEYMAPPING_CONTEXT_03_LINE_0390=validate_tar_zst(path)\nKEYMAPPING_CONTEXT_03_LINE_0391=elif typ=='pve_guest':\nKEYMAPPING_CONTEXT_03_LINE_0392=if t['guest_type']=='lxc': validate_tar_zst(path)\nKEYMAPPING_CONTEXT_03_LINE_0393=else:\nKEYMAPPING_CONTEXT_03_LINE_0394=# Green set is intentionally CT-only. Scheduled QEMU backups still get dual remote byte readback.\nKEYMAPPING_CONTEXT_03_LINE_0395=run([shutil.which('zstd') or '/usr/bin/zstd','-t','-q',str(path)],timeout=600)\nKEYMAPPING_CONTEXT_03_LINE_0396=elif typ=='xenforo':\nKEYMAPPING_CONTEXT_03_LINE_0397=validate_tar_zst(path,'db.sql')\nKEYMAPPING_CONTEXT_04_RANGE=547-560\nKEYMAPPING_CONTEXT_04_LINE_0547=m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s)\nKEYMAPPING_CONTEXT_04_LINE_0548=if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH')\nKEYMAPPING_CONTEXT_04_LINE_0549=return m.group(1)\nKEYMAPPING_CONTEXT_04_LINE_0550=\nKEYMAPPING_CONTEXT_04_LINE_0551=def scan_hostkey_line(host,port,expected):\nKEYMAPPING_CONTEXT_04_LINE_0552=p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15)\nKEYMAPPING_CONTEXT_04_LINE_0553=lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')]\nKEYMAPPING_CONTEXT_04_LINE_0554=good=[]\nKEYMAPPING_CONTEXT_04_LINE_0555=for line in lines:\nKEYMAPPING_CONTEXT_04_LINE_0556=f=line.split()\nKEYMAPPING_CONTEXT_04_LINE_0557=if len(f)<3 or f[1]!='ssh-ed25519': continue\nKEYMAPPING_CONTEXT_04_LINE_0558=try: blob=base64.b64decode(f[2])\nKEYMAPPING_CONTEXT_04_LINE_0559=except Exception: continue\nKEYMAPPING_CONTEXT_04_LINE_0560=fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=')\nKEYMAPPING_CONTEXT_05_RANGE=563-576\nKEYMAPPING_CONTEXT_05_LINE_0563=return good[0]\nKEYMAPPING_CONTEXT_05_LINE_0564=\nKEYMAPPING_CONTEXT_05_LINE_0565=def ensure_vps_known_hosts(targets):\nKEYMAPPING_CONTEXT_05_LINE_0566=lines=[]\nKEYMAPPING_CONTEXT_05_LINE_0567=for t in targets:\nKEYMAPPING_CONTEXT_05_LINE_0568=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue\nKEYMAPPING_CONTEXT_05_LINE_0569=lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint']))\nKEYMAPPING_CONTEXT_05_LINE_0570=atomic_write(VPS_KNOWN_HOSTS,('\\n'.join(lines)+'\\n').encode(),0o600)\nKEYMAPPING_CONTEXT_05_LINE_0571=\nKEYMAPPING_CONTEXT_05_LINE_0572=def vps_ssh_argv(t, *, use_agent=False):\nKEYMAPPING_CONTEXT_05_LINE_0573=a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15']\nKEYMAPPING_CONTEXT_05_LINE_0574=if use_agent:\nKEYMAPPING_CONTEXT_05_LINE_0575=a += ['-o','IdentitiesOnly=no']\nKEYMAPPING_CONTEXT_05_LINE_0576=else:\nKEYMAPPING_CONTEXT_06_RANGE=586-629\nKEYMAPPING_CONTEXT_06_LINE_0586=operator_key_fingerprint()\nKEYMAPPING_CONTEXT_06_LINE_0587=ensure_vps_known_hosts(targets)\nKEYMAPPING_CONTEXT_06_LINE_0588=pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\\n'\nKEYMAPPING_CONTEXT_06_LINE_0589=results={}\nKEYMAPPING_CONTEXT_06_LINE_0590=for t in targets:\nKEYMAPPING_CONTEXT_06_LINE_0591=if t['type'] not in ('vps_md','vps_spb'): continue\nKEYMAPPING_CONTEXT_06_LINE_0592=probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False)\nKEYMAPPING_CONTEXT_06_LINE_0593=if probe.returncode==0:\nKEYMAPPING_CONTEXT_06_LINE_0594=results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue\nKEYMAPPING_CONTEXT_06_LINE_0595=if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP')\nKEYMAPPING_CONTEXT_06_LINE_0596=script=b\"umask 077; mkdir -p \\\"$HOME/.ssh\\\"; chmod 700 \\\"$HOME/.ssh\\\"; touch \\\"$HOME/.ssh/authorized_keys\\\"; chmod 600 \\\"$HOME/.ssh/authorized_keys\\\"; IFS= read -r k; if grep -qF -- \\\"$k\\\" \\\"$HOME/.ssh/authorized_keys\\\"; then printf 'ALREADY\\\\n'; else printf '%s\\\\n' \\\"$k\\\" >> \\\"$HOME/.ssh/authorized_keys\\\"; printf 'ADDED\\\\n'; fi\"\nKEYMAPPING_CONTEXT_06_LINE_0597=p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True)\nKEYMAPPING_CONTEXT_06_LINE_0598=tag=p.stdout.decode().strip()\nKEYMAPPING_CONTEXT_06_LINE_0599=if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT')\nKEYMAPPING_CONTEXT_06_LINE_0600=vps_run(t,['true'],timeout=30,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0601=results[t['logical_id']]=tag\nKEYMAPPING_CONTEXT_06_LINE_0602=# US was already operator-key based; prove it agentless too.\nKEYMAPPING_CONTEXT_06_LINE_0603=us=[x for x in targets if x['type']=='vps_us'][0]\nKEYMAPPING_CONTEXT_06_LINE_0604=vps_run(us,['true'],timeout=30,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0605=results[us['logical_id']]='ALREADY_US_OPERATOR_KEY'\nKEYMAPPING_CONTEXT_06_LINE_0606=return results\nKEYMAPPING_CONTEXT_06_LINE_0607=\nKEYMAPPING_CONTEXT_06_LINE_0608=def remote_hashset(t,command):\nKEYMAPPING_CONTEXT_06_LINE_0609=p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False)\nKEYMAPPING_CONTEXT_06_LINE_0610=return sha256_bytes(p.stdout)\nKEYMAPPING_CONTEXT_06_LINE_0611=\nKEYMAPPING_CONTEXT_06_LINE_0612=def capture_vps_md(t,gen,work):\nKEYMAPPING_CONTEXT_06_LINE_0613=files=['etc/netbird/install.conf','var/lib/netbird/state.json','var/lib/netbird/service.json','var/lib/netbird/active_profile.json','var/lib/netbird/default.json']\nKEYMAPPING_CONTEXT_06_LINE_0614=cmd=\"sudo -n sha256sum -- \"+' '.join(shlex.quote('/'+x) for x in files)\nKEYMAPPING_CONTEXT_06_LINE_0615=pre=remote_hashset(t,cmd)\nKEYMAPPING_CONTEXT_06_LINE_0616=remote=shlex.join(['sudo','-n','tar','--numeric-owner','-C','/','-cf','-']+files)\nKEYMAPPING_CONTEXT_06_LINE_0617=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_06_LINE_0618=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=600)\nKEYMAPPING_CONTEXT_06_LINE_0619=post=remote_hashset(t,cmd)\nKEYMAPPING_CONTEXT_06_LINE_0620=if pre!=post: raise BackupError('MD_SOURCE_CHANGED_DURING_CAPTURE')\nKEYMAPPING_CONTEXT_06_LINE_0621=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None\nKEYMAPPING_CONTEXT_06_LINE_0622=\nKEYMAPPING_CONTEXT_06_LINE_0623=def capture_vps_spb(t,gen,work):\nKEYMAPPING_CONTEXT_06_LINE_0624=hcmd=\"find /etc/nginx -xdev -type f -print0 | sort -z | xargs -0 sha256sum\"\nKEYMAPPING_CONTEXT_06_LINE_0625=pre=remote_hashset(t,hcmd)\nKEYMAPPING_CONTEXT_06_LINE_0626=remote=shlex.join(['tar','--numeric-owner','-C','/','-cf','-','etc/nginx'])\nKEYMAPPING_CONTEXT_06_LINE_0627=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_06_LINE_0628=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=900)\nKEYMAPPING_CONTEXT_06_LINE_0629=post=remote_hashset(t,hcmd)\nKEYMAPPING_CONTEXT_07_RANGE=657-674\nKEYMAPPING_CONTEXT_07_LINE_0657=if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33)\nKEYMAPPING_CONTEXT_07_LINE_0658=b=dst.serialize(); dst.close(); src.close()\nKEYMAPPING_CONTEXT_07_LINE_0659=ti=tarfile.TarInfo(name=('sqlite-backups/'+name)); ti.size=len(b); ti.mode=0o600; ti.mtime=int(time.time()); tf.addfile(ti,io.BytesIO(b))\nKEYMAPPING_CONTEXT_07_LINE_0660='''\nKEYMAPPING_CONTEXT_07_LINE_0661=\nKEYMAPPING_CONTEXT_07_LINE_0662=def capture_vps_us(t,gen,work):\nKEYMAPPING_CONTEXT_07_LINE_0663=remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT])\nKEYMAPPING_CONTEXT_07_LINE_0664=argv=vps_ssh_argv(t,use_agent=False)+[remote]\nKEYMAPPING_CONTEXT_07_LINE_0665=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200)\nKEYMAPPING_CONTEXT_07_LINE_0666=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None\nKEYMAPPING_CONTEXT_07_LINE_0667=\nKEYMAPPING_CONTEXT_07_LINE_0668=def _simple_shell_assignments(text):\nKEYMAPPING_CONTEXT_07_LINE_0669=vals={}\nKEYMAPPING_CONTEXT_07_LINE_0670=for line in text.splitlines():\nKEYMAPPING_CONTEXT_07_LINE_0671=m=re.match(r'^\\s*(?:export\\s+)?([A-Z_][A-Z0-9_]*)=(.*)$',line)\nKEYMAPPING_CONTEXT_07_LINE_0672=if not m: continue\nKEYMAPPING_CONTEXT_07_LINE_0673=v=m.group(2).strip()\nKEYMAPPING_CONTEXT_07_LINE_0674=if len(v)>=2 and v[0]==v[-1] and v[0] in ('\\\"',\"'\"): v=v[1:-1]\nKEYMAPPING_CONTEXT_08_RANGE=846-860\nKEYMAPPING_CONTEXT_08_LINE_0846=return local,{'generation':gen,'source_class':'xenforo','site':t['slug'],'vmid':t['vmid'],'node':t['node'],'dump_strategy':t['dump_strategy'],'db_dump_bytes':j.get('db_bytes')},None\nKEYMAPPING_CONTEXT_08_LINE_0847=\nKEYMAPPING_CONTEXT_08_LINE_0848=def node_bundle_paths(node):\nKEYMAPPING_CONTEXT_08_LINE_0849=p=['etc/network/interfaces','etc/hosts','etc/resolv.conf','etc/hostname','etc/pve/corosync.conf','etc/pve/storage.cfg','etc/pve/user.cfg','etc/pve/datacenter.cfg','etc/pve/firewall','etc/pve/nodes/'+node,'etc/apt/sources.list.d']\nKEYMAPPING_CONTEXT_08_LINE_0850=if node=='pve01':\nKEYMAPPING_CONTEXT_08_LINE_0851=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator')\nKEYMAPPING_CONTEXT_08_LINE_0852=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub')\nKEYMAPPING_CONTEXT_08_LINE_0853=return p\nKEYMAPPING_CONTEXT_08_LINE_0854=\nKEYMAPPING_CONTEXT_08_LINE_0855=def capture_node_bundle(t,gen,work):\nKEYMAPPING_CONTEXT_08_LINE_0856=node=t['node']; raw=node_bundle_paths(node); paths=[]\nKEYMAPPING_CONTEXT_08_LINE_0857=for rel in raw:\nKEYMAPPING_CONTEXT_08_LINE_0858=if node=='pve01': ok=(pathlib.Path('/')/rel).exists()\nKEYMAPPING_CONTEXT_08_LINE_0859=else: ok=(ssh_remote(node,['test','-e','/'+rel],timeout=20,check=False).returncode==0)\nKEYMAPPING_CONTEXT_08_LINE_0860=if ok: paths.append(rel)\nKEYMAPPING_CONTEXT_09_RANGE=870-885\nKEYMAPPING_CONTEXT_09_LINE_0870=\nKEYMAPPING_CONTEXT_09_LINE_0871=def capture_target(t,gen,work):\nKEYMAPPING_CONTEXT_09_LINE_0872=typ=t['type']\nKEYMAPPING_CONTEXT_09_LINE_0873=if typ=='pve_guest': return capture_pve_guest(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0874=if typ=='pve_node_bundle': return capture_node_bundle(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0875=if typ=='vps_md': return capture_vps_md(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0876=if typ=='vps_spb': return capture_vps_spb(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0877=if typ=='vps_us': return capture_vps_us(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0878=if typ=='router': return capture_router(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0879=if typ=='xenforo': return capture_xenforo(t,gen,work)\nKEYMAPPING_CONTEXT_09_LINE_0880=raise BackupError('CAPTURE_TYPE_UNKNOWN')\nKEYMAPPING_CONTEXT_09_LINE_0881=\nKEYMAPPING_CONTEXT_09_LINE_0882=def cleanup_source(cleanup):\nKEYMAPPING_CONTEXT_09_LINE_0883=if not cleanup: return\nKEYMAPPING_CONTEXT_09_LINE_0884=if cleanup.get('kind')=='pve_source_dir':\nKEYMAPPING_CONTEXT_09_LINE_0885=ssh_remote(cleanup['node'],['rm','-rf','--',cleanup['path']],timeout=60)\nKEYMAPPING_RELEVANT_LINE_COUNT=15\nKEYMAPPING_RELEVANT_01_LINE=16\nKEYMAPPING_RELEVANT_01_TEXT=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH]\nKEYMAPPING_RELEVANT_02_LINE=158\nKEYMAPPING_RELEVANT_02_TEXT={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_RELEVANT_03_LINE=160\nKEYMAPPING_RELEVANT_03_TEXT={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True},\nKEYMAPPING_RELEVANT_04_LINE=389\nKEYMAPPING_RELEVANT_04_TEXT=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'):\nKEYMAPPING_RELEVANT_05_LINE=568\nKEYMAPPING_RELEVANT_05_TEXT=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue\nKEYMAPPING_RELEVANT_06_LINE=591\nKEYMAPPING_RELEVANT_06_TEXT=if t['type'] not in ('vps_md','vps_spb'): continue\nKEYMAPPING_RELEVANT_07_LINE=603\nKEYMAPPING_RELEVANT_07_TEXT=us=[x for x in targets if x['type']=='vps_us'][0]\nKEYMAPPING_RELEVANT_08_LINE=612\nKEYMAPPING_RELEVANT_08_TEXT=def capture_vps_md(t,gen,work):\nKEYMAPPING_RELEVANT_09_LINE=621\nKEYMAPPING_RELEVANT_09_TEXT=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None\nKEYMAPPING_RELEVANT_10_LINE=662\nKEYMAPPING_RELEVANT_10_TEXT=def capture_vps_us(t,gen,work):\nKEYMAPPING_RELEVANT_11_LINE=666\nKEYMAPPING_RELEVANT_11_TEXT=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None\nKEYMAPPING_RELEVANT_12_LINE=851\nKEYMAPPING_RELEVANT_12_TEXT=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator')\nKEYMAPPING_RELEVANT_13_LINE=852\nKEYMAPPING_RELEVANT_13_TEXT=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub')\nKEYMAPPING_RELEVANT_14_LINE=875\nKEYMAPPING_RELEVANT_14_TEXT=if typ=='vps_md': return capture_vps_md(t,gen,work)\nKEYMAPPING_RELEVANT_15_LINE=877\nKEYMAPPING_RELEVANT_15_TEXT=if typ=='vps_us': return capture_vps_us(t,gen,work)\nPVE1_KEY_ID_ED25519_PRESENT=True\nPVE1_KEY_ID_ED25519_FP=SHA256:s0CusF0IHQGVJ02oi7ejWkGhH9NkhTWonn3441toe5M\nPVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_PRESENT=True\nPVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_FP=SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0\nVPS552R1_DECISION=HOLD_KEY_MAPPING_AMBIGUOUS\nVPS552R1_NEXT_GATE=PVE1_ACCEPTED_ENGINE_CALLPATH_PARSE\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1\",\"status\":\"OK\",\"changes_made\":false,\"rollback_started\":false,\"rollback_restored\":null}\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 200435e2..83e236a4 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,15 +1,15 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=SUPPORT-260918-INFRA-PVE1-MOLDOVA-ACCEPTED-ENGINE-CONTEXT-READONLY-551R2 +COMMAND_ID=SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1 STATUS=OK RC=0 HOST=pve01 MODE=read-only -COMPONENT=infra-pve1-moldova-accepted-engine-context-readonly +COMPONENT=infra-pve1-moldova-keymapping-readonly REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 -COMMAND_SHA256=466b431b89ae334593305e1fbbdea6c6a21b439a2568b9ccdbb76fa98c59baa9 +COMMAND_SHA256=0fadfaf45ded2524c42751f3efe29300f054f11e12b445ef897607a6f6b3e448 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGE_DECLARED=false @@ -24,52 +24,230 @@ MUTATION_OUTCOME=NO_MUTATION SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=ddd844d81c397e39417a2eb7724f43b3b134b5e6019653f7704be4a9a981af07 -SANITIZED_OUTPUT_SHA256=ddd844d81c397e39417a2eb7724f43b3b134b5e6019653f7704be4a9a981af07 +RAW_EVIDENCE_SHA256=b3e7cbda886dbd253274af0d4c726c89e54425e5b793e9e1f149ea8412962c14 +SANITIZED_OUTPUT_SHA256=be1cde014d4680574aba7cefa652231f34f1db8d57c07b09e171b79b88530186 OUTPUT_BEGIN ERROR_REGISTER_CHECK=OK REFERENCE_CHECK=OK AUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED ACCEPTED_ENGINE_PRESENT=True ACCEPTED_ENGINE_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7 -MOLDOVA_MATCH_LINE_COUNT=1 -MOLDOVA_MATCH_LINES=160 -MOLDOVA_CONTEXT_RANGE=148-172 -MOLDOVA_CONTEXT_0148= -MOLDOVA_CONTEXT_0149=def default_targets(): -MOLDOVA_CONTEXT_0150=d=86400 -MOLDOVA_CONTEXT_0151=out=[] -MOLDOVA_CONTEXT_0152=# PVE guests. Source node is resolved live every run. -MOLDOVA_CONTEXT_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]: -MOLDOVA_CONTEXT_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112}) -MOLDOVA_CONTEXT_0155=for node in ('pve01','pve02','pve03'): -MOLDOVA_CONTEXT_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'}) -MOLDOVA_CONTEXT_0157=out += [ -MOLDOVA_CONTEXT_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True}, -MOLDOVA_CONTEXT_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True}, -MOLDOVA_CONTEXT_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True}, -MOLDOVA_CONTEXT_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True}, -MOLDOVA_CONTEXT_0162=] -MOLDOVA_CONTEXT_0163=sites=[ -MOLDOVA_CONTEXT_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'), -MOLDOVA_CONTEXT_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'), -MOLDOVA_CONTEXT_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'), -MOLDOVA_CONTEXT_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'), -MOLDOVA_CONTEXT_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'), -MOLDOVA_CONTEXT_0169=('hkmods',160,'pve02','/var/www/forums/hkmods/public','xf_hkmods','global_read_lock'), -MOLDOVA_CONTEXT_0170=('zakrutim',160,'pve02','/var/www/forums/zakrutim/public','xf_zakrutim','global_read_lock')] -MOLDOVA_CONTEXT_0171=for slug,vmid,node,root,db,strategy in sites: -MOLDOVA_CONTEXT_0172=out.append({'logical_id':'xf-'+slug,'scope':'xenforo','type':'xenforo','slug':slug,'vmid':vmid,'node':node,'app_root':root,'db_name':db,'dump_strategy':strategy,'due_seconds':d,'enabled':True,'green1':slug in ('codevipe','zakrutim')}) -MOLDOVA_MIN_DICT_COUNT=1 -MOLDOVA_DICT_01_LINENO=160 -MOLDOVA_DICT_01_FIELD_HOST=46.16.34.129 -MOLDOVA_DICT_01_FIELD_PORT=22 -MOLDOVA_DICT_01_FIELD_USER=root -MOLDOVA_DICT_01_FIELD_HOSTKEY_FINGERPRINT=SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE -MOLDOVA_SAFE_FIELD_COUNT=4 -VPS551R2_DECISION=PASS_ACCEPTED_ENGINE_MOLDOVA_RECORD_FOUND -VPS551R2_NEXT_GATE=PVE1_MOLDOVA_EXACT_ROUTE_TEST -HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-INFRA-PVE1-MOLDOVA-ACCEPTED-ENGINE-CONTEXT-READONLY-551R2","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null} +KEYMAPPING_MATCH_LINE_COUNT=17 +KEYMAPPING_MATCH_LINES=14,16,158,160,389,552,568,591,603,612,621,662,666,851,852,875,877 +KEYMAPPING_CONTEXT_01_RANGE=9-24 +KEYMAPPING_CONTEXT_01_LINE_0009=WORK_ROOT=pathlib.Path('/mnt/staging/homelab-backup-v2') +KEYMAPPING_CONTEXT_01_LINE_0010=ENGINE_PATH=pathlib.Path('/usr/local/sbin/homelab-backup-v2') +KEYMAPPING_CONTEXT_01_LINE_0011=RCLONE=shutil.which('rclone') or '/usr/bin/rclone' +KEYMAPPING_CONTEXT_01_LINE_0012=SSH=shutil.which('ssh') or '/usr/bin/ssh' +KEYMAPPING_CONTEXT_01_LINE_0013=SCP=shutil.which('scp') or '/usr/bin/scp' +KEYMAPPING_CONTEXT_01_LINE_0014=SSH_KEYSCAN=shutil.which('ssh-keyscan') or '/usr/bin/ssh-keyscan' +KEYMAPPING_CONTEXT_01_LINE_0015=SSHPASS=shutil.which('sshpass') or '/usr/bin/sshpass' +KEYMAPPING_CONTEXT_01_LINE_0016=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH] +KEYMAPPING_CONTEXT_01_LINE_0017=VPS_KNOWN_HOSTS=CONFIG_ROOT/'vps_known_hosts' +KEYMAPPING_CONTEXT_01_LINE_0018=ROUTER_KNOWN_HOSTS=CONFIG_ROOT/'router_known_hosts' +KEYMAPPING_CONTEXT_01_LINE_0019=ROUTER_LEGACY_SCRIPT=pathlib.Path('/usr/local/sbin/homelab-router-running-config-mail-cloud') +KEYMAPPING_CONTEXT_01_LINE_0020=ROUTER_LEGACY_SHA='a0aeb0e1ec7e2714b3d6147c13c2af04d8d8118219541ec60b66df6919858dc7' +KEYMAPPING_CONTEXT_01_LINE_0021=ROUTER_TARGET_SHA='4f9da1283166a1e9f4e6bc7dd240c76aef85772177f717f92abb6e8e2bb8de90' +KEYMAPPING_CONTEXT_01_LINE_0022=ROUTER_FINGERPRINT='SHA256:2Tw4CU4kvwtXSIiym+699Y6W2VJVWzRUD4opXrSfOIs' +KEYMAPPING_CONTEXT_01_LINE_0023=ROUTER_KNOWN_HOSTS_SHA='02d4e1dad1620937b7a67416a73aa182f9e80ea9c4b11f777161bc7455cf234d' +KEYMAPPING_CONTEXT_01_LINE_0024=OPERATOR_KEY_FINGERPRINT='SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0' +KEYMAPPING_CONTEXT_02_RANGE=153-168 +KEYMAPPING_CONTEXT_02_LINE_0153=for vmid,typ in [(110,'lxc'),(111,'lxc'),(112,'lxc'),(113,'lxc'),(130,'qemu'),(150,'qemu'),(160,'qemu'),(170,'qemu'),(171,'qemu'),(190,'qemu'),(210,'qemu'),(211,'qemu'),(9130,'qemu')]: +KEYMAPPING_CONTEXT_02_LINE_0154=out.append({'logical_id':('ct' if typ=='lxc' else 'vm')+str(vmid),'scope':'pve','type':'pve_guest','vmid':vmid,'guest_type':typ,'due_seconds':d,'enabled':True,'green1':vmid==112}) +KEYMAPPING_CONTEXT_02_LINE_0155=for node in ('pve01','pve02','pve03'): +KEYMAPPING_CONTEXT_02_LINE_0156=out.append({'logical_id':'node-'+node,'scope':'node','type':'pve_node_bundle','node':node,'due_seconds':7*d,'enabled':True,'green1':node=='pve01'}) +KEYMAPPING_CONTEXT_02_LINE_0157=out += [ +KEYMAPPING_CONTEXT_02_LINE_0158={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0159={'logical_id':'spb-ingress','scope':'vps','type':'vps_spb','host':'185.225.35.6','port':22,'user':'edgeadmin','hostkey_fingerprint':'SHA256:Ef+HsZb8lIXoadvYBXuGKIL3H7NyJMmf9EYCoJRoSv8','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0160={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0161={'logical_id':'router-netcraze','scope':'router','type':'router','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_CONTEXT_02_LINE_0162=] +KEYMAPPING_CONTEXT_02_LINE_0163=sites=[ +KEYMAPPING_CONTEXT_02_LINE_0164=('codevipe',160,'pve02','/var/www/forums/codevipe/public','xf_codevipe','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0165=('dsmods',160,'pve02','/var/www/forums/dsmods/public','xf_dsmods','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0166=('kingofwolk',160,'pve02','/var/www/forums/kingofwolk/public','xf_kingofwolk','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0167=('newfi',210,'pve01','/var/www/forums/newfi/public','xf_newfi','single_transaction'), +KEYMAPPING_CONTEXT_02_LINE_0168=('gamevipe',160,'pve02','/var/www/forums/gamevipe/public','xf_gamevipe','global_read_lock'), +KEYMAPPING_CONTEXT_03_RANGE=384-397 +KEYMAPPING_CONTEXT_03_LINE_0384=if not names: raise BackupError('TAR_ZST_EMPTY') +KEYMAPPING_CONTEXT_03_LINE_0385=if required_member and required_member not in names: raise BackupError('REQUIRED_MEMBER_MISSING') +KEYMAPPING_CONTEXT_03_LINE_0386= +KEYMAPPING_CONTEXT_03_LINE_0387=def validate_payload(t,path): +KEYMAPPING_CONTEXT_03_LINE_0388=typ=t['type'] +KEYMAPPING_CONTEXT_03_LINE_0389=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'): +KEYMAPPING_CONTEXT_03_LINE_0390=validate_tar_zst(path) +KEYMAPPING_CONTEXT_03_LINE_0391=elif typ=='pve_guest': +KEYMAPPING_CONTEXT_03_LINE_0392=if t['guest_type']=='lxc': validate_tar_zst(path) +KEYMAPPING_CONTEXT_03_LINE_0393=else: +KEYMAPPING_CONTEXT_03_LINE_0394=# Green set is intentionally CT-only. Scheduled QEMU backups still get dual remote byte readback. +KEYMAPPING_CONTEXT_03_LINE_0395=run([shutil.which('zstd') or '/usr/bin/zstd','-t','-q',str(path)],timeout=600) +KEYMAPPING_CONTEXT_03_LINE_0396=elif typ=='xenforo': +KEYMAPPING_CONTEXT_03_LINE_0397=validate_tar_zst(path,'db.sql') +KEYMAPPING_CONTEXT_04_RANGE=547-560 +KEYMAPPING_CONTEXT_04_LINE_0547=m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s) +KEYMAPPING_CONTEXT_04_LINE_0548=if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH') +KEYMAPPING_CONTEXT_04_LINE_0549=return m.group(1) +KEYMAPPING_CONTEXT_04_LINE_0550= +KEYMAPPING_CONTEXT_04_LINE_0551=def scan_hostkey_line(host,port,expected): +KEYMAPPING_CONTEXT_04_LINE_0552=p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15) +KEYMAPPING_CONTEXT_04_LINE_0553=lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')] +KEYMAPPING_CONTEXT_04_LINE_0554=good=[] +KEYMAPPING_CONTEXT_04_LINE_0555=for line in lines: +KEYMAPPING_CONTEXT_04_LINE_0556=f=line.split() +KEYMAPPING_CONTEXT_04_LINE_0557=if len(f)<3 or f[1]!='ssh-ed25519': continue +KEYMAPPING_CONTEXT_04_LINE_0558=try: blob=base64.b64decode(f[2]) +KEYMAPPING_CONTEXT_04_LINE_0559=except Exception: continue +KEYMAPPING_CONTEXT_04_LINE_0560=fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=') +KEYMAPPING_CONTEXT_05_RANGE=563-576 +KEYMAPPING_CONTEXT_05_LINE_0563=return good[0] +KEYMAPPING_CONTEXT_05_LINE_0564= +KEYMAPPING_CONTEXT_05_LINE_0565=def ensure_vps_known_hosts(targets): +KEYMAPPING_CONTEXT_05_LINE_0566=lines=[] +KEYMAPPING_CONTEXT_05_LINE_0567=for t in targets: +KEYMAPPING_CONTEXT_05_LINE_0568=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue +KEYMAPPING_CONTEXT_05_LINE_0569=lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint'])) +KEYMAPPING_CONTEXT_05_LINE_0570=atomic_write(VPS_KNOWN_HOSTS,('\n'.join(lines)+'\n').encode(),0o600) +KEYMAPPING_CONTEXT_05_LINE_0571= +KEYMAPPING_CONTEXT_05_LINE_0572=def vps_ssh_argv(t, *, use_agent=False): +KEYMAPPING_CONTEXT_05_LINE_0573=a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15'] +KEYMAPPING_CONTEXT_05_LINE_0574=if use_agent: +KEYMAPPING_CONTEXT_05_LINE_0575=a += ['-o','IdentitiesOnly=no'] +KEYMAPPING_CONTEXT_05_LINE_0576=else: +KEYMAPPING_CONTEXT_06_RANGE=586-629 +KEYMAPPING_CONTEXT_06_LINE_0586=operator_key_fingerprint() +KEYMAPPING_CONTEXT_06_LINE_0587=ensure_vps_known_hosts(targets) +KEYMAPPING_CONTEXT_06_LINE_0588=pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\n' +KEYMAPPING_CONTEXT_06_LINE_0589=results={} +KEYMAPPING_CONTEXT_06_LINE_0590=for t in targets: +KEYMAPPING_CONTEXT_06_LINE_0591=if t['type'] not in ('vps_md','vps_spb'): continue +KEYMAPPING_CONTEXT_06_LINE_0592=probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False) +KEYMAPPING_CONTEXT_06_LINE_0593=if probe.returncode==0: +KEYMAPPING_CONTEXT_06_LINE_0594=results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue +KEYMAPPING_CONTEXT_06_LINE_0595=if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP') +KEYMAPPING_CONTEXT_06_LINE_0596=script=b"umask 077; mkdir -p \"$HOME/.ssh\"; chmod 700 \"$HOME/.ssh\"; touch \"$HOME/.ssh/authorized_keys\"; chmod 600 \"$HOME/.ssh/authorized_keys\"; IFS= read -r k; if grep -qF -- \"$k\" \"$HOME/.ssh/authorized_keys\"; then printf 'ALREADY\\n'; else printf '%s\\n' \"$k\" >> \"$HOME/.ssh/authorized_keys\"; printf 'ADDED\\n'; fi" +KEYMAPPING_CONTEXT_06_LINE_0597=p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True) +KEYMAPPING_CONTEXT_06_LINE_0598=tag=p.stdout.decode().strip() +KEYMAPPING_CONTEXT_06_LINE_0599=if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT') +KEYMAPPING_CONTEXT_06_LINE_0600=vps_run(t,['true'],timeout=30,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0601=results[t['logical_id']]=tag +KEYMAPPING_CONTEXT_06_LINE_0602=# US was already operator-key based; prove it agentless too. +KEYMAPPING_CONTEXT_06_LINE_0603=us=[x for x in targets if x['type']=='vps_us'][0] +KEYMAPPING_CONTEXT_06_LINE_0604=vps_run(us,['true'],timeout=30,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0605=results[us['logical_id']]='ALREADY_US_OPERATOR_KEY' +KEYMAPPING_CONTEXT_06_LINE_0606=return results +KEYMAPPING_CONTEXT_06_LINE_0607= +KEYMAPPING_CONTEXT_06_LINE_0608=def remote_hashset(t,command): +KEYMAPPING_CONTEXT_06_LINE_0609=p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False) +KEYMAPPING_CONTEXT_06_LINE_0610=return sha256_bytes(p.stdout) +KEYMAPPING_CONTEXT_06_LINE_0611= +KEYMAPPING_CONTEXT_06_LINE_0612=def capture_vps_md(t,gen,work): +KEYMAPPING_CONTEXT_06_LINE_0613=files=['etc/netbird/install.conf','var/lib/netbird/state.json','var/lib/netbird/service.json','var/lib/netbird/active_profile.json','var/lib/netbird/default.json'] +KEYMAPPING_CONTEXT_06_LINE_0614=cmd="sudo -n sha256sum -- "+' '.join(shlex.quote('/'+x) for x in files) +KEYMAPPING_CONTEXT_06_LINE_0615=pre=remote_hashset(t,cmd) +KEYMAPPING_CONTEXT_06_LINE_0616=remote=shlex.join(['sudo','-n','tar','--numeric-owner','-C','/','-cf','-']+files) +KEYMAPPING_CONTEXT_06_LINE_0617=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_06_LINE_0618=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=600) +KEYMAPPING_CONTEXT_06_LINE_0619=post=remote_hashset(t,cmd) +KEYMAPPING_CONTEXT_06_LINE_0620=if pre!=post: raise BackupError('MD_SOURCE_CHANGED_DURING_CAPTURE') +KEYMAPPING_CONTEXT_06_LINE_0621=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None +KEYMAPPING_CONTEXT_06_LINE_0622= +KEYMAPPING_CONTEXT_06_LINE_0623=def capture_vps_spb(t,gen,work): +KEYMAPPING_CONTEXT_06_LINE_0624=hcmd="find /etc/nginx -xdev -type f -print0 | sort -z | xargs -0 sha256sum" +KEYMAPPING_CONTEXT_06_LINE_0625=pre=remote_hashset(t,hcmd) +KEYMAPPING_CONTEXT_06_LINE_0626=remote=shlex.join(['tar','--numeric-owner','-C','/','-cf','-','etc/nginx']) +KEYMAPPING_CONTEXT_06_LINE_0627=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_06_LINE_0628=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=900) +KEYMAPPING_CONTEXT_06_LINE_0629=post=remote_hashset(t,hcmd) +KEYMAPPING_CONTEXT_07_RANGE=657-674 +KEYMAPPING_CONTEXT_07_LINE_0657=if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33) +KEYMAPPING_CONTEXT_07_LINE_0658=b=dst.serialize(); dst.close(); src.close() +KEYMAPPING_CONTEXT_07_LINE_0659=ti=tarfile.TarInfo(name=('sqlite-backups/'+name)); ti.size=len(b); ti.mode=0o600; ti.mtime=int(time.time()); tf.addfile(ti,io.BytesIO(b)) +KEYMAPPING_CONTEXT_07_LINE_0660=''' +KEYMAPPING_CONTEXT_07_LINE_0661= +KEYMAPPING_CONTEXT_07_LINE_0662=def capture_vps_us(t,gen,work): +KEYMAPPING_CONTEXT_07_LINE_0663=remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT]) +KEYMAPPING_CONTEXT_07_LINE_0664=argv=vps_ssh_argv(t,use_agent=False)+[remote] +KEYMAPPING_CONTEXT_07_LINE_0665=payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200) +KEYMAPPING_CONTEXT_07_LINE_0666=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None +KEYMAPPING_CONTEXT_07_LINE_0667= +KEYMAPPING_CONTEXT_07_LINE_0668=def _simple_shell_assignments(text): +KEYMAPPING_CONTEXT_07_LINE_0669=vals={} +KEYMAPPING_CONTEXT_07_LINE_0670=for line in text.splitlines(): +KEYMAPPING_CONTEXT_07_LINE_0671=m=re.match(r'^\s*(?:export\s+)?([A-Z_][A-Z0-9_]*)=(.*)$',line) +KEYMAPPING_CONTEXT_07_LINE_0672=if not m: continue +KEYMAPPING_CONTEXT_07_LINE_0673=v=m.group(2).strip() +KEYMAPPING_CONTEXT_07_LINE_0674=if len(v)>=2 and v[0]==v[-1] and v[0] in ('\"',"'"): v=v[1:-1] +KEYMAPPING_CONTEXT_08_RANGE=846-860 +KEYMAPPING_CONTEXT_08_LINE_0846=return local,{'generation':gen,'source_class':'xenforo','site':t['slug'],'vmid':t['vmid'],'node':t['node'],'dump_strategy':t['dump_strategy'],'db_dump_bytes':j.get('db_bytes')},None +KEYMAPPING_CONTEXT_08_LINE_0847= +KEYMAPPING_CONTEXT_08_LINE_0848=def node_bundle_paths(node): +KEYMAPPING_CONTEXT_08_LINE_0849=p=['etc/network/interfaces','etc/hosts','etc/resolv.conf','etc/hostname','etc/pve/corosync.conf','etc/pve/storage.cfg','etc/pve/user.cfg','etc/pve/datacenter.cfg','etc/pve/firewall','etc/pve/nodes/'+node,'etc/apt/sources.list.d'] +KEYMAPPING_CONTEXT_08_LINE_0850=if node=='pve01': +KEYMAPPING_CONTEXT_08_LINE_0851=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator') +KEYMAPPING_CONTEXT_08_LINE_0852=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub') +KEYMAPPING_CONTEXT_08_LINE_0853=return p +KEYMAPPING_CONTEXT_08_LINE_0854= +KEYMAPPING_CONTEXT_08_LINE_0855=def capture_node_bundle(t,gen,work): +KEYMAPPING_CONTEXT_08_LINE_0856=node=t['node']; raw=node_bundle_paths(node); paths=[] +KEYMAPPING_CONTEXT_08_LINE_0857=for rel in raw: +KEYMAPPING_CONTEXT_08_LINE_0858=if node=='pve01': ok=(pathlib.Path('/')/rel).exists() +KEYMAPPING_CONTEXT_08_LINE_0859=else: ok=(ssh_remote(node,['test','-e','/'+rel],timeout=20,check=False).returncode==0) +KEYMAPPING_CONTEXT_08_LINE_0860=if ok: paths.append(rel) +KEYMAPPING_CONTEXT_09_RANGE=870-885 +KEYMAPPING_CONTEXT_09_LINE_0870= +KEYMAPPING_CONTEXT_09_LINE_0871=def capture_target(t,gen,work): +KEYMAPPING_CONTEXT_09_LINE_0872=typ=t['type'] +KEYMAPPING_CONTEXT_09_LINE_0873=if typ=='pve_guest': return capture_pve_guest(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0874=if typ=='pve_node_bundle': return capture_node_bundle(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0875=if typ=='vps_md': return capture_vps_md(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0876=if typ=='vps_spb': return capture_vps_spb(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0877=if typ=='vps_us': return capture_vps_us(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0878=if typ=='router': return capture_router(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0879=if typ=='xenforo': return capture_xenforo(t,gen,work) +KEYMAPPING_CONTEXT_09_LINE_0880=raise BackupError('CAPTURE_TYPE_UNKNOWN') +KEYMAPPING_CONTEXT_09_LINE_0881= +KEYMAPPING_CONTEXT_09_LINE_0882=def cleanup_source(cleanup): +KEYMAPPING_CONTEXT_09_LINE_0883=if not cleanup: return +KEYMAPPING_CONTEXT_09_LINE_0884=if cleanup.get('kind')=='pve_source_dir': +KEYMAPPING_CONTEXT_09_LINE_0885=ssh_remote(cleanup['node'],['rm','-rf','--',cleanup['path']],timeout=60) +KEYMAPPING_RELEVANT_LINE_COUNT=15 +KEYMAPPING_RELEVANT_01_LINE=16 +KEYMAPPING_RELEVANT_01_TEXT=OPERATOR_KEY=pathlib.Path('[SENSITIVE_PATH] +KEYMAPPING_RELEVANT_02_LINE=158 +KEYMAPPING_RELEVANT_02_TEXT={'logical_id':'md-relay','scope':'vps','type':'vps_md','host':'85.121.4.192','port':22,'user':'ops','hostkey_fingerprint':'SHA256:DXJGwunC5tEVvnC3nRxyayTN8FXmyJcVgf+Oa6udQsY','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_RELEVANT_03_LINE=160 +KEYMAPPING_RELEVANT_03_TEXT={'logical_id':'us-netbird','scope':'vps','type':'vps_us','host':'46.16.34.129','port':22,'user':'root','hostkey_fingerprint':'SHA256:805Q9eh/fePUci42dfY58I6q0lFiiPHn0/M+mckypmE','due_seconds':d,'enabled':True,'green1':True}, +KEYMAPPING_RELEVANT_04_LINE=389 +KEYMAPPING_RELEVANT_04_TEXT=if typ in ('pve_node_bundle','vps_md','vps_spb','vps_us','router'): +KEYMAPPING_RELEVANT_05_LINE=568 +KEYMAPPING_RELEVANT_05_TEXT=if t['type'] not in ('vps_md','vps_spb','vps_us'): continue +KEYMAPPING_RELEVANT_06_LINE=591 +KEYMAPPING_RELEVANT_06_TEXT=if t['type'] not in ('vps_md','vps_spb'): continue +KEYMAPPING_RELEVANT_07_LINE=603 +KEYMAPPING_RELEVANT_07_TEXT=us=[x for x in targets if x['type']=='vps_us'][0] +KEYMAPPING_RELEVANT_08_LINE=612 +KEYMAPPING_RELEVANT_08_TEXT=def capture_vps_md(t,gen,work): +KEYMAPPING_RELEVANT_09_LINE=621 +KEYMAPPING_RELEVANT_09_TEXT=return payload,{'generation':gen,'source_class':'vps_md','consistency':'FILESET_PRE_POST_HASH_STABILITY','hashset_sha256':pre},None +KEYMAPPING_RELEVANT_10_LINE=662 +KEYMAPPING_RELEVANT_10_TEXT=def capture_vps_us(t,gen,work): +KEYMAPPING_RELEVANT_11_LINE=666 +KEYMAPPING_RELEVANT_11_TEXT=return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None +KEYMAPPING_RELEVANT_12_LINE=851 +KEYMAPPING_RELEVANT_12_TEXT=if OPERATOR_KEY.exists(): p.append('root/.ssh/id_ed25519_netbird_operator') +KEYMAPPING_RELEVANT_13_LINE=852 +KEYMAPPING_RELEVANT_13_TEXT=if pathlib.Path(str(OPERATOR_KEY)+'.pub').exists(): p.append('root/.ssh/id_ed25519_netbird_operator.pub') +KEYMAPPING_RELEVANT_14_LINE=875 +KEYMAPPING_RELEVANT_14_TEXT=if typ=='vps_md': return capture_vps_md(t,gen,work) +KEYMAPPING_RELEVANT_15_LINE=877 +KEYMAPPING_RELEVANT_15_TEXT=if typ=='vps_us': return capture_vps_us(t,gen,work) +PVE1_KEY_ID_ED25519_PRESENT=True +PVE1_KEY_ID_ED25519_FP=SHA256:s0CusF0IHQGVJ02oi7ejWkGhH9NkhTWonn3441toe5M +PVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_PRESENT=True +PVE1_KEY_ID_ED25519_NETBIRD_OPERATOR_FP=SHA256:wipXiBB3cpAwyWap9LcB185WjEEmDxtRJsI/UuMVAp0 +VPS552R1_DECISION=HOLD_KEY_MAPPING_AMBIGUOUS +VPS552R1_NEXT_GATE=PVE1_ACCEPTED_ENGINE_CALLPATH_PARSE +HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-INFRA-PVE1-MOLDOVA-KEYMAPPING-READONLY-552R1","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null} OUTPUT_END CHAT_OUTPUT_END