From fd4185eb38da59783246efe6ccc4a563530f2dd5 Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Tue, 22 Sep 2026 06:17:03 +0000 Subject: [PATCH] runtime: publish CONTEXT-AUTO-20260922T061701Z --- .../CONTEXT-AUTO-20260922T061701Z.json | 1 + .../history/CONTEXT-AUTO-20260922T061701Z.txt | 163 ++++++ runtime/latest.json | 39 +- runtime/latest.txt | 544 +++++------------- 4 files changed, 307 insertions(+), 440 deletions(-) create mode 100644 runtime/history/CONTEXT-AUTO-20260922T061701Z.json create mode 100644 runtime/history/CONTEXT-AUTO-20260922T061701Z.txt diff --git a/runtime/history/CONTEXT-AUTO-20260922T061701Z.json b/runtime/history/CONTEXT-AUTO-20260922T061701Z.json new file mode 100644 index 00000000..e591715d --- /dev/null +++ b/runtime/history/CONTEXT-AUTO-20260922T061701Z.json @@ -0,0 +1 @@ +{"schema_version":1,"channel":"homelab-runtime","command_id":"CONTEXT-AUTO-20260922T061701Z","status":"OK","rc":0,"host":"pve01","mode":"read-only","component":"cluster-context","started_at_utc":"2026-09-22T06:17:01Z","finished_at_utc":"2026-09-22T06:17:02Z","reference_register_checked":true,"reference_sha256":"5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66","error_register_checked":true,"error_register_sha256":"3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0","changes_made":false,"sanitized":true,"secrets_included":false,"private_addresses_included":false,"output":"AUTOMATIC_CLUSTER_CONTEXT_REFRESH=OK"} diff --git a/runtime/history/CONTEXT-AUTO-20260922T061701Z.txt b/runtime/history/CONTEXT-AUTO-20260922T061701Z.txt new file mode 100644 index 00000000..2f534065 --- /dev/null +++ b/runtime/history/CONTEXT-AUTO-20260922T061701Z.txt @@ -0,0 +1,163 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=CONTEXT-AUTO-[PRIVATE_IP]701Z +STATUS=OK +RC=0 +HOST=pve01 +COMPONENT=cluster-context +REFERENCE_SHA[PRIVATE_IP]e5154c41cb[PRIVATE_IP]aca68090be[PRIVATE_IP]bf[PRIVATE_IP]df[PRIVATE_IP] +ERROR_REGISTER_SHA[PRIVATE_IP]ec0f527ed3afeed[PRIVATE_IP]ee[PRIVATE_IP]bbfb[PRIVATE_IP]af4ba7ba0 +OUTPUT_BEGIN +GENERATED_AT_UTC=[PRIVATE_IP]T06:17:01Z +Cluster information +------------------- +Name: homelab +Config Version: 3 +Transport: knet +Secure auth: on + +Quorum information +------------------ +Date: Tue Sep [PRIVATE_IP] 2026 +Quorum provider: corosync_votequorum +Nodes: 3 +Node ID: [PRIVATE_IP] +Ring ID: 1.130 +Quorate: Yes + +Votequorum information +---------------------- +Expected votes: 3 +Highest expected: 3 +Total votes: 3 +Quorum: 2 +Flags: Quorate + +Membership information +---------------------- + Nodeid Votes Name +[PRIVATE_IP] [PRIVATE_IP].11 (local) +[PRIVATE_IP] [PRIVATE_IP].13 +[PRIVATE_IP] [PRIVATE_IP].12 + +Membership information +---------------------- + Nodeid Votes Name + 1 1 pve01 (local) + 2 1 pve03 + 3 1 pve02 +[{"cpu":[PRIVATE_IP]507669,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/100","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"pvepro-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":191789,"vmid":100},{"cpu":0,"disk":0,"diskread":0,"diskwrite":0,"id":"qemu/101","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":0,"memhost":0,"name":"pvepro-staging-v1","netin":0,"netout":0,"node":"pve01","status":"stopped","template":0,"type":"qemu","uptime":0,"vmid":101},{"cpu":[PRIVATE_IP][PRIVATE_IP],"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/110","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"dns1","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":110},{"cpu":[PRIVATE_IP]812998,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/111","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"dns2","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":111},{"cpu":[PRIVATE_IP]427e-05,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/112","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"unbound1","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":112},{"cpu":[PRIVATE_IP]832e-05,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/113","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"unbound2","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":113},{"cpu":[PRIVATE_IP]61437,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/130","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"edge-vm","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":130},{"cpu":[PRIVATE_IP]06647,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/150","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"snikket","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":150},{"cpu":[PRIVATE_IP]724704,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/160","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"forum-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":160},{"cpu":[PRIVATE_IP]41414,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/170","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"core-apps","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":170},{"cpu":[PRIVATE_IP]09203,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/171","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"monitoring","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":171},{"cpu":[PRIVATE_IP]046608,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/190","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"homelab-ops-worker","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":190},{"cpu":[PRIVATE_IP]015338,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/210","maxcpu":2,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"newfi-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":210},{"cpu":[PRIVATE_IP]411014,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/211","maxcpu":2,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"newfi-staging","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":211},{"cpu":0,"disk":0,"diskread":0,"diskwrite":0,"id":"qemu/9130","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":0,"memhost":0,"name":"edge-cold-standby","netin":0,"netout":0,"node":"pve02","status":"stopped","template":0,"type":"qemu","uptime":0,"vmid":9130},{"cgroup-mode":2,"cpu":[PRIVATE_IP]49991,"disk":[PRIVATE_IP],"id":"node/pve02","level":"","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve02","status":"online","type":"node","uptime":[PRIVATE_IP]},{"cgroup-mode":2,"cpu":[PRIVATE_IP]55929,"disk":[PRIVATE_IP],"id":"node/pve01","level":"","maxcpu":24,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve01","status":"online","type":"node","uptime":[PRIVATE_IP]},{"cgroup-mode":2,"cpu":[PRIVATE_IP]56779,"disk":[PRIVATE_IP],"id":"node/pve03","level":"","maxcpu":8,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve03","status":"online","type":"node","uptime":[PRIVATE_IP]},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve02/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve02","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve01/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve01","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve03/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve03","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve02/local","maxdisk":[PRIVATE_IP],"node":"pve02","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve01/local","maxdisk":[PRIVATE_IP],"node":"pve01","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve03/local","maxdisk":[PRIVATE_IP],"node":"pve03","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"id":"network/pve02/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve02","status":"ok","type":"network"},{"id":"network/pve01/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve01","status":"ok","type":"network"},{"id":"network/pve03/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve03","status":"ok","type":"network"}] +Name Type Status Total (KiB) Used (KiB) Available (KiB) % +local dir active [PRIVATE_IP] [PRIVATE_IP] [PRIVATE_IP] 37.33% +local-lvm lvmthin active [PRIVATE_IP] [PRIVATE_IP] [PRIVATE_IP] 15.64% + UNIT LOAD ACTIVE SUB DESCRIPTION +● homelab-backup-audit.service loaded failed failed Homelab unified backup and DR audit +● homelab-backup-v2.service loaded failed failed Homelab Backup V2 manifest-driven scheduler + +Legend: LOAD → Reflects whether the unit definition was properly loaded. + ACTIVE → The high-level unit activation state, i.e. generalization of SUB. + SUB → The low-level unit activation state, values depend on unit type. + +2 loaded units listed. +NEXT LEFT LAST PASSED UNIT ACTIVATES +Tue [PRIVATE_IP] 09:17:16 MSK 13s Tue [PRIVATE_IP] 09:16:16 MSK 46s ago homelab-private-vpn-hosts-health.timer homelab-private-vpn-hosts-health.service +Tue [PRIVATE_IP] 09:17:51 MSK 48s Tue [PRIVATE_IP] 09:16:49 MSK 13s ago homelab-router-watchdog.timer homelab-router-watchdog.service +Tue [PRIVATE_IP] 09:19:03 MSK 2min 1s Tue [PRIVATE_IP] 09:13:45 MSK 3min 16s ago homelab-health-metrics.timer homelab-health-metrics.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:11:59 MSK 5min ago skladchik-reports-monitor-supervisor.timer skladchik-reports-monitor-supervisor.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:06:59 MSK 10min ago prometheus-node-exporter-apt.timer prometheus-node-exporter-apt.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:16:59 MSK 3s ago homelab-smartctl-textfile.timer homelab-smartctl-textfile.service +Tue [PRIVATE_IP] 09:25:31 MSK 8min Tue [PRIVATE_IP] 08:53:16 MSK 23min ago homelab-backup-v2.timer homelab-backup-v2.service +Tue [PRIVATE_IP] 09:26:03 MSK 9min Tue [PRIVATE_IP] 09:10:59 MSK 6min ago homelab-alertmanager-backup-health.timer homelab-alertmanager-backup-health.service +Tue [PRIVATE_IP] 09:27:59 MSK 10min Tue [PRIVATE_IP] 09:12:59 MSK 4min 3s ago homelab-disk-space-health.timer homelab-disk-space-health.service +Tue [PRIVATE_IP] 09:27:59 MSK 10min Tue [PRIVATE_IP] 09:12:59 MSK 4min 3s ago prometheus-node-exporter-nvme.timer prometheus-node-exporter-nvme.service +Tue [PRIVATE_IP] 09:28:37 MSK 11min Tue [PRIVATE_IP] 08:56:32 MSK 20min ago homelab-reference-refresh.timer homelab-reference-refresh.service +Tue [PRIVATE_IP] 09:29:59 MSK 12min Tue [PRIVATE_IP] 09:14:59 MSK 2min 3s ago homelab-pve03-staging-capacity-health.timer homelab-pve03-staging-capacity-health.service +Tue [PRIVATE_IP] 09:30:00 MSK 12min Tue [PRIVATE_IP] 07:30:15 MSK 1h 46min ago homelab-app-cloud-quorum-queue.timer homelab-app-cloud-quorum-queue.service +Tue [PRIVATE_IP] 09:30:00 MSK 12min Tue [PRIVATE_IP] 09:15:12 MSK 1min 50s ago homelab-incident-journal.timer homelab-incident-journal.service +Tue [PRIVATE_IP] 09:30:34 MSK 13min Tue [PRIVATE_IP] 09:15:59 MSK 1min 3s ago homelab-external-probe-vps-health.timer homelab-external-probe-vps-health.service +Tue [PRIVATE_IP] 09:31:15 MSK 14min Tue [PRIVATE_IP] 09:16:45 MSK 16s ago homelab-duty-admin-v2.timer homelab-duty-admin-v2.service +Tue [PRIVATE_IP] 09:31:26 MSK 14min Tue [PRIVATE_IP] 09:15:42 MSK 1min 20s ago homelab-forum-snuffleupagus-health.timer homelab-forum-snuffleupagus-health.service +Tue [PRIVATE_IP] 09:34:27 MSK 17min Tue [PRIVATE_IP] 09:04:58 MSK 12min ago homelab-mkdocs-auto-refresh.timer homelab-mkdocs-auto-refresh.service +Tue [PRIVATE_IP] 09:35:22 MSK 18min Tue [PRIVATE_IP] 09:05:13 MSK 11min ago homelab-backup-audit.timer homelab-backup-audit.service +Tue [PRIVATE_IP] 10:15:00 MSK 57min Mon [PRIVATE_IP] 10:15:00 MSK 23h ago skladchik-reports-monitor-monthly-selftest-watch.timer skladchik-reports-monitor-monthly-selftest-watch.service +Tue [PRIVATE_IP] 10:35:59 MSK 1h 18min Tue [PRIVATE_IP] 04:35:59 MSK 4h 41min ago homelab-vps-identity-audit.timer homelab-vps-identity-audit.service +Tue [PRIVATE_IP] 13:16:26 MSK 3h 59min Tue [PRIVATE_IP] 07:09:07 MSK 2h 7min ago homelab-evidence-root.timer homelab-evidence-root.service +Tue [PRIVATE_IP] 14:44:55 MSK 5h 27min Tue [PRIVATE_IP] 08:42:59 MSK 34min ago homelab-mailru-trash-gc.timer homelab-mailru-trash-gc.service +Tue [PRIVATE_IP] 16:47:58 MSK 7h Mon [PRIVATE_IP] 16:47:58 MSK 16h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service +Tue [PRIVATE_IP] 17:40:23 MSK 8h Mon [PRIVATE_IP] 19:10:54 MSK 14h ago apt-daily.timer apt-daily.service +Wed [PRIVATE_IP] 00:00:00 MSK 14h Tue [PRIVATE_IP] 00:00:15 MSK 9h ago dpkg-db-backup.timer dpkg-db-backup.service +Wed [PRIVATE_IP] 00:04:00 MSK 14h Tue [PRIVATE_IP] 00:14:16 MSK 9h ago homelab-docker-health.timer homelab-docker-health.service +Wed [PRIVATE_IP] 00:05:26 MSK 14h Tue [PRIVATE_IP] 00:01:16 MSK 9h ago homelab-evidence-catalog.timer homelab-evidence-catalog.service +Wed [PRIVATE_IP] 00:09:18 MSK 14h Tue [PRIVATE_IP] 00:11:58 MSK 9h ago homelab-quality-gate.timer homelab-quality-gate.service +Wed [PRIVATE_IP] 00:11:10 MSK 14h Tue [PRIVATE_IP] 00:13:45 MSK 9h ago homelab-storage-capacity.timer homelab-storage-capacity.service +Wed [PRIVATE_IP] 00:23:23 MSK 15h Tue [PRIVATE_IP] 00:17:32 MSK 8h ago logrotate.timer logrotate.service +Wed [PRIVATE_IP] 01:43:37 MSK 16h Tue [PRIVATE_IP] 01:58:53 MSK 7h ago pve-daily-update.timer pve-daily-update.service +Wed [PRIVATE_IP] 03:23:23 MSK 18h Tue [PRIVATE_IP] 03:23:32 MSK 5h 53min ago homelab-backup-retention-gc.timer homelab-backup-retention-gc.service +Wed [PRIVATE_IP] 06:05:55 MSK 20h Tue [PRIVATE_IP] 06:01:58 MSK 3h 15min ago apt-daily-upgrade.timer apt-daily-upgrade.service +Wed [PRIVATE_IP] 07:00:09 MSK 21h Tue [PRIVATE_IP] 07:05:52 MSK 2h 11min ago homelab-drift-check.timer homelab-drift-check.service +Wed [PRIVATE_IP] 07:37:32 MSK 22h Tue [PRIVATE_IP] 07:32:58 MSK 1h 44min ago homelab-service-registry-check.timer homelab-service-registry-check.service +Wed [PRIVATE_IP] 07:41:08 MSK 22h Tue [PRIVATE_IP] 07:55:16 MSK 1h 21min ago homelab-dependency-map-check.timer homelab-dependency-map-check.service +Wed [PRIVATE_IP] 07:45:08 MSK 22h Tue [PRIVATE_IP] 07:53:32 MSK 1h 23min ago homelab-alerting-health.timer homelab-alerting-health.service +Wed [PRIVATE_IP] 07:49:54 MSK 22h Tue [PRIVATE_IP] 07:52:16 MSK 1h 24min ago homelab-runbook-generate.timer homelab-runbook-generate.service +Wed [PRIVATE_IP] 07:54:04 MSK 22h Tue [PRIVATE_IP] 08:00:58 MSK 1h 16min ago homelab-desired-state-sync.timer homelab-desired-state-sync.service +Wed [PRIVATE_IP] 08:06:21 MSK 22h Tue [PRIVATE_IP] 08:01:32 MSK 1h 15min ago homelab-duty-admin-report.timer homelab-duty-admin-report.service +Wed [PRIVATE_IP] 08:13:48 MSK 22h Tue [PRIVATE_IP] 08:11:58 MSK 1h 5min ago homelab-overall-health.timer homelab-overall-health.service +Wed [PRIVATE_IP] 08:16:23 MSK 22h Tue [PRIVATE_IP] 08:12:58 MSK 1h 4min ago homelab-kuma-monitor-policy.timer homelab-kuma-monitor-policy.service +Wed [PRIVATE_IP] 08:18:31 MSK 23h Tue [PRIVATE_IP] 08:19:32 MSK 57min ago homelab-final-readiness-gate.timer homelab-final-readiness-gate.service +Wed [PRIVATE_IP] 08:39:26 MSK 23h Tue [PRIVATE_IP] 08:28:45 MSK 48min ago homelab-capacity-risk.timer homelab-capacity-risk.service +Wed [PRIVATE_IP] 08:40:06 MSK 23h Tue [PRIVATE_IP] 08:43:32 MSK 33min ago homelab-secret-exposure-guard.timer homelab-secret-exposure-guard.service +Wed [PRIVATE_IP] 08:48:42 MSK 23h Tue [PRIVATE_IP] 08:51:11 MSK 25min ago homelab-cluster-passport.timer homelab-cluster-passport.service +Wed [PRIVATE_IP] 08:49:21 MSK 23h Tue [PRIVATE_IP] 09:01:45 MSK 15min ago homelab-golden-state-index.timer homelab-golden-state-index.service +Wed [PRIVATE_IP] 11:04:23 MSK 1 day 1h Tue [PRIVATE_IP] 08:22:45 MSK 54min ago man-db.timer man-db.service +Sun [PRIVATE_IP] 03:10:02 MSK 4 days Sun [PRIVATE_IP] 03:10:58 MSK 2 days ago xfs_scrub_all.timer xfs_scrub_all.service +Sun [PRIVATE_IP] 03:10:39 MSK 4 days Sun [PRIVATE_IP] 03:10:12 MSK 2 days ago e2scrub_all.timer e2scrub_all.service +Sun [PRIVATE_IP] 06:43:52 MSK 4 days Sun [PRIVATE_IP] 07:40:22 MSK 2 days ago homelab-rotating-boot-drill.timer homelab-rotating-boot-drill.service +Mon [PRIVATE_IP] 00:01:03 MSK 5 days Mon [PRIVATE_IP] 00:04:44 MSK 1 day 9h ago homelab-secret-sanity.timer homelab-secret-sanity.service +Mon [PRIVATE_IP] 00:15:22 MSK 5 days Mon [PRIVATE_IP] 00:09:14 MSK 1 day 9h ago fstrim.timer fstrim.service +- - Tue [PRIVATE_IP] 09:16:59 MSK 3s ago netbird-peers-health.timer netbird-peers-health.service +- - - - prometheus-node-exporter-ipmitool-sensor.timer prometheus-node-exporter-ipmitool-sensor.service +- - - - prometheus-node-exporter-mellanox-hca-temp.timer prometheus-node-exporter-mellanox-hca-temp.service +- - - - prometheus-node-exporter-smartmon.timer prometheus-node-exporter-smartmon.service + +58 timers listed. +RUNTIME_MANIFEST_ID=df[PRIVATE_IP]ac9b5abd[PRIVATE_IP]b[PRIVATE_IP]d89496fb2bde[PRIVATE_IP] +EXPERIMENT_ID=5462ee[PRIVATE_IP]ebe[PRIVATE_IP]feb2ad[PRIVATE_IP]1ad87bbac0b8108 +COLLECTION_START_AT=[PRIVATE_IP]T[PRIVATE_IP]:00 +FIRST_COMPLETE_D1_CLOSE=[PRIVATE_IP]T[PRIVATE_IP]:00 +PRODUCTION_LAUNCH_ALLOWED=False +EXECUTION_AUTHORITY=False +RISK_AUTHORITY=False +STAGE_A_HEALTH=AWAITING_PRIMARY_FINALITY +FORENSIC_PREVIOUS_EPOCH_PRESERVED=YES + +## NEWFI_TASK6_AUTH_CHECKPOINT_V[PRIVATE_IP] +- Scope: historical accepted AUTH test, not a current SMTP connection test. +- Newfi approved SMTP account/sender: aleisaev@yandex.ru. +- Endpoint used by accepted test: smtp.yandex.ru:465 with certificate verification; single PLAIN initial response accepted with code 235. +- Evidence: incident ledger ### NEWFI_TASK6_YANDEX_AUTH_V2_OBSERVATION and ### NEWFI_TASK6_AUTH_PROOF_CLOSE_V1. +- No password file written, no application configuration changed, no mail sent by the accepted AUTH test. +- Persistent transport installation and application delivery are not proven by this checkpoint. Task6 is not complete. +- AUTH challenge and missing-file incidents closed; launch/session incident remains OPEN with original cause unproven. +- This update does not change VM211, VM160, routing, board state or Git. +- Other incidents and infrastructure health were not assessed. + + +## NEWFI_PRIVATE_STRUCTURE92_WRONG_MARKER_SCOPE_[PRIVATE_IP] CLOSURE +- Status: CLOSED +- RCA: NEWFI92 inspected the pve01 NEWFI90 attempt marker, which had not been finalized because the outer shell exited immediately after the guest returned RC3 following its successful rollback. The guest marker contained the true final rollback state. +- Correction: NEWFI93 required both the guest FINISHED/ROLLED_BACK record and a fresh exact demo-state readback before reconciling the outer NEWFI90 marker. NEWFI92 itself never reserved an attempt or mutated state. + + +## NEWFI_PRIVATE_NEWFI95_NESTED_TRIPLE_QUOTE_PARSE_[PRIVATE_IP] +- Status: OPEN +- Command: NEWFI95 +- Symptom: after the content-structure precheck passed, the pve03 Python wrapper failed to parse at the PHP line beginning with $root. No Portal discovery or application mutation was reached. +- RCA: an outer raw triple-single-quoted guest Python payload contained an inner raw triple-single-quoted PHP payload. The inner delimiter terminated the outer Python string, causing PHP source to be parsed as Python. +- Safety: NEWFI95 was read-only, created no attempt marker, and did not reach the intended nested guest execution. Do not replay NEWFI95. + + +## NEWFI_PRIVATE_NEWFI95_NESTED_TRIPLE_QUOTE_PARSE_[PRIVATE_IP] CLOSURE +- Status: CLOSED +- RCA: an inner triple-single-quoted PHP literal terminated the outer triple-single-quoted Python guest payload in NEWFI95. The wrapper therefore failed parsing before the intended Portal discovery executed. +- Correction: NEWFI96 removed the nested Python payload layer entirely and passed one Python program directly to VM211 through qm guest exec stdin. The read-only Portal contract completed with QGA exit 0 and the implementation worktree remained unchanged. +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index e4af0c69..e591715d 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,38 +1 @@ -{ - "schema_version": 1, - "channel": "homelab-runtime", - "command_id": "SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1", - "status": "OK", - "rc": 0, - "host": "pve01", - "mode": "read-only", - "component": "homelab-backup-1116-contract-pipe-rca", - "started_at_utc": "2026-09-22T06:05:29Z", - "finished_at_utc": "2026-09-22T06:05:29Z", - "reference_register_checked": true, - "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66", - "error_register_checked": true, - "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0", - "command_sha256": "0ba8e65003a7561a9e01930aa9eec5d2b6a6cd73c9f05d217fca4a399c992fed", - "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": "8314f5500f36a8ab9866f3f778ae569bf18655d73ade7aca6ada77060826a746", - "sanitized_output_sha256": "1c8576db6611dd527a417a275078b31f952af42ddef0dd6dd0fa1661455bb847", - "output_truncated_in_json": false, - "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "WORKERS2_BACKUP_1116_CONTRACT_PIPE_RCA_BEGIN=1\nCOMMAND_ID=SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1\nMODE=read-only\nCOMPONENT=homelab-backup-1116-contract-pipe-rca\nMUTATION_BOUNDARY=NONE;READ_ONLY_APP_RESTORE_CONTRACT_AND_US_NETBIRD_PIPE_RCA;NO_SYSTEMCTL_ACTION;NO_BACKUP_TARGET_EXECUTION;NO_RESTORE_EXECUTION;NO_GIT_WRITE;NO_CLOUD_WRITE;REMOTE_PROBES_READ_ONLY\nERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nREFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66\nERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0\nRUNNER_SHA256=b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d\nWRAPPER_SHA256=5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2\nLEGACY_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7\nAPP_WORKER_SHA256=1d6c4a04f762e2a33561c109b0c0a4878caaa48627903e7e78fdf5f22d79f196\nSCHEDULER_RC=0\nSELFTEST_REPLACEMENT486=PASS\nSCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET\nAPP_RESTORE_CONTRACT_SOURCE_BEGIN=1\n89-}\n90-latest_sealed_state(){\n91- local app=\"$1\" d\n92- d=\"$(state_dir \"$app\")\"; [[ -d \"$d\" ]] || return 0\n93- find \"$d\" -maxdepth 1 -type f -name '*.json' -printf '%T@|%p\\n' | LC_ALL=C sort -t'|' -k1,1nr | while IFS='|' read -r _ f; do\n94- if jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' \"$f\" >/dev/null 2>&1; then echo \"$f\"; break; fi\n95- done\n96-}\n97:restore_ok(){\n98- local app=\"$1\" gen=\"$2\" f\n99- f=\"$(restore_dir \"$app\")/$gen.json\"\n100- [[ -s \"$f\" && ! -L \"$f\" ]] || return 1\n101: jq -e --arg l \"$(logical_id \"$app\")\" --arg g \"$gen\" '.logical_id==$l and .generation==$g and .transport_state==\"SEALED\" and .restore_source==\"Cloud A\" and .payload_sha256_verified==true and .result==\"OK\"' \"$f\" >/dev/null\n102-}\n103-remote_core(){ local action=\"$1\" gen=\"$2\"; ssh \"${SSH_BASE[@]}\" \"$CORE\" sudo -n /bin/bash -s -- \"$action\" \"$gen\" <\"$CORE_HELPER\"; }\n104-remote_edge(){ local action=\"$1\" gen=\"$2\"; ssh \"${SSH_BASE[@]}\" \"$EDGE\" sudo -n /bin/bash -s -- \"$action\" \"$gen\" <\"$EDGE_HELPER\"; }\n105-rsync_core(){\n106- local src=\"$1\" dst=\"$2\"\n107- mkdir -p \"$dst\"\n108- RSYNC_RSH='ssh -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=[SENSITIVE_PATH] rsync -a --numeric-ids --delete --info=progress2 --rsync-path='sudo -n rsync' \"$CORE:$src/\" \"$dst/\"\n109-}\n--\n344- [[ -f \"$ex/$path\" && ! -L \"$ex/$path\" ]] || die RESTORE_COMPONENT_MISSING 70\n345- actual=\"$(sha256sum \"$ex/$path\"|awk '{print $1}')\"; [[ \"$actual\" == \"$sha\" ]] || die RESTORE_COMPONENT_SHA_MISMATCH 70\n346- done < <(jq -r '.components|to_entries[]|[.value.path,.value.sha256]|@tsv' \"$ex/app-generation.json\")\n347-}\n348-reconstruct_cloud_a(){\n349- local app=\"$1\" gen=\"$2\" state=\"$3\" out=\"$4\" logical base manifest expected_msha got_msha idx name size sha part actual\n350- logical=\"$(logical_id \"$app\")\"\n351- \"$TRANSPORT\" verify-sealed \"$logical\" \"$gen\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\" >/dev/null\n352: base=\"$(jq -er '.remote_a_base' \"$state\")\"; expected_msha=\"$(jq -er '.parts_manifest_sha256' \"$state\")\"\n353- manifest=\"$(dirname \"$out\")/PARTS.tsv\"; rclone cat \"${base%/}/PARTS.tsv\" >\"$manifest\"\n354- got_msha=\"$(sha256sum \"$manifest\"|awk '{print $1}')\"; [[ \"$got_msha\" == \"$expected_msha\" ]] || die RESTORE_A_MANIFEST_SHA_MISMATCH 70\n355- : >\"$out\"; chmod 0600 \"$out\"\n356- while IFS=$'\\t' read -r idx name size sha; do\n357- [[ \"$idx\" =~ ^[0-9]{8}$ && \"$name\" == part-????????.bin && \"$size\" =~ ^[1-9][0-9]*$ && \"$sha\" =~ ^[0-9a-f]{64}$ ]] || die RESTORE_A_MANIFEST_ROW_INVALID 70\n358- part=\"$(dirname \"$out\")/$name\"; rm -f \"$part\"; rclone cat \"${base%/}/payload.parts/$name\" >\"$part\"\n359- [[ \"$(stat -c %s \"$part\")\" == \"$size\" ]] || die RESTORE_A_PART_SIZE_MISMATCH 70\n360- actual=\"$(sha256sum \"$part\"|awk '{print $1}')\"; [[ \"$actual\" == \"$sha\" ]] || die RESTORE_A_PART_SHA_MISMATCH 70\n--\n505- scp \"${SCP_BASE[@]}\" \"$ex/immich/db/immich.dump\" \"$CORE:$remote_dump\" >/dev/null\n506- scp \"${SCP_BASE[@]}\" \"$ACTIVE_STAGE/postgres-image.txt\" \"$CORE:$remote_img\" >/dev/null\n507- if ! ssh \"${SSH_BASE[@]}\" \"$CORE\" sudo -n /bin/bash -s -- validate-immich-db \"$gen\" \"$remote_dump\" \"$expect\" \"$remote_img\" <\"$CORE_HELPER\" >/dev/null; then ssh \"${SSH_BASE[@]}\" \"$CORE\" rm -f -- \"$remote_dump\" \"$remote_img\" >/dev/null 2>&1 || true; die IMMICH_POSTGRES_IMPORT_FAILED 70; fi\n508- ssh \"${SSH_BASE[@]}\" \"$CORE\" rm -f -- \"$remote_dump\" \"$remote_img\" >/dev/null\n509- checks=\"$(jq -n --argjson n \"$expect\" '[{name:\"postgres_import\",result:\"OK\",table_count:$n},{name:\"media_manifest\",result:\"OK\"},{name:\"config_manifest\",result:\"OK\"}]')\" ;;\n510- esac\n511- printf '%s\\n' \"$checks\"\n512-}\n513:restore_validate(){\n514- local app=\"$1\" gen=\"$2\" logical state work payload ex expected_sha checks out tmp\n515- valid_generation \"$gen\" || die GENERATION_INVALID 64\n516- logical=\"$(logical_id \"$app\")\"; state=\"$STATE_ROOT/$logical/$gen.json\"\n517- [[ -s \"$state\" && ! -L \"$state\" ]] || die RESTORE_STATE_MISSING 65\n518- jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' \"$state\" >/dev/null || die RESTORE_REQUIRES_SEALED 65\n519: if restore_ok \"$app\" \"$gen\"; then printf 'RESTORE_VALIDATION_STATUS=OK\\nAPP=%s\\nGENERATION=%s\\nRESULT=ALREADY_VALIDATED\\n' \"$app\" \"$gen\"; return 0; fi\n520- work=\"$RESTORE_WORK_ROOT/$logical/$gen\"; rm -rf --one-file-system \"$work\" 2>/dev/null || true; mkdir -p \"$work/extract\"; chmod 0700 \"$RESTORE_WORK_ROOT\" \"$RESTORE_WORK_ROOT/$logical\" \"$work\" 2>/dev/null || true; ACTIVE_STAGE=\"$work\"\n521- payload=\"$work/payload.tar.zst\"; reconstruct_cloud_a \"$app\" \"$gen\" \"$state\" \"$payload\"\n522- expected_sha=\"$(jq -er '.archive_sha256' \"$state\")\"; [[ \"$(sha256sum \"$payload\"|awk '{print $1}')\" == \"$expected_sha\" ]] || die RESTORE_PAYLOAD_SHA_MISMATCH 70\n523- zstd -t \"$payload\" >/dev/null; zstd -dc \"$payload\" | tar -xf - -C \"$work/extract\"; ex=\"$work/extract\"\n524- verify_binding_components \"$ex\" \"$logical\" \"$gen\"\n525- checks=\"$(semantic_validate \"$app\" \"$gen\" \"$ex\")\"\n526- out=\"$(restore_dir \"$app\")/$gen.json\"; mkdir -p \"$(dirname \"$out\")\"; chmod 0700 \"$RESTORE_STATE_ROOT\" \"$(dirname \"$out\")\"\n527- tmp=\"${out}.new.$$\"\n528: jq -n --arg logical_id \"$logical\" --arg generation \"$gen\" --arg app \"$app\" --arg sha \"$expected_sha\" --arg at \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" --arg state \"$state\" --argjson checks \"$checks\" '{schema:\"homelab-app-restore-validation-v1\",logical_id:$logical_id,generation:$generation,app:$app,transport_state:\"SEALED\",transport_state_file:$state,restore_source:\"Cloud A\",payload_sha256:$sha,payload_sha256_verified:true,result:\"OK\",validated_at_utc:$at,checks:$checks}' >\"$tmp\"\n529- chmod 0600 \"$tmp\"; mv -f \"$tmp\" \"$out\"\n530: jq -e --arg l \"$logical\" --arg g \"$gen\" '.logical_id==$l and .generation==$g and .result==\"OK\" and .transport_state==\"SEALED\" and .payload_sha256_verified==true' \"$out\" >/dev/null\n531- rm -rf --one-file-system \"$work\"; ACTIVE_STAGE=\"\"\n532- printf 'RESTORE_VALIDATION_STATUS=OK\\nAPP=%s\\nGENERATION=%s\\nEVIDENCE=%s\\n' \"$app\" \"$gen\" \"$out\"\n533-}\n534-backup_one(){\n535- local app=\"$1\" logical pending_count state gen payload latest orphan_count\n536- logical=\"$(logical_id \"$app\")\"; mkdir -p \"$STATE_ROOT/$logical\" \"$RESTORE_STATE_ROOT/$logical\" \"$STAGE_ROOT/$logical\"; chmod 0700 \"$STATE_ROOT\" \"$STATE_ROOT/$logical\" \"$RESTORE_STATE_ROOT\" \"$RESTORE_STATE_ROOT/$logical\" \"$STAGE_ROOT\" \"$STAGE_ROOT/$logical\"\n537- mapfile -t pending < <(latest_incomplete \"$app\"); pending_count=\"${#pending[@]}\"; (( pending_count <= 1 )) || die \"MULTIPLE_INCOMPLETE_GENERATIONS_$app\" 65\n538- if (( pending_count == 1 )); then\n539- state=\"${pending[0]}\"; gen=\"$(jq -er '.generation' \"$state\")\"; payload=\"$(jq -er '.payload_path' \"$state\")\"; printf 'RESUME=YES\\nAPP=%s\\nGENERATION=%s\\nSTAGE=TRANSPORT_RESUME\\n' \"$app\" \"$gen\"\n540- \"$TRANSPORT\" backup-delete \"$logical\" \"$gen\" \"$payload\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\"\n541: printf 'STAGE=RESTORE_VALIDATION\\n'; restore_validate \"$app\" \"$gen\"\n542- printf 'BACKUP_STATUS=SEALED\\nAPP=%s\\nGENERATION=%s\\nCLOUD_QUORUM=2\\n' \"$app\" \"$gen\"; return\n543- fi\n544- plan \"$app\" >/dev/null\n545- latest=\"$(latest_sealed_state \"$app\")\"\n546: if [[ -n \"$latest\" ]]; then gen=\"$(jq -er '.generation' \"$latest\")\"; if ! restore_ok \"$app\" \"$gen\"; then printf 'RESUME_RESTORE_VALIDATION=YES\\nAPP=%s\\nGENERATION=%s\\n' \"$app\" \"$gen\"; restore_validate \"$app\" \"$gen\"; printf 'BACKUP_STATUS=SEALED\\nAPP=%s\\nGENERATION=%s\\nCLOUD_QUORUM=2\\n' \"$app\" \"$gen\"; return; fi; fi\n547- if [[ \"$app\" == scrutiny ]]; then\n548- orphan_count=\"$(find \"$STAGE_ROOT/$logical\" -maxdepth 1 -type d -name '.capture-app-scrutiny-*' | wc -l)\"\n549- (( orphan_count == 0 )) || die SCRUTINY_ORPHAN_CAPTURE_REQUIRES_CONTROLLED_RECOVERY 65\n550- fi\n551- gen=\"${logical}-pve01-$(date -u +%Y%m%dT%H%M%SZ)\"; valid_generation \"$gen\" || die GENERATED_ID_INVALID 65\n552- printf 'RESUME=NO\\nAPP=%s\\nGENERATION=%s\\nSTAGE=CAPTURE\\n' \"$app\" \"$gen\"; capture_new \"$app\" \"$gen\"; payload=\"$PAYLOAD\"\n553- printf 'STAGE=TRANSPORT\\n'; \"$TRANSPORT\" backup-delete \"$logical\" \"$gen\" \"$payload\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\"\n554: printf 'STAGE=RESTORE_VALIDATION\\n'; restore_validate \"$app\" \"$gen\"\n555- state=\"$STATE_ROOT/$logical/$gen.json\"; jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .local_payload_present==false and .seal_written==true' \"$state\" >/dev/null\n556- printf 'BACKUP_STATUS=SEALED\\nAPP=%s\\nGENERATION=%s\\nCLOUD_QUORUM=2\\n' \"$app\" \"$gen\"\n557-}\n558-plan(){\n559- local app=\"$1\" logical free\n560- logical=\"$(logical_id \"$app\")\"; free=\"$(df -B1 --output=avail /mnt/staging | tail -n1 | tr -d ' ')\"\n561- [[ \"$free\" =~ ^[1-9][0-9]+$ ]] || die STAGING_FREE_INVALID 65\n562- local source_bytes=0 required=0\n--\n589- ;;\n590- skladchik-reports-monitor) remote_edge probe plan >/dev/null ;;\n591- esac\n592- printf 'PLAN_STATUS=OK\\nAPP=%s\\nLOGICAL_ID=%s\\nSOURCE_HOST=%s\\nSTAGING_FREE_BYTES=%s\\nSOURCE_BYTES=%s\\nREQUIRED_STAGING_BYTES=%s\\n' \"$app\" \"$logical\" \"$(source_host \"$app\")\" \"$free\" \"$source_bytes\" \"$required\"\n593-}\n594-latest_sealed(){\n595- local app=\"$1\" f gen\n596- f=\"$(latest_sealed_state \"$app\")\"; [[ -n \"$f\" ]] || die \"SEALED_STATE_MISSING_$app\" 65; gen=\"$(jq -er '.generation' \"$f\")\"\n597: restore_ok \"$app\" \"$gen\" || die \"LATEST_RESTORE_NOT_OK_$app\" 65\n598: printf 'LATEST_SEALED_STATUS=OK\\nAPP=%s\\nLOGICAL_ID=%s\\nGENERATION=%s\\nSTATE_FILE=%s\\nRESTORE_EVIDENCE=%s\\n' \"$app\" \"$(logical_id \"$app\")\" \"$gen\" \"$f\" \"$(restore_dir \"$app\")/$gen.json\"\n599-}\n600-recover_scrutiny_orphan(){\n601- local gen=\"$1\" started=\"$2\" qstart=\"$3\" qend=\"$4\" expected_config=\"$5\" expected_influx=\"$6\"\n602- local completed unitsha ref iid digest repodigests isize scdb idb devices migrations settings influx_tables tsm_files tsm_bytes wal_files wal_bytes series trange cfgsha boltbytes sqlitebytes image_sha meta_sha config_manifest_sha influx_manifest_sha validation_manifest_sha unit_copy_sha comps report actual_config actual_influx logical state restore\n603- logical=app-scrutiny\n604- valid_generation \"$gen\" || die GENERATION_INVALID 64\n605- [[ \"$gen\" == app-scrutiny-pve01-* ]] || die SCRUTINY_RECOVERY_GENERATION_INVALID 64\n606- [[ \"$started\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ && \"$qstart\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ && \"$qend\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]] || die SCRUTINY_RECOVERY_TIMESTAMP_INVALID 64\n--\n639- if [[ -s \"$state\" && ! -L \"$state\" ]] && jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' \"$state\" >/dev/null 2>&1; then\n640- printf 'RESUME_RESTORE_VALIDATION=YES\\nAPP=scrutiny\\nGENERATION=%s\\n' \"$gen\"\n641- else\n642- [[ -s \"$PAYLOAD\" && ! -L \"$PAYLOAD\" ]] || die SCRUTINY_RECOVERY_PAYLOAD_MISSING_FOR_TRANSPORT 65\n643- printf 'STAGE=TRANSPORT_RESUME\\n'\n644- \"$TRANSPORT\" backup-delete \"$logical\" \"$gen\" \"$PAYLOAD\" \"$REMOTE_A\" \"$REMOTE_B\" \"$STATE_ROOT\"\n645- fi\n646- printf 'STAGE=RESTORE_VALIDATION\\n'\n647: restore_validate scrutiny \"$gen\"\n648- [[ -s \"$state\" && ! -L \"$state\" ]] || die SCRUTINY_RECOVERY_SEALED_STATE_MISSING 70\n649- jq -e '.status==\"SEALED\" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' \"$state\" >/dev/null || die SCRUTINY_RECOVERY_SEALED_STATE_INVALID 70\n650: [[ -s \"$restore\" && ! -L \"$restore\" ]] || die SCRUTINY_RECOVERY_RESTORE_EVIDENCE_MISSING 70\n651: jq -e '.result==\"OK\" and .transport_state==\"SEALED\" and .restore_source==\"Cloud A\" and .payload_sha256_verified==true' \"$restore\" >/dev/null || die SCRUTINY_RECOVERY_RESTORE_EVIDENCE_INVALID 70\n652- printf 'BACKUP_STATUS=SEALED\\nAPP=scrutiny\\nGENERATION=%s\\nCLOUD_QUORUM=2\\n' \"$gen\"\n653-}\n654-\n655-ACTION=\"${1:-}\"\n656-case \"$ACTION\" in\n657- plan) [[ \"$#\" == 2 ]] || die USAGE_PLAN 64; plan \"$2\" ;;\n658- backup) [[ \"$#\" == 2 ]] || die USAGE_BACKUP 64; backup_one \"$2\" ;;\n659: restore-validate) [[ \"$#\" == 3 ]] || die USAGE_RESTORE_VALIDATE 64; logical_id \"$2\" >/dev/null; restore_validate \"$2\" \"$3\" ;;\n660- recover-scrutiny-orphan) [[ \"$#\" == 7 ]] || die USAGE_RECOVER_SCRUTINY_ORPHAN 64; recover_scrutiny_orphan \"$2\" \"$3\" \"$4\" \"$5\" \"$6\" \"$7\" ;;\n661: latest-sealed) [[ \"$#\" == 2 ]] || die USAGE_LATEST_SEALED 64; latest_sealed \"$2\" ;;\n662- *) die ACTION_INVALID 64 ;;\n663-esac\nAPP_RESTORE_CONTRACT_SOURCE_END=1\nAPP_STATE_FILE=/var/lib/homelab-backup/cloud-quorum/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json\nAPP_STATE_SHA256=5a0e9a386c2bf83ebed141ef2687dc687427ac186943029d69a6c075087592cc\nAPP_GENERATION=app-skladchik-reports-monitor-pve01-20260921T175029Z\nAPP_RESTORE_FILE=/var/lib/homelab-backup/app-restore-validation/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json\nAPP_RESTORE_SHA256=b33104501140837eac006f04a8256d19d2bf027d9f06fff7dba1d17199edce8e\nAPP_RESTORE_KEYS_BEGIN=1\n[\"app\",\"checks\",\"generation\",\"logical_id\",\"payload_sha256\",\"payload_sha256_verified\",\"restore_source\",\"result\",\"schema\",\"transport_state\",\"transport_state_file\",\"validated_at_utc\"]\nAPP_RESTORE_KEYS_END=1\nAPP_RESTORE_SAFE_VIEW_BEGIN=1\n{\"schema\":\"homelab-app-restore-validation-v1\",\"result\":\"OK\",\"status\":null,\"logical_id\":\"app-skladchik-reports-monitor\",\"generation\":\"app-skladchik-reports-monitor-pve01-20260921T175029Z\",\"transport_state\":\"SEALED\",\"transport_state_file\":\"/var/lib/homelab-backup/cloud-quorum/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json\",\"restore_source\":\"Cloud A\",\"payload_sha256\":\"8034a3188e933ff7b316e369869561b8a14ef7a1688ab497477035346b43b3dc\",\"payload_sha256_verified\":true,\"payload_decompression_verified\":null,\"archive_recovery_readback_verified\":null,\"parts_manifest_verified\":null,\"bounded_staging\":null,\"full_local_payload_written\":null,\"tar_test_ok\":null,\"required_files_ok\":null,\"cookie_jar_ok\":null,\"sqlite_ok\":null,\"validated_at_utc\":\"2026-09-21T17:50:46Z\"}\nAPP_RESTORE_SAFE_VIEW_END=1\nAPP_RESTORE_BASE_CONTRACT_OK=true\nUS_NETBIRD_STATE_BEGIN=1\nUS_NETBIRD_STATE_SHA256=12d13c0d07056469b1ad4b9328ce29737d1ab76698a4d6115ca1c5648b95ba26\n{\"consecutive_failures\":14,\"failure_backoff_seconds\":21600,\"generation\":\"v2-us-netbird-20260922T055316Z-d5c92acdd2e8\",\"last_attempt_epoch\":1790056411,\"last_success_epoch\":1789704670,\"last_success_generation\":\"v2-us-netbird-20260918T041032Z-d7648be4c16b\",\"last_success_green_verified\":false,\"last_success_manifest_sha256\":\"f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5\",\"last_success_payload_sha256\":\"e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf\",\"last_success_replicas\":[{\"crypt\":\"pve01-mail-05-crypt\",\"physical\":\"pve01-mail-05\"},{\"crypt\":\"pve03-mail-04-crypt\",\"physical\":\"pve03-mail-04\"}],\"logical_id\":\"us-netbird\",\"reason\":\"PIPE_FAILED\",\"result\":\"FAIL\",\"retry_after_epoch\":1790078011,\"schema\":1,\"sealed\":false,\"updated_at_utc\":\"2026-09-22T05:53:31Z\"}\nUS_NETBIRD_STATE_END=1\nPIPE_TO_ZSTD_SOURCE_BEGIN=1\n if not c: return None\n c.sort(key=lambda x:(x[0],x[1],x[2]))\n return c[0][3]\n\ndef run(argv, *, input=None, timeout=300, check=True, env=None):\n try:\n p=subprocess.run(argv,input=input,stdout=subprocess.PIPE,stderr=subprocess.PIPE,timeout=timeout,env=env)\n except subprocess.TimeoutExpired: raise BackupError('COMMAND_TIMEOUT')\n if check and p.returncode!=0: raise BackupError('COMMAND_FAILED',str(p.returncode))\n return p\n\ndef stream_process_to_file(argv,out_path,timeout=1800,input=None):\n out_path=pathlib.Path(out_path)\n with open(out_path,'wb') as f:\n try:p=subprocess.run(argv,input=input,stdout=f,stderr=subprocess.PIPE,timeout=timeout)\n except subprocess.TimeoutExpired: raise BackupError('STREAM_COMMAND_TIMEOUT')\n if p.returncode!=0: raise BackupError('STREAM_COMMAND_FAILED',str(p.returncode))\n\ndef pipe_to_zstd(argv,out_path,timeout=1800,input=None):\n zstd=shutil.which('zstd') or '/usr/bin/zstd'\n try:\n src=subprocess.Popen(argv,stdin=subprocess.PIPE if input is not None else None,stdout=subprocess.PIPE,stderr=subprocess.PIPE)\n z=subprocess.Popen([zstd,'-T0','-3','-q','-o',str(out_path)],stdin=src.stdout,stdout=subprocess.DEVNULL,stderr=subprocess.PIPE)\n if src.stdout: src.stdout.close()\n if input is not None:\n src.stdin.write(input); src.stdin.close()\n zerr=z.communicate(timeout=timeout)[1]\n try: src.wait(timeout=60)\n except subprocess.TimeoutExpired:\n src.kill(); src.wait(); raise BackupError('PIPE_SOURCE_TIMEOUT')\n serr=src.stderr.read() if src.stderr else b''\n except subprocess.TimeoutExpired:\n for q in (src,z):\n try:q.kill()\n except Exception:pass\n raise BackupError('PIPE_TIMEOUT')\n if src.returncode!=0 or z.returncode!=0: raise BackupError('PIPE_FAILED',f'{src.returncode}_{z.returncode}')\n\ndef ensure_dir(p,mode=0o700):\n p=pathlib.Path(p); p.mkdir(parents=True,exist_ok=True); os.chmod(p,mode); return p\n\ndef atomic_write(path,data,mode=0o600):\n path=pathlib.Path(path); ensure_dir(path.parent,0o700)\n fd,tmp=tempfile.mkstemp(prefix='.'+path.name+'.',dir=str(path.parent))\nPIPE_TO_ZSTD_SOURCE_END=1\nUS_REMOTE_SCRIPT_SOURCE_BEGIN=1\n if pre!=post: raise BackupError('SPB_SOURCE_CHANGED_DURING_CAPTURE')\n return payload,{'generation':gen,'source_class':'vps_spb','consistency':'STATIC_CONFIG_FILESET_PRE_POST_HASH_STABILITY','tls_recovery':'REISSUE_TLS_ON_RESTORE','hashset_sha256':pre},None\n\nUS_REMOTE_SCRIPT=r'''import io,os,sqlite3,sys,tarfile,time,json,hashlib\npaths=['/opt/netbird/docker-compose.yml','/opt/netbird/config.yaml']\ndata_root='/var/lib/docker/volumes/netbird_netbird_data/_data'\nle_root='/var/lib/docker/volumes/netbird_netbird_traefik_letsencrypt/_data'\ndbs=['events.db','store.db','geonames_20260602.db','idp.db']\nnon=['GeoLite2-City_20260602.mmdb']\nout=sys.stdout.buffer\nwith tarfile.open(fileobj=out,mode='w|') as tf:\n for p in paths:\n if os.path.isfile(p): tf.add(p,arcname=p.lstrip('/'),recursive=False)\n for name in non:\n p=os.path.join(data_root,name)\n if os.path.isfile(p): tf.add(p,arcname=p.lstrip('/'),recursive=False)\n ac=os.path.join(le_root,'acme.json')\n if os.path.isfile(ac):\n st=os.stat(ac)\n if (st.st_mode & 0o777)!=0o600: raise SystemExit(31)\n json.load(open(ac,'r'))\n tf.add(ac,arcname=ac.lstrip('/'),recursive=False)\n for name in dbs:\n srcp=os.path.join(data_root,name)\n src=sqlite3.connect('file:'+srcp+'?mode=ro',uri=True)\n if src.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(32)\n dst=sqlite3.connect(':memory:'); src.backup(dst)\n if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33)\n b=dst.serialize(); dst.close(); src.close()\n 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))\n'''\n\ndef capture_vps_us(t,gen,work):\n remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT])\n argv=vps_ssh_argv(t,use_agent=False)+[remote]\n payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200)\n return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None\n\ndef _simple_shell_assignments(text):\nUS_REMOTE_SCRIPT_SOURCE_END=1\nVPS_SSH_SOURCE_BEGIN=1\ndef operator_key_fingerprint():\n if not OPERATOR_KEY.is_file() or OPERATOR_KEY.is_symlink(): raise BackupError('OPERATOR_KEY_MISSING')\n p=run(['ssh-keygen','-lf',str(OPERATOR_KEY),'-E','sha256'],timeout=30)\n s=p.stdout.decode('utf-8','replace')\n m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s)\n if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH')\n return m.group(1)\n\ndef scan_hostkey_line(host,port,expected):\n p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15)\n lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')]\n good=[]\n for line in lines:\n f=line.split()\n if len(f)<3 or f[1]!='ssh-ed25519': continue\n try: blob=base64.b64decode(f[2])\n except Exception: continue\n fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=')\n if fp==expected: good.append(line)\n if len(good)!=1: raise BackupError('HOSTKEY_PIN_MISMATCH')\n return good[0]\n\ndef ensure_vps_known_hosts(targets):\n lines=[]\n for t in targets:\n if t['type'] not in ('vps_md','vps_spb','vps_us'): continue\n lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint']))\n atomic_write(VPS_KNOWN_HOSTS,('\\n'.join(lines)+'\\n').encode(),0o600)\n\ndef vps_ssh_argv(t, *, use_agent=False):\n a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15']\n if use_agent:\n a += ['-o','IdentitiesOnly=no']\n else:\n a += ['-i',str(OPERATOR_KEY),'-o','IdentitiesOnly=yes','-o','IdentityAgent=none']\n a += [t['user']+'@'+t['host']]\n return a\n\ndef vps_run(t, remote_argv, *, input=None, timeout=300, use_agent=False, check=True):\n remote=shlex.join([str(x) for x in remote_argv])\n return run(vps_ssh_argv(t,use_agent=use_agent)+[remote],input=input,timeout=timeout,check=check)\n\ndef bootstrap_vps_keys(targets):\n operator_key_fingerprint()\n ensure_vps_known_hosts(targets)\n pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\\n'\n results={}\n for t in targets:\n if t['type'] not in ('vps_md','vps_spb'): continue\n probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False)\n if probe.returncode==0:\n results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue\n if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP')\n 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\"\n p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True)\n tag=p.stdout.decode().strip()\n if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT')\n vps_run(t,['true'],timeout=30,use_agent=False)\n results[t['logical_id']]=tag\n # US was already operator-key based; prove it agentless too.\n us=[x for x in targets if x['type']=='vps_us'][0]\n vps_run(us,['true'],timeout=30,use_agent=False)\n results[us['logical_id']]='ALREADY_US_OPERATOR_KEY'\n return results\n\ndef remote_hashset(t,command):\n p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False)\n return sha256_bytes(p.stdout)\nVPS_SSH_SOURCE_END=1\nUS_NETBIRD_PID_JOURNAL_BEGIN=1\nPID_BEGIN=936114\n2026-09-21T20:30:36+03:00 pve01 homelab-backup-v2[936114]: SELFTEST_REPLACEMENT486=PASS\n2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_TARGET=us-netbird\n2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_RESULT=FAIL\n2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_REASON=PIPE_FAILED\nPID_END=936114\nPID_BEGIN=2121414\n2026-09-22T02:36:58+03:00 pve01 homelab-backup-v2[2121414]: SELFTEST_REPLACEMENT486=PASS\n2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_TARGET=us-netbird\n2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_RESULT=FAIL\n2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_REASON=PIPE_FAILED\nPID_END=2121414\nPID_BEGIN=3378768\n2026-09-22T08:53:16+03:00 pve01 homelab-backup-v2[3378768]: SELFTEST_REPLACEMENT486=PASS\n2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_TARGET=us-netbird\n2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_RESULT=FAIL\n2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_REASON=PIPE_FAILED\nPID_END=3378768\nUS_NETBIRD_PID_JOURNAL_END=1\nUS_NETBIRD_WORK_ARTIFACTS_BEGIN=1\nf|1790056411.7319950600|792|/var/lib/homelab-backup-v2/state/us-netbird.json\nf|1789642259.3981707900|1255|/var/lib/homelab-backup-v2/cold-bootstrap/us-netbird.json\nd|1790056411.7288067540|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260922T055316Z-d5c92acdd2e8\nd|1790033833.7009700260|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T233658Z-709cf01e1256\nd|1790011851.2302881580|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T173036Z-1128898e4cc8\nd|1789989471.8069593230|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T111736Z-c5a5c5e71776\nd|1789955807.6619889330|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T015632Z-dc499030a55f\nd|1789932571.7940614350|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T192916Z-ca2592a81a30\nd|1789908991.7828657500|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T125616Z-8caeb0b6c7b7\nd|1789886227.6266376830|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T063652Z-e6c72515a153\nd|1789862827.7065704150|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T000652Z-7ecdcfcafc12\nd|1789839091.8314245860|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T173116Z-cfc70719f4e9\nd|1789822687.5806853640|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T125752Z-a4efa5c07171\nd|1789814653.6399387990|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T104358Z-b2232f971dbc\nd|1789810393.6722341230|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T093258Z-64f5c2972565\nd|1789807993.6075344840|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T085258Z-36f858f91de5\nUS_NETBIRD_WORK_ARTIFACTS_END=1\nUS_NETBIRD_READONLY_PROBES_BEGIN=1\nUS_NETBIRD_READONLY_PROBE_RC=41\nPROBE_TARGET_FOUND=true\nPROBE_TYPE=vps_us\nPROBE_SSH_TRUE_EXCEPTION=BackupError\nPROBE_SSH_TRUE_CODE=COMMAND_FAILED\nPROBE_SSH_TRUE_DETAIL=255\nUS_NETBIRD_READONLY_PROBE_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\nUS_NETBIRD_READONLY_PROBES_END=1\nUS_NETBIRD_PIPE_BASELINE_CLASS=SSH_BASELINE_FAILURE\nDECISION=PASS_BACKUP_1117_APP_CONTRACT_AND_PIPE_BASELINE_CLASSIFIED\nNEXT_GATE=REPAIR_ONLY_BACKUP_US_NETBIRD_AND_AUDIT_CANONICAL_CLOUDB_SOURCE_OFFHOST\nTASK_RESULT=PASS_HOMELAB_BACKUP_1116_CONTRACT_PIPE_RCA\nCHANGES_MADE_BY_1117=false\nPRODUCT_MUTATION_BY_1117=false\nVM_MUTATION_BY_1117=false\nCLOUD_MUTATION_BY_1117=false\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1\",\"status\":\"OK\",\"changes_made\":false,\"rollback_started\":false,\"rollback_restored\":null}\nWORKERS2_BACKUP_1116_CONTRACT_PIPE_RCA_END=1\n" -} +{"schema_version":1,"channel":"homelab-runtime","command_id":"CONTEXT-AUTO-20260922T061701Z","status":"OK","rc":0,"host":"pve01","mode":"read-only","component":"cluster-context","started_at_utc":"2026-09-22T06:17:01Z","finished_at_utc":"2026-09-22T06:17:02Z","reference_register_checked":true,"reference_sha256":"5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66","error_register_checked":true,"error_register_sha256":"3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0","changes_made":false,"sanitized":true,"secrets_included":false,"private_addresses_included":false,"output":"AUTOMATIC_CLUSTER_CONTEXT_REFRESH=OK"} diff --git a/runtime/latest.txt b/runtime/latest.txt index 790521b2..2f534065 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,423 +1,163 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1 +COMMAND_ID=CONTEXT-AUTO-[PRIVATE_IP]701Z STATUS=OK RC=0 HOST=pve01 -MODE=read-only -COMPONENT=homelab-backup-1116-contract-pipe-rca -REFERENCE_REGISTER_CHECK=OK -REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 -ERROR_REGISTER_CHECK=OK -ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 -COMMAND_SHA256=0ba8e65003a7561a9e01930aa9eec5d2b6a6cd73c9f05d217fca4a399c992fed -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=8314f5500f36a8ab9866f3f778ae569bf18655d73ade7aca6ada77060826a746 -SANITIZED_OUTPUT_SHA256=1c8576db6611dd527a417a275078b31f952af42ddef0dd6dd0fa1661455bb847 +COMPONENT=cluster-context +REFERENCE_SHA[PRIVATE_IP]e5154c41cb[PRIVATE_IP]aca68090be[PRIVATE_IP]bf[PRIVATE_IP]df[PRIVATE_IP] +ERROR_REGISTER_SHA[PRIVATE_IP]ec0f527ed3afeed[PRIVATE_IP]ee[PRIVATE_IP]bbfb[PRIVATE_IP]af4ba7ba0 OUTPUT_BEGIN -WORKERS2_BACKUP_1116_CONTRACT_PIPE_RCA_BEGIN=1 -COMMAND_ID=SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1 -MODE=read-only -COMPONENT=homelab-backup-1116-contract-pipe-rca -MUTATION_BOUNDARY=NONE;READ_ONLY_APP_RESTORE_CONTRACT_AND_US_NETBIRD_PIPE_RCA;NO_SYSTEMCTL_ACTION;NO_BACKUP_TARGET_EXECUTION;NO_RESTORE_EXECUTION;NO_GIT_WRITE;NO_CLOUD_WRITE;REMOTE_PROBES_READ_ONLY -ERROR_REGISTER_CHECK=OK -REFERENCE_CHECK=OK -REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66 -ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0 -RUNNER_SHA256=b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d -WRAPPER_SHA256=5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2 -LEGACY_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7 -APP_WORKER_SHA256=1d6c4a04f762e2a33561c109b0c0a4878caaa48627903e7e78fdf5f22d79f196 -SCHEDULER_RC=0 -SELFTEST_REPLACEMENT486=PASS -SCHEDULER_LIVE_SELECTION=DEFER_NO_DUE_TARGET -APP_RESTORE_CONTRACT_SOURCE_BEGIN=1 -89-} -90-latest_sealed_state(){ -91- local app="$1" d -92- d="$(state_dir "$app")"; [[ -d "$d" ]] || return 0 -93- find "$d" -maxdepth 1 -type f -name '*.json' -printf '%T@|%p\n' | LC_ALL=C sort -t'|' -k1,1nr | while IFS='|' read -r _ f; do -94- if jq -e '.status=="SEALED" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' "$f" >/dev/null 2>&1; then echo "$f"; break; fi -95- done -96-} -97:restore_ok(){ -98- local app="$1" gen="$2" f -99- f="$(restore_dir "$app")/$gen.json" -100- [[ -s "$f" && ! -L "$f" ]] || return 1 -101: jq -e --arg l "$(logical_id "$app")" --arg g "$gen" '.logical_id==$l and .generation==$g and .transport_state=="SEALED" and .restore_source=="Cloud A" and .payload_sha256_verified==true and .result=="OK"' "$f" >/dev/null -102-} -103-remote_core(){ local action="$1" gen="$2"; ssh "${SSH_BASE[@]}" "$CORE" sudo -n /bin/bash -s -- "$action" "$gen" <"$CORE_HELPER"; } -104-remote_edge(){ local action="$1" gen="$2"; ssh "${SSH_BASE[@]}" "$EDGE" sudo -n /bin/bash -s -- "$action" "$gen" <"$EDGE_HELPER"; } -105-rsync_core(){ -106- local src="$1" dst="$2" -107- mkdir -p "$dst" -108- RSYNC_RSH='ssh -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=[SENSITIVE_PATH] rsync -a --numeric-ids --delete --info=progress2 --rsync-path='sudo -n rsync' "$CORE:$src/" "$dst/" -109-} --- -344- [[ -f "$ex/$path" && ! -L "$ex/$path" ]] || die RESTORE_COMPONENT_MISSING 70 -345- actual="$(sha256sum "$ex/$path"|awk '{print $1}')"; [[ "$actual" == "$sha" ]] || die RESTORE_COMPONENT_SHA_MISMATCH 70 -346- done < <(jq -r '.components|to_entries[]|[.value.path,.value.sha256]|@tsv' "$ex/app-generation.json") -347-} -348-reconstruct_cloud_a(){ -349- local app="$1" gen="$2" state="$3" out="$4" logical base manifest expected_msha got_msha idx name size sha part actual -350- logical="$(logical_id "$app")" -351- "$TRANSPORT" verify-sealed "$logical" "$gen" "$REMOTE_A" "$REMOTE_B" "$STATE_ROOT" >/dev/null -352: base="$(jq -er '.remote_a_base' "$state")"; expected_msha="$(jq -er '.parts_manifest_sha256' "$state")" -353- manifest="$(dirname "$out")/PARTS.tsv"; rclone cat "${base%/}/PARTS.tsv" >"$manifest" -354- got_msha="$(sha256sum "$manifest"|awk '{print $1}')"; [[ "$got_msha" == "$expected_msha" ]] || die RESTORE_A_MANIFEST_SHA_MISMATCH 70 -355- : >"$out"; chmod 0600 "$out" -356- while IFS=$'\t' read -r idx name size sha; do -357- [[ "$idx" =~ ^[0-9]{8}$ && "$name" == part-????????.bin && "$size" =~ ^[1-9][0-9]*$ && "$sha" =~ ^[0-9a-f]{64}$ ]] || die RESTORE_A_MANIFEST_ROW_INVALID 70 -358- part="$(dirname "$out")/$name"; rm -f "$part"; rclone cat "${base%/}/payload.parts/$name" >"$part" -359- [[ "$(stat -c %s "$part")" == "$size" ]] || die RESTORE_A_PART_SIZE_MISMATCH 70 -360- actual="$(sha256sum "$part"|awk '{print $1}')"; [[ "$actual" == "$sha" ]] || die RESTORE_A_PART_SHA_MISMATCH 70 --- -505- scp "${SCP_BASE[@]}" "$ex/immich/db/immich.dump" "$CORE:$remote_dump" >/dev/null -506- scp "${SCP_BASE[@]}" "$ACTIVE_STAGE/postgres-image.txt" "$CORE:$remote_img" >/dev/null -507- if ! ssh "${SSH_BASE[@]}" "$CORE" sudo -n /bin/bash -s -- validate-immich-db "$gen" "$remote_dump" "$expect" "$remote_img" <"$CORE_HELPER" >/dev/null; then ssh "${SSH_BASE[@]}" "$CORE" rm -f -- "$remote_dump" "$remote_img" >/dev/null 2>&1 || true; die IMMICH_POSTGRES_IMPORT_FAILED 70; fi -508- ssh "${SSH_BASE[@]}" "$CORE" rm -f -- "$remote_dump" "$remote_img" >/dev/null -509- checks="$(jq -n --argjson n "$expect" '[{name:"postgres_import",result:"OK",table_count:$n},{name:"media_manifest",result:"OK"},{name:"config_manifest",result:"OK"}]')" ;; -510- esac -511- printf '%s\n' "$checks" -512-} -513:restore_validate(){ -514- local app="$1" gen="$2" logical state work payload ex expected_sha checks out tmp -515- valid_generation "$gen" || die GENERATION_INVALID 64 -516- logical="$(logical_id "$app")"; state="$STATE_ROOT/$logical/$gen.json" -517- [[ -s "$state" && ! -L "$state" ]] || die RESTORE_STATE_MISSING 65 -518- jq -e '.status=="SEALED" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' "$state" >/dev/null || die RESTORE_REQUIRES_SEALED 65 -519: if restore_ok "$app" "$gen"; then printf 'RESTORE_VALIDATION_STATUS=OK\nAPP=%s\nGENERATION=%s\nRESULT=ALREADY_VALIDATED\n' "$app" "$gen"; return 0; fi -520- work="$RESTORE_WORK_ROOT/$logical/$gen"; rm -rf --one-file-system "$work" 2>/dev/null || true; mkdir -p "$work/extract"; chmod 0700 "$RESTORE_WORK_ROOT" "$RESTORE_WORK_ROOT/$logical" "$work" 2>/dev/null || true; ACTIVE_STAGE="$work" -521- payload="$work/payload.tar.zst"; reconstruct_cloud_a "$app" "$gen" "$state" "$payload" -522- expected_sha="$(jq -er '.archive_sha256' "$state")"; [[ "$(sha256sum "$payload"|awk '{print $1}')" == "$expected_sha" ]] || die RESTORE_PAYLOAD_SHA_MISMATCH 70 -523- zstd -t "$payload" >/dev/null; zstd -dc "$payload" | tar -xf - -C "$work/extract"; ex="$work/extract" -524- verify_binding_components "$ex" "$logical" "$gen" -525- checks="$(semantic_validate "$app" "$gen" "$ex")" -526- out="$(restore_dir "$app")/$gen.json"; mkdir -p "$(dirname "$out")"; chmod 0700 "$RESTORE_STATE_ROOT" "$(dirname "$out")" -527- tmp="${out}.new.$$" -528: jq -n --arg logical_id "$logical" --arg generation "$gen" --arg app "$app" --arg sha "$expected_sha" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg state "$state" --argjson checks "$checks" '{schema:"homelab-app-restore-validation-v1",logical_id:$logical_id,generation:$generation,app:$app,transport_state:"SEALED",transport_state_file:$state,restore_source:"Cloud A",payload_sha256:$sha,payload_sha256_verified:true,result:"OK",validated_at_utc:$at,checks:$checks}' >"$tmp" -529- chmod 0600 "$tmp"; mv -f "$tmp" "$out" -530: jq -e --arg l "$logical" --arg g "$gen" '.logical_id==$l and .generation==$g and .result=="OK" and .transport_state=="SEALED" and .payload_sha256_verified==true' "$out" >/dev/null -531- rm -rf --one-file-system "$work"; ACTIVE_STAGE="" -532- printf 'RESTORE_VALIDATION_STATUS=OK\nAPP=%s\nGENERATION=%s\nEVIDENCE=%s\n' "$app" "$gen" "$out" -533-} -534-backup_one(){ -535- local app="$1" logical pending_count state gen payload latest orphan_count -536- logical="$(logical_id "$app")"; mkdir -p "$STATE_ROOT/$logical" "$RESTORE_STATE_ROOT/$logical" "$STAGE_ROOT/$logical"; chmod 0700 "$STATE_ROOT" "$STATE_ROOT/$logical" "$RESTORE_STATE_ROOT" "$RESTORE_STATE_ROOT/$logical" "$STAGE_ROOT" "$STAGE_ROOT/$logical" -537- mapfile -t pending < <(latest_incomplete "$app"); pending_count="${#pending[@]}"; (( pending_count <= 1 )) || die "MULTIPLE_INCOMPLETE_GENERATIONS_$app" 65 -538- if (( pending_count == 1 )); then -539- state="${pending[0]}"; gen="$(jq -er '.generation' "$state")"; payload="$(jq -er '.payload_path' "$state")"; printf 'RESUME=YES\nAPP=%s\nGENERATION=%s\nSTAGE=TRANSPORT_RESUME\n' "$app" "$gen" -540- "$TRANSPORT" backup-delete "$logical" "$gen" "$payload" "$REMOTE_A" "$REMOTE_B" "$STATE_ROOT" -541: printf 'STAGE=RESTORE_VALIDATION\n'; restore_validate "$app" "$gen" -542- printf 'BACKUP_STATUS=SEALED\nAPP=%s\nGENERATION=%s\nCLOUD_QUORUM=2\n' "$app" "$gen"; return -543- fi -544- plan "$app" >/dev/null -545- latest="$(latest_sealed_state "$app")" -546: if [[ -n "$latest" ]]; then gen="$(jq -er '.generation' "$latest")"; if ! restore_ok "$app" "$gen"; then printf 'RESUME_RESTORE_VALIDATION=YES\nAPP=%s\nGENERATION=%s\n' "$app" "$gen"; restore_validate "$app" "$gen"; printf 'BACKUP_STATUS=SEALED\nAPP=%s\nGENERATION=%s\nCLOUD_QUORUM=2\n' "$app" "$gen"; return; fi; fi -547- if [[ "$app" == scrutiny ]]; then -548- orphan_count="$(find "$STAGE_ROOT/$logical" -maxdepth 1 -type d -name '.capture-app-scrutiny-*' | wc -l)" -549- (( orphan_count == 0 )) || die SCRUTINY_ORPHAN_CAPTURE_REQUIRES_CONTROLLED_RECOVERY 65 -550- fi -551- gen="${logical}-pve01-$(date -u +%Y%m%dT%H%M%SZ)"; valid_generation "$gen" || die GENERATED_ID_INVALID 65 -552- printf 'RESUME=NO\nAPP=%s\nGENERATION=%s\nSTAGE=CAPTURE\n' "$app" "$gen"; capture_new "$app" "$gen"; payload="$PAYLOAD" -553- printf 'STAGE=TRANSPORT\n'; "$TRANSPORT" backup-delete "$logical" "$gen" "$payload" "$REMOTE_A" "$REMOTE_B" "$STATE_ROOT" -554: printf 'STAGE=RESTORE_VALIDATION\n'; restore_validate "$app" "$gen" -555- state="$STATE_ROOT/$logical/$gen.json"; jq -e '.status=="SEALED" and .cloud_quorum==2 and .local_payload_present==false and .seal_written==true' "$state" >/dev/null -556- printf 'BACKUP_STATUS=SEALED\nAPP=%s\nGENERATION=%s\nCLOUD_QUORUM=2\n' "$app" "$gen" -557-} -558-plan(){ -559- local app="$1" logical free -560- logical="$(logical_id "$app")"; free="$(df -B1 --output=avail /mnt/staging | tail -n1 | tr -d ' ')" -561- [[ "$free" =~ ^[1-9][0-9]+$ ]] || die STAGING_FREE_INVALID 65 -562- local source_bytes=0 required=0 --- -589- ;; -590- skladchik-reports-monitor) remote_edge probe plan >/dev/null ;; -591- esac -592- printf 'PLAN_STATUS=OK\nAPP=%s\nLOGICAL_ID=%s\nSOURCE_HOST=%s\nSTAGING_FREE_BYTES=%s\nSOURCE_BYTES=%s\nREQUIRED_STAGING_BYTES=%s\n' "$app" "$logical" "$(source_host "$app")" "$free" "$source_bytes" "$required" -593-} -594-latest_sealed(){ -595- local app="$1" f gen -596- f="$(latest_sealed_state "$app")"; [[ -n "$f" ]] || die "SEALED_STATE_MISSING_$app" 65; gen="$(jq -er '.generation' "$f")" -597: restore_ok "$app" "$gen" || die "LATEST_RESTORE_NOT_OK_$app" 65 -598: printf 'LATEST_SEALED_STATUS=OK\nAPP=%s\nLOGICAL_ID=%s\nGENERATION=%s\nSTATE_FILE=%s\nRESTORE_EVIDENCE=%s\n' "$app" "$(logical_id "$app")" "$gen" "$f" "$(restore_dir "$app")/$gen.json" -599-} -600-recover_scrutiny_orphan(){ -601- local gen="$1" started="$2" qstart="$3" qend="$4" expected_config="$5" expected_influx="$6" -602- local completed unitsha ref iid digest repodigests isize scdb idb devices migrations settings influx_tables tsm_files tsm_bytes wal_files wal_bytes series trange cfgsha boltbytes sqlitebytes image_sha meta_sha config_manifest_sha influx_manifest_sha validation_manifest_sha unit_copy_sha comps report actual_config actual_influx logical state restore -603- logical=app-scrutiny -604- valid_generation "$gen" || die GENERATION_INVALID 64 -605- [[ "$gen" == app-scrutiny-pve01-* ]] || die SCRUTINY_RECOVERY_GENERATION_INVALID 64 -606- [[ "$started" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ && "$qstart" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ && "$qend" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]] || die SCRUTINY_RECOVERY_TIMESTAMP_INVALID 64 --- -639- if [[ -s "$state" && ! -L "$state" ]] && jq -e '.status=="SEALED" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' "$state" >/dev/null 2>&1; then -640- printf 'RESUME_RESTORE_VALIDATION=YES\nAPP=scrutiny\nGENERATION=%s\n' "$gen" -641- else -642- [[ -s "$PAYLOAD" && ! -L "$PAYLOAD" ]] || die SCRUTINY_RECOVERY_PAYLOAD_MISSING_FOR_TRANSPORT 65 -643- printf 'STAGE=TRANSPORT_RESUME\n' -644- "$TRANSPORT" backup-delete "$logical" "$gen" "$PAYLOAD" "$REMOTE_A" "$REMOTE_B" "$STATE_ROOT" -645- fi -646- printf 'STAGE=RESTORE_VALIDATION\n' -647: restore_validate scrutiny "$gen" -648- [[ -s "$state" && ! -L "$state" ]] || die SCRUTINY_RECOVERY_SEALED_STATE_MISSING 70 -649- jq -e '.status=="SEALED" and .cloud_quorum==2 and .seal_written==true and .local_payload_present==false' "$state" >/dev/null || die SCRUTINY_RECOVERY_SEALED_STATE_INVALID 70 -650: [[ -s "$restore" && ! -L "$restore" ]] || die SCRUTINY_RECOVERY_RESTORE_EVIDENCE_MISSING 70 -651: jq -e '.result=="OK" and .transport_state=="SEALED" and .restore_source=="Cloud A" and .payload_sha256_verified==true' "$restore" >/dev/null || die SCRUTINY_RECOVERY_RESTORE_EVIDENCE_INVALID 70 -652- printf 'BACKUP_STATUS=SEALED\nAPP=scrutiny\nGENERATION=%s\nCLOUD_QUORUM=2\n' "$gen" -653-} -654- -655-ACTION="${1:-}" -656-case "$ACTION" in -657- plan) [[ "$#" == 2 ]] || die USAGE_PLAN 64; plan "$2" ;; -658- backup) [[ "$#" == 2 ]] || die USAGE_BACKUP 64; backup_one "$2" ;; -659: restore-validate) [[ "$#" == 3 ]] || die USAGE_RESTORE_VALIDATE 64; logical_id "$2" >/dev/null; restore_validate "$2" "$3" ;; -660- recover-scrutiny-orphan) [[ "$#" == 7 ]] || die USAGE_RECOVER_SCRUTINY_ORPHAN 64; recover_scrutiny_orphan "$2" "$3" "$4" "$5" "$6" "$7" ;; -661: latest-sealed) [[ "$#" == 2 ]] || die USAGE_LATEST_SEALED 64; latest_sealed "$2" ;; -662- *) die ACTION_INVALID 64 ;; -663-esac -APP_RESTORE_CONTRACT_SOURCE_END=1 -APP_STATE_FILE=/var/lib/homelab-backup/cloud-quorum/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json -APP_STATE_SHA256=5a0e9a386c2bf83ebed141ef2687dc687427ac186943029d69a6c075087592cc -APP_GENERATION=app-skladchik-reports-monitor-pve01-20260921T175029Z -APP_RESTORE_FILE=/var/lib/homelab-backup/app-restore-validation/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json -APP_RESTORE_SHA256=b33104501140837eac006f04a8256d19d2bf027d9f06fff7dba1d17199edce8e -APP_RESTORE_KEYS_BEGIN=1 -["app","checks","generation","logical_id","payload_sha256","payload_sha256_verified","restore_source","result","schema","transport_state","transport_state_file","validated_at_utc"] -APP_RESTORE_KEYS_END=1 -APP_RESTORE_SAFE_VIEW_BEGIN=1 -{"schema":"homelab-app-restore-validation-v1","result":"OK","status":null,"logical_id":"app-skladchik-reports-monitor","generation":"app-skladchik-reports-monitor-pve01-20260921T175029Z","transport_state":"SEALED","transport_state_file":"/var/lib/homelab-backup/cloud-quorum/app-skladchik-reports-monitor/app-skladchik-reports-monitor-pve01-20260921T175029Z.json","restore_source":"Cloud A","payload_sha256":"8034a3188e933ff7b316e369869561b8a14ef7a1688ab497477035346b43b3dc","payload_sha256_verified":true,"payload_decompression_verified":null,"archive_recovery_readback_verified":null,"parts_manifest_verified":null,"bounded_staging":null,"full_local_payload_written":null,"tar_test_ok":null,"required_files_ok":null,"cookie_jar_ok":null,"sqlite_ok":null,"validated_at_utc":"2026-09-21T17:50:46Z"} -APP_RESTORE_SAFE_VIEW_END=1 -APP_RESTORE_BASE_CONTRACT_OK=true -US_NETBIRD_STATE_BEGIN=1 -US_NETBIRD_STATE_SHA256=12d13c0d07056469b1ad4b9328ce29737d1ab76698a4d6115ca1c5648b95ba26 -{"consecutive_failures":14,"failure_backoff_seconds":21600,"generation":"v2-us-netbird-20260922T055316Z-d5c92acdd2e8","last_attempt_epoch":1790056411,"last_success_epoch":1789704670,"last_success_generation":"v2-us-netbird-20260918T041032Z-d7648be4c16b","last_success_green_verified":false,"last_success_manifest_sha256":"f82c761cafe8aa43d90d0b4b6124933799b5087d34daf880791d850d0d15cee5","last_success_payload_sha256":"e41e3e012442ef41da1c667d7f5fbe4fd52786b0bb5ffca195660750c773efbf","last_success_replicas":[{"crypt":"pve01-mail-05-crypt","physical":"pve01-mail-05"},{"crypt":"pve03-mail-04-crypt","physical":"pve03-mail-04"}],"logical_id":"us-netbird","reason":"PIPE_FAILED","result":"FAIL","retry_after_epoch":1790078011,"schema":1,"sealed":false,"updated_at_utc":"2026-09-22T05:53:31Z"} -US_NETBIRD_STATE_END=1 -PIPE_TO_ZSTD_SOURCE_BEGIN=1 - if not c: return None - c.sort(key=lambda x:(x[0],x[1],x[2])) - return c[0][3] +GENERATED_AT_UTC=[PRIVATE_IP]T06:17:01Z +Cluster information +------------------- +Name: homelab +Config Version: 3 +Transport: knet +Secure auth: on -def run(argv, *, input=None, timeout=300, check=True, env=None): - try: - p=subprocess.run(argv,input=input,stdout=subprocess.PIPE,stderr=subprocess.PIPE,timeout=timeout,env=env) - except subprocess.TimeoutExpired: raise BackupError('COMMAND_TIMEOUT') - if check and p.returncode!=0: raise BackupError('COMMAND_FAILED',str(p.returncode)) - return p +Quorum information +------------------ +Date: Tue Sep [PRIVATE_IP] 2026 +Quorum provider: corosync_votequorum +Nodes: 3 +Node ID: [PRIVATE_IP] +Ring ID: 1.130 +Quorate: Yes -def stream_process_to_file(argv,out_path,timeout=1800,input=None): - out_path=pathlib.Path(out_path) - with open(out_path,'wb') as f: - try:p=subprocess.run(argv,input=input,stdout=f,stderr=subprocess.PIPE,timeout=timeout) - except subprocess.TimeoutExpired: raise BackupError('STREAM_COMMAND_TIMEOUT') - if p.returncode!=0: raise BackupError('STREAM_COMMAND_FAILED',str(p.returncode)) +Votequorum information +---------------------- +Expected votes: 3 +Highest expected: 3 +Total votes: 3 +Quorum: 2 +Flags: Quorate -def pipe_to_zstd(argv,out_path,timeout=1800,input=None): - zstd=shutil.which('zstd') or '/usr/bin/zstd' - try: - src=subprocess.Popen(argv,stdin=subprocess.PIPE if input is not None else None,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - z=subprocess.Popen([zstd,'-T0','-3','-q','-o',str(out_path)],stdin=src.stdout,stdout=subprocess.DEVNULL,stderr=subprocess.PIPE) - if src.stdout: src.stdout.close() - if input is not None: - src.stdin.write(input); src.stdin.close() - zerr=z.communicate(timeout=timeout)[1] - try: src.wait(timeout=60) - except subprocess.TimeoutExpired: - src.kill(); src.wait(); raise BackupError('PIPE_SOURCE_TIMEOUT') - serr=src.stderr.read() if src.stderr else b'' - except subprocess.TimeoutExpired: - for q in (src,z): - try:q.kill() - except Exception:pass - raise BackupError('PIPE_TIMEOUT') - if src.returncode!=0 or z.returncode!=0: raise BackupError('PIPE_FAILED',f'{src.returncode}_{z.returncode}') +Membership information +---------------------- + Nodeid Votes Name +[PRIVATE_IP] [PRIVATE_IP].11 (local) +[PRIVATE_IP] [PRIVATE_IP].13 +[PRIVATE_IP] [PRIVATE_IP].12 -def ensure_dir(p,mode=0o700): - p=pathlib.Path(p); p.mkdir(parents=True,exist_ok=True); os.chmod(p,mode); return p +Membership information +---------------------- + Nodeid Votes Name + 1 1 pve01 (local) + 2 1 pve03 + 3 1 pve02 +[{"cpu":[PRIVATE_IP]507669,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/100","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"pvepro-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":191789,"vmid":100},{"cpu":0,"disk":0,"diskread":0,"diskwrite":0,"id":"qemu/101","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":0,"memhost":0,"name":"pvepro-staging-v1","netin":0,"netout":0,"node":"pve01","status":"stopped","template":0,"type":"qemu","uptime":0,"vmid":101},{"cpu":[PRIVATE_IP][PRIVATE_IP],"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/110","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"dns1","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":110},{"cpu":[PRIVATE_IP]812998,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/111","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"dns2","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":111},{"cpu":[PRIVATE_IP]427e-05,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/112","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"unbound1","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":112},{"cpu":[PRIVATE_IP]832e-05,"disk":[PRIVATE_IP],"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"lxc/113","maxcpu":1,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":0,"name":"unbound2","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"lxc","uptime":[PRIVATE_IP],"vmid":113},{"cpu":[PRIVATE_IP]61437,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/130","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"edge-vm","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":130},{"cpu":[PRIVATE_IP]06647,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/150","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"snikket","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":150},{"cpu":[PRIVATE_IP]724704,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/160","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"forum-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve02","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":160},{"cpu":[PRIVATE_IP]41414,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/170","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"core-apps","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":170},{"cpu":[PRIVATE_IP]09203,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/171","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"monitoring","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":171},{"cpu":[PRIVATE_IP]046608,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/190","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"homelab-ops-worker","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":190},{"cpu":[PRIVATE_IP]015338,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/210","maxcpu":2,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"newfi-prod","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve01","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":210},{"cpu":[PRIVATE_IP]411014,"disk":0,"diskread":[PRIVATE_IP],"diskwrite":[PRIVATE_IP],"id":"qemu/211","maxcpu":2,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"memhost":[PRIVATE_IP],"name":"newfi-staging","netin":[PRIVATE_IP],"netout":[PRIVATE_IP],"node":"pve03","status":"running","template":0,"type":"qemu","uptime":[PRIVATE_IP],"vmid":211},{"cpu":0,"disk":0,"diskread":0,"diskwrite":0,"id":"qemu/9130","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":0,"memhost":0,"name":"edge-cold-standby","netin":0,"netout":0,"node":"pve02","status":"stopped","template":0,"type":"qemu","uptime":0,"vmid":9130},{"cgroup-mode":2,"cpu":[PRIVATE_IP]49991,"disk":[PRIVATE_IP],"id":"node/pve02","level":"","maxcpu":4,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve02","status":"online","type":"node","uptime":[PRIVATE_IP]},{"cgroup-mode":2,"cpu":[PRIVATE_IP]55929,"disk":[PRIVATE_IP],"id":"node/pve01","level":"","maxcpu":24,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve01","status":"online","type":"node","uptime":[PRIVATE_IP]},{"cgroup-mode":2,"cpu":[PRIVATE_IP]56779,"disk":[PRIVATE_IP],"id":"node/pve03","level":"","maxcpu":8,"maxdisk":[PRIVATE_IP],"maxmem":[PRIVATE_IP],"mem":[PRIVATE_IP],"node":"pve03","status":"online","type":"node","uptime":[PRIVATE_IP]},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve02/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve02","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve01/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve01","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"images,rootdir","disk":[PRIVATE_IP],"id":"storage/pve03/local-lvm","maxdisk":[PRIVATE_IP],"node":"pve03","plugintype":"lvmthin","shared":0,"status":"available","storage":"local-lvm","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve02/local","maxdisk":[PRIVATE_IP],"node":"pve02","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve01/local","maxdisk":[PRIVATE_IP],"node":"pve01","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"content":"iso,backup,import,vztmpl","disk":[PRIVATE_IP],"id":"storage/pve03/local","maxdisk":[PRIVATE_IP],"node":"pve03","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"id":"network/pve02/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve02","status":"ok","type":"network"},{"id":"network/pve01/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve01","status":"ok","type":"network"},{"id":"network/pve03/zone/localnetwork","network":"localnetwork","network-type":"zone","node":"pve03","status":"ok","type":"network"}] +Name Type Status Total (KiB) Used (KiB) Available (KiB) % +local dir active [PRIVATE_IP] [PRIVATE_IP] [PRIVATE_IP] 37.33% +local-lvm lvmthin active [PRIVATE_IP] [PRIVATE_IP] [PRIVATE_IP] 15.64% + UNIT LOAD ACTIVE SUB DESCRIPTION +● homelab-backup-audit.service loaded failed failed Homelab unified backup and DR audit +● homelab-backup-v2.service loaded failed failed Homelab Backup V2 manifest-driven scheduler -def atomic_write(path,data,mode=0o600): - path=pathlib.Path(path); ensure_dir(path.parent,0o700) - fd,tmp=tempfile.mkstemp(prefix='.'+path.name+'.',dir=str(path.parent)) -PIPE_TO_ZSTD_SOURCE_END=1 -US_REMOTE_SCRIPT_SOURCE_BEGIN=1 - if pre!=post: raise BackupError('SPB_SOURCE_CHANGED_DURING_CAPTURE') - return payload,{'generation':gen,'source_class':'vps_spb','consistency':'STATIC_CONFIG_FILESET_PRE_POST_HASH_STABILITY','tls_recovery':'REISSUE_TLS_ON_RESTORE','hashset_sha256':pre},None +Legend: LOAD → Reflects whether the unit definition was properly loaded. + ACTIVE → The high-level unit activation state, i.e. generalization of SUB. + SUB → The low-level unit activation state, values depend on unit type. -US_REMOTE_SCRIPT=r'''import io,os,sqlite3,sys,tarfile,time,json,hashlib -paths=['/opt/netbird/docker-compose.yml','/opt/netbird/config.yaml'] -data_root='/var/lib/docker/volumes/netbird_netbird_data/_data' -le_root='/var/lib/docker/volumes/netbird_netbird_traefik_letsencrypt/_data' -dbs=['events.db','store.db','geonames_20260602.db','idp.db'] -non=['GeoLite2-City_20260602.mmdb'] -out=sys.stdout.buffer -with tarfile.open(fileobj=out,mode='w|') as tf: - for p in paths: - if os.path.isfile(p): tf.add(p,arcname=p.lstrip('/'),recursive=False) - for name in non: - p=os.path.join(data_root,name) - if os.path.isfile(p): tf.add(p,arcname=p.lstrip('/'),recursive=False) - ac=os.path.join(le_root,'acme.json') - if os.path.isfile(ac): - st=os.stat(ac) - if (st.st_mode & 0o777)!=0o600: raise SystemExit(31) - json.load(open(ac,'r')) - tf.add(ac,arcname=ac.lstrip('/'),recursive=False) - for name in dbs: - srcp=os.path.join(data_root,name) - src=sqlite3.connect('file:'+srcp+'?mode=ro',uri=True) - if src.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(32) - dst=sqlite3.connect(':memory:'); src.backup(dst) - if dst.execute('pragma quick_check').fetchone()[0]!='ok': raise SystemExit(33) - b=dst.serialize(); dst.close(); src.close() - 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)) -''' +2 loaded units listed. +NEXT LEFT LAST PASSED UNIT ACTIVATES +Tue [PRIVATE_IP] 09:17:16 MSK 13s Tue [PRIVATE_IP] 09:16:16 MSK 46s ago homelab-private-vpn-hosts-health.timer homelab-private-vpn-hosts-health.service +Tue [PRIVATE_IP] 09:17:51 MSK 48s Tue [PRIVATE_IP] 09:16:49 MSK 13s ago homelab-router-watchdog.timer homelab-router-watchdog.service +Tue [PRIVATE_IP] 09:19:03 MSK 2min 1s Tue [PRIVATE_IP] 09:13:45 MSK 3min 16s ago homelab-health-metrics.timer homelab-health-metrics.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:11:59 MSK 5min ago skladchik-reports-monitor-supervisor.timer skladchik-reports-monitor-supervisor.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:06:59 MSK 10min ago prometheus-node-exporter-apt.timer prometheus-node-exporter-apt.service +Tue [PRIVATE_IP] 09:21:59 MSK 4min 56s Tue [PRIVATE_IP] 09:16:59 MSK 3s ago homelab-smartctl-textfile.timer homelab-smartctl-textfile.service +Tue [PRIVATE_IP] 09:25:31 MSK 8min Tue [PRIVATE_IP] 08:53:16 MSK 23min ago homelab-backup-v2.timer homelab-backup-v2.service +Tue [PRIVATE_IP] 09:26:03 MSK 9min Tue [PRIVATE_IP] 09:10:59 MSK 6min ago homelab-alertmanager-backup-health.timer homelab-alertmanager-backup-health.service +Tue [PRIVATE_IP] 09:27:59 MSK 10min Tue [PRIVATE_IP] 09:12:59 MSK 4min 3s ago homelab-disk-space-health.timer homelab-disk-space-health.service +Tue [PRIVATE_IP] 09:27:59 MSK 10min Tue [PRIVATE_IP] 09:12:59 MSK 4min 3s ago prometheus-node-exporter-nvme.timer prometheus-node-exporter-nvme.service +Tue [PRIVATE_IP] 09:28:37 MSK 11min Tue [PRIVATE_IP] 08:56:32 MSK 20min ago homelab-reference-refresh.timer homelab-reference-refresh.service +Tue [PRIVATE_IP] 09:29:59 MSK 12min Tue [PRIVATE_IP] 09:14:59 MSK 2min 3s ago homelab-pve03-staging-capacity-health.timer homelab-pve03-staging-capacity-health.service +Tue [PRIVATE_IP] 09:30:00 MSK 12min Tue [PRIVATE_IP] 07:30:15 MSK 1h 46min ago homelab-app-cloud-quorum-queue.timer homelab-app-cloud-quorum-queue.service +Tue [PRIVATE_IP] 09:30:00 MSK 12min Tue [PRIVATE_IP] 09:15:12 MSK 1min 50s ago homelab-incident-journal.timer homelab-incident-journal.service +Tue [PRIVATE_IP] 09:30:34 MSK 13min Tue [PRIVATE_IP] 09:15:59 MSK 1min 3s ago homelab-external-probe-vps-health.timer homelab-external-probe-vps-health.service +Tue [PRIVATE_IP] 09:31:15 MSK 14min Tue [PRIVATE_IP] 09:16:45 MSK 16s ago homelab-duty-admin-v2.timer homelab-duty-admin-v2.service +Tue [PRIVATE_IP] 09:31:26 MSK 14min Tue [PRIVATE_IP] 09:15:42 MSK 1min 20s ago homelab-forum-snuffleupagus-health.timer homelab-forum-snuffleupagus-health.service +Tue [PRIVATE_IP] 09:34:27 MSK 17min Tue [PRIVATE_IP] 09:04:58 MSK 12min ago homelab-mkdocs-auto-refresh.timer homelab-mkdocs-auto-refresh.service +Tue [PRIVATE_IP] 09:35:22 MSK 18min Tue [PRIVATE_IP] 09:05:13 MSK 11min ago homelab-backup-audit.timer homelab-backup-audit.service +Tue [PRIVATE_IP] 10:15:00 MSK 57min Mon [PRIVATE_IP] 10:15:00 MSK 23h ago skladchik-reports-monitor-monthly-selftest-watch.timer skladchik-reports-monitor-monthly-selftest-watch.service +Tue [PRIVATE_IP] 10:35:59 MSK 1h 18min Tue [PRIVATE_IP] 04:35:59 MSK 4h 41min ago homelab-vps-identity-audit.timer homelab-vps-identity-audit.service +Tue [PRIVATE_IP] 13:16:26 MSK 3h 59min Tue [PRIVATE_IP] 07:09:07 MSK 2h 7min ago homelab-evidence-root.timer homelab-evidence-root.service +Tue [PRIVATE_IP] 14:44:55 MSK 5h 27min Tue [PRIVATE_IP] 08:42:59 MSK 34min ago homelab-mailru-trash-gc.timer homelab-mailru-trash-gc.service +Tue [PRIVATE_IP] 16:47:58 MSK 7h Mon [PRIVATE_IP] 16:47:58 MSK 16h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service +Tue [PRIVATE_IP] 17:40:23 MSK 8h Mon [PRIVATE_IP] 19:10:54 MSK 14h ago apt-daily.timer apt-daily.service +Wed [PRIVATE_IP] 00:00:00 MSK 14h Tue [PRIVATE_IP] 00:00:15 MSK 9h ago dpkg-db-backup.timer dpkg-db-backup.service +Wed [PRIVATE_IP] 00:04:00 MSK 14h Tue [PRIVATE_IP] 00:14:16 MSK 9h ago homelab-docker-health.timer homelab-docker-health.service +Wed [PRIVATE_IP] 00:05:26 MSK 14h Tue [PRIVATE_IP] 00:01:16 MSK 9h ago homelab-evidence-catalog.timer homelab-evidence-catalog.service +Wed [PRIVATE_IP] 00:09:18 MSK 14h Tue [PRIVATE_IP] 00:11:58 MSK 9h ago homelab-quality-gate.timer homelab-quality-gate.service +Wed [PRIVATE_IP] 00:11:10 MSK 14h Tue [PRIVATE_IP] 00:13:45 MSK 9h ago homelab-storage-capacity.timer homelab-storage-capacity.service +Wed [PRIVATE_IP] 00:23:23 MSK 15h Tue [PRIVATE_IP] 00:17:32 MSK 8h ago logrotate.timer logrotate.service +Wed [PRIVATE_IP] 01:43:37 MSK 16h Tue [PRIVATE_IP] 01:58:53 MSK 7h ago pve-daily-update.timer pve-daily-update.service +Wed [PRIVATE_IP] 03:23:23 MSK 18h Tue [PRIVATE_IP] 03:23:32 MSK 5h 53min ago homelab-backup-retention-gc.timer homelab-backup-retention-gc.service +Wed [PRIVATE_IP] 06:05:55 MSK 20h Tue [PRIVATE_IP] 06:01:58 MSK 3h 15min ago apt-daily-upgrade.timer apt-daily-upgrade.service +Wed [PRIVATE_IP] 07:00:09 MSK 21h Tue [PRIVATE_IP] 07:05:52 MSK 2h 11min ago homelab-drift-check.timer homelab-drift-check.service +Wed [PRIVATE_IP] 07:37:32 MSK 22h Tue [PRIVATE_IP] 07:32:58 MSK 1h 44min ago homelab-service-registry-check.timer homelab-service-registry-check.service +Wed [PRIVATE_IP] 07:41:08 MSK 22h Tue [PRIVATE_IP] 07:55:16 MSK 1h 21min ago homelab-dependency-map-check.timer homelab-dependency-map-check.service +Wed [PRIVATE_IP] 07:45:08 MSK 22h Tue [PRIVATE_IP] 07:53:32 MSK 1h 23min ago homelab-alerting-health.timer homelab-alerting-health.service +Wed [PRIVATE_IP] 07:49:54 MSK 22h Tue [PRIVATE_IP] 07:52:16 MSK 1h 24min ago homelab-runbook-generate.timer homelab-runbook-generate.service +Wed [PRIVATE_IP] 07:54:04 MSK 22h Tue [PRIVATE_IP] 08:00:58 MSK 1h 16min ago homelab-desired-state-sync.timer homelab-desired-state-sync.service +Wed [PRIVATE_IP] 08:06:21 MSK 22h Tue [PRIVATE_IP] 08:01:32 MSK 1h 15min ago homelab-duty-admin-report.timer homelab-duty-admin-report.service +Wed [PRIVATE_IP] 08:13:48 MSK 22h Tue [PRIVATE_IP] 08:11:58 MSK 1h 5min ago homelab-overall-health.timer homelab-overall-health.service +Wed [PRIVATE_IP] 08:16:23 MSK 22h Tue [PRIVATE_IP] 08:12:58 MSK 1h 4min ago homelab-kuma-monitor-policy.timer homelab-kuma-monitor-policy.service +Wed [PRIVATE_IP] 08:18:31 MSK 23h Tue [PRIVATE_IP] 08:19:32 MSK 57min ago homelab-final-readiness-gate.timer homelab-final-readiness-gate.service +Wed [PRIVATE_IP] 08:39:26 MSK 23h Tue [PRIVATE_IP] 08:28:45 MSK 48min ago homelab-capacity-risk.timer homelab-capacity-risk.service +Wed [PRIVATE_IP] 08:40:06 MSK 23h Tue [PRIVATE_IP] 08:43:32 MSK 33min ago homelab-secret-exposure-guard.timer homelab-secret-exposure-guard.service +Wed [PRIVATE_IP] 08:48:42 MSK 23h Tue [PRIVATE_IP] 08:51:11 MSK 25min ago homelab-cluster-passport.timer homelab-cluster-passport.service +Wed [PRIVATE_IP] 08:49:21 MSK 23h Tue [PRIVATE_IP] 09:01:45 MSK 15min ago homelab-golden-state-index.timer homelab-golden-state-index.service +Wed [PRIVATE_IP] 11:04:23 MSK 1 day 1h Tue [PRIVATE_IP] 08:22:45 MSK 54min ago man-db.timer man-db.service +Sun [PRIVATE_IP] 03:10:02 MSK 4 days Sun [PRIVATE_IP] 03:10:58 MSK 2 days ago xfs_scrub_all.timer xfs_scrub_all.service +Sun [PRIVATE_IP] 03:10:39 MSK 4 days Sun [PRIVATE_IP] 03:10:12 MSK 2 days ago e2scrub_all.timer e2scrub_all.service +Sun [PRIVATE_IP] 06:43:52 MSK 4 days Sun [PRIVATE_IP] 07:40:22 MSK 2 days ago homelab-rotating-boot-drill.timer homelab-rotating-boot-drill.service +Mon [PRIVATE_IP] 00:01:03 MSK 5 days Mon [PRIVATE_IP] 00:04:44 MSK 1 day 9h ago homelab-secret-sanity.timer homelab-secret-sanity.service +Mon [PRIVATE_IP] 00:15:22 MSK 5 days Mon [PRIVATE_IP] 00:09:14 MSK 1 day 9h ago fstrim.timer fstrim.service +- - Tue [PRIVATE_IP] 09:16:59 MSK 3s ago netbird-peers-health.timer netbird-peers-health.service +- - - - prometheus-node-exporter-ipmitool-sensor.timer prometheus-node-exporter-ipmitool-sensor.service +- - - - prometheus-node-exporter-mellanox-hca-temp.timer prometheus-node-exporter-mellanox-hca-temp.service +- - - - prometheus-node-exporter-smartmon.timer prometheus-node-exporter-smartmon.service -def capture_vps_us(t,gen,work): - remote=shlex.join(['python3','-I','-B','-c',US_REMOTE_SCRIPT]) - argv=vps_ssh_argv(t,use_agent=False)+[remote] - payload=work/'payload.tar.zst'; pipe_to_zstd(argv,payload,timeout=1200) - return payload,{'generation':gen,'source_class':'vps_us','consistency':'SQLITE_ONLINE_BACKUP_PLUS_NONDB_FILES','sqlite_count':4},None +58 timers listed. +RUNTIME_MANIFEST_ID=df[PRIVATE_IP]ac9b5abd[PRIVATE_IP]b[PRIVATE_IP]d89496fb2bde[PRIVATE_IP] +EXPERIMENT_ID=5462ee[PRIVATE_IP]ebe[PRIVATE_IP]feb2ad[PRIVATE_IP]1ad87bbac0b8108 +COLLECTION_START_AT=[PRIVATE_IP]T[PRIVATE_IP]:00 +FIRST_COMPLETE_D1_CLOSE=[PRIVATE_IP]T[PRIVATE_IP]:00 +PRODUCTION_LAUNCH_ALLOWED=False +EXECUTION_AUTHORITY=False +RISK_AUTHORITY=False +STAGE_A_HEALTH=AWAITING_PRIMARY_FINALITY +FORENSIC_PREVIOUS_EPOCH_PRESERVED=YES -def _simple_shell_assignments(text): -US_REMOTE_SCRIPT_SOURCE_END=1 -VPS_SSH_SOURCE_BEGIN=1 -def operator_key_fingerprint(): - if not OPERATOR_KEY.is_file() or OPERATOR_KEY.is_symlink(): raise BackupError('OPERATOR_KEY_MISSING') - p=run(['ssh-keygen','-lf',str(OPERATOR_KEY),'-E','sha256'],timeout=30) - s=p.stdout.decode('utf-8','replace') - m=re.search(r'(SHA256:[A-Za-z0-9+/]+)',s) - if not m or m.group(1)!=OPERATOR_KEY_FINGERPRINT: raise BackupError('OPERATOR_KEY_FINGERPRINT_MISMATCH') - return m.group(1) +## NEWFI_TASK6_AUTH_CHECKPOINT_V[PRIVATE_IP] +- Scope: historical accepted AUTH test, not a current SMTP connection test. +- Newfi approved SMTP account/sender: aleisaev@yandex.ru. +- Endpoint used by accepted test: smtp.yandex.ru:465 with certificate verification; single PLAIN initial response accepted with code 235. +- Evidence: incident ledger ### NEWFI_TASK6_YANDEX_AUTH_V2_OBSERVATION and ### NEWFI_TASK6_AUTH_PROOF_CLOSE_V1. +- No password file written, no application configuration changed, no mail sent by the accepted AUTH test. +- Persistent transport installation and application delivery are not proven by this checkpoint. Task6 is not complete. +- AUTH challenge and missing-file incidents closed; launch/session incident remains OPEN with original cause unproven. +- This update does not change VM211, VM160, routing, board state or Git. +- Other incidents and infrastructure health were not assessed. -def scan_hostkey_line(host,port,expected): - p=run([SSH_KEYSCAN,'-T','8','-p',str(port),'-t','ed25519',host],timeout=15) - lines=[x.strip() for x in p.stdout.decode().splitlines() if x.strip() and not x.startswith('#')] - good=[] - for line in lines: - f=line.split() - if len(f)<3 or f[1]!='ssh-ed25519': continue - try: blob=base64.b64decode(f[2]) - except Exception: continue - fp='SHA256:'+base64.b64encode(hashlib.sha256(blob).digest()).decode().rstrip('=') - if fp==expected: good.append(line) - if len(good)!=1: raise BackupError('HOSTKEY_PIN_MISMATCH') - return good[0] -def ensure_vps_known_hosts(targets): - lines=[] - for t in targets: - if t['type'] not in ('vps_md','vps_spb','vps_us'): continue - lines.append(scan_hostkey_line(t['host'],t['port'],t['hostkey_fingerprint'])) - atomic_write(VPS_KNOWN_HOSTS,('\n'.join(lines)+'\n').encode(),0o600) +## NEWFI_PRIVATE_STRUCTURE92_WRONG_MARKER_SCOPE_[PRIVATE_IP] CLOSURE +- Status: CLOSED +- RCA: NEWFI92 inspected the pve01 NEWFI90 attempt marker, which had not been finalized because the outer shell exited immediately after the guest returned RC3 following its successful rollback. The guest marker contained the true final rollback state. +- Correction: NEWFI93 required both the guest FINISHED/ROLLED_BACK record and a fresh exact demo-state readback before reconciling the outer NEWFI90 marker. NEWFI92 itself never reserved an attempt or mutated state. -def vps_ssh_argv(t, *, use_agent=False): - a=[SSH,'-p',str(t['port']),'-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','UserKnownHostsFile='+str(VPS_KNOWN_HOSTS),'-o','ConnectTimeout=15'] - if use_agent: - a += ['-o','IdentitiesOnly=no'] - else: - a += ['-i',str(OPERATOR_KEY),'-o','IdentitiesOnly=yes','-o','IdentityAgent=none'] - a += [t['user']+'@'+t['host']] - return a -def vps_run(t, remote_argv, *, input=None, timeout=300, use_agent=False, check=True): - remote=shlex.join([str(x) for x in remote_argv]) - return run(vps_ssh_argv(t,use_agent=use_agent)+[remote],input=input,timeout=timeout,check=check) +## NEWFI_PRIVATE_NEWFI95_NESTED_TRIPLE_QUOTE_PARSE_[PRIVATE_IP] +- Status: OPEN +- Command: NEWFI95 +- Symptom: after the content-structure precheck passed, the pve03 Python wrapper failed to parse at the PHP line beginning with $root. No Portal discovery or application mutation was reached. +- RCA: an outer raw triple-single-quoted guest Python payload contained an inner raw triple-single-quoted PHP payload. The inner delimiter terminated the outer Python string, causing PHP source to be parsed as Python. +- Safety: NEWFI95 was read-only, created no attempt marker, and did not reach the intended nested guest execution. Do not replay NEWFI95. -def bootstrap_vps_keys(targets): - operator_key_fingerprint() - ensure_vps_known_hosts(targets) - pub=run(['ssh-keygen','-y','-f',str(OPERATOR_KEY)],timeout=30).stdout.strip()+b'\n' - results={} - for t in targets: - if t['type'] not in ('vps_md','vps_spb'): continue - probe=vps_run(t,['true'],timeout=30,use_agent=False,check=False) - if probe.returncode==0: - results[t['logical_id']]='ALREADY_OPERATOR_KEY'; continue - if not os.environ.get('SSH_AUTH_SOCK'): raise BackupError('FORWARDED_AGENT_REQUIRED_FOR_BOOTSTRAP') - 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" - p=vps_run(t,['sh','-c',script.decode()],input=pub,timeout=45,use_agent=True) - tag=p.stdout.decode().strip() - if tag not in ('ADDED','ALREADY'): raise BackupError('VPS_AUTHORIZED_KEY_BOOTSTRAP_RESULT') - vps_run(t,['true'],timeout=30,use_agent=False) - results[t['logical_id']]=tag - # US was already operator-key based; prove it agentless too. - us=[x for x in targets if x['type']=='vps_us'][0] - vps_run(us,['true'],timeout=30,use_agent=False) - results[us['logical_id']]='ALREADY_US_OPERATOR_KEY' - return results - -def remote_hashset(t,command): - p=vps_run(t,['sh','-c',command],timeout=120,use_agent=False) - return sha256_bytes(p.stdout) -VPS_SSH_SOURCE_END=1 -US_NETBIRD_PID_JOURNAL_BEGIN=1 -PID_BEGIN=936114 -2026-09-21T20:30:36+03:00 pve01 homelab-backup-v2[936114]: SELFTEST_REPLACEMENT486=PASS -2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_TARGET=us-netbird -2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_RESULT=FAIL -2026-09-21T20:30:51+03:00 pve01 homelab-backup-v2[936114]: SCHEDULE_REASON=PIPE_FAILED -PID_END=936114 -PID_BEGIN=2121414 -2026-09-22T02:36:58+03:00 pve01 homelab-backup-v2[2121414]: SELFTEST_REPLACEMENT486=PASS -2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_TARGET=us-netbird -2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_RESULT=FAIL -2026-09-22T02:37:13+03:00 pve01 homelab-backup-v2[2121414]: SCHEDULE_REASON=PIPE_FAILED -PID_END=2121414 -PID_BEGIN=3378768 -2026-09-22T08:53:16+03:00 pve01 homelab-backup-v2[3378768]: SELFTEST_REPLACEMENT486=PASS -2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_TARGET=us-netbird -2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_RESULT=FAIL -2026-09-22T08:53:31+03:00 pve01 homelab-backup-v2[3378768]: SCHEDULE_REASON=PIPE_FAILED -PID_END=3378768 -US_NETBIRD_PID_JOURNAL_END=1 -US_NETBIRD_WORK_ARTIFACTS_BEGIN=1 -f|1790056411.7319950600|792|/var/lib/homelab-backup-v2/state/us-netbird.json -f|1789642259.3981707900|1255|/var/lib/homelab-backup-v2/cold-bootstrap/us-netbird.json -d|1790056411.7288067540|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260922T055316Z-d5c92acdd2e8 -d|1790033833.7009700260|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T233658Z-709cf01e1256 -d|1790011851.2302881580|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T173036Z-1128898e4cc8 -d|1789989471.8069593230|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T111736Z-c5a5c5e71776 -d|1789955807.6619889330|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260921T015632Z-dc499030a55f -d|1789932571.7940614350|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T192916Z-ca2592a81a30 -d|1789908991.7828657500|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T125616Z-8caeb0b6c7b7 -d|1789886227.6266376830|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T063652Z-e6c72515a153 -d|1789862827.7065704150|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260920T000652Z-7ecdcfcafc12 -d|1789839091.8314245860|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T173116Z-cfc70719f4e9 -d|1789822687.5806853640|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T125752Z-a4efa5c07171 -d|1789814653.6399387990|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T104358Z-b2232f971dbc -d|1789810393.6722341230|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T093258Z-64f5c2972565 -d|1789807993.6075344840|4096|/mnt/staging/homelab-backup-v2/v2-us-netbird-20260919T085258Z-36f858f91de5 -US_NETBIRD_WORK_ARTIFACTS_END=1 -US_NETBIRD_READONLY_PROBES_BEGIN=1 -US_NETBIRD_READONLY_PROBE_RC=41 -PROBE_TARGET_FOUND=true -PROBE_TYPE=vps_us -PROBE_SSH_TRUE_EXCEPTION=BackupError -PROBE_SSH_TRUE_CODE=COMMAND_FAILED -PROBE_SSH_TRUE_DETAIL=255 -US_NETBIRD_READONLY_PROBE_STDERR_SHA256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -US_NETBIRD_READONLY_PROBES_END=1 -US_NETBIRD_PIPE_BASELINE_CLASS=SSH_BASELINE_FAILURE -DECISION=PASS_BACKUP_1117_APP_CONTRACT_AND_PIPE_BASELINE_CLASSIFIED -NEXT_GATE=REPAIR_ONLY_BACKUP_US_NETBIRD_AND_AUDIT_CANONICAL_CLOUDB_SOURCE_OFFHOST -TASK_RESULT=PASS_HOMELAB_BACKUP_1116_CONTRACT_PIPE_RCA -CHANGES_MADE_BY_1117=false -PRODUCT_MUTATION_BY_1117=false -VM_MUTATION_BY_1117=false -CLOUD_MUTATION_BY_1117=false -HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260922-HOMELAB-BACKUP-1116-CONTRACT-PIPE-RCA-1117R1","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null} -WORKERS2_BACKUP_1116_CONTRACT_PIPE_RCA_END=1 +## NEWFI_PRIVATE_NEWFI95_NESTED_TRIPLE_QUOTE_PARSE_[PRIVATE_IP] CLOSURE +- Status: CLOSED +- RCA: an inner triple-single-quoted PHP literal terminated the outer triple-single-quoted Python guest payload in NEWFI95. The wrapper therefore failed parsing before the intended Portal discovery executed. +- Correction: NEWFI96 removed the nested Python payload layer entirely and passed one Python program directly to VM211 through qm guest exec stdin. The read-only Portal contract completed with QGA exit 0 and the implementation worktree remained unchanged. OUTPUT_END CHAT_OUTPUT_END