Files
felhom.eu/documentation/audits/catalog-sweep-2026-10-24/tools/repoint.py
T
admin 67053335d1
gates / gates (push) Successful in 13m17s
Catalog sweep 2026-10-24: all 65 catalog apps on a fresh box (52 work, 10 with a problem, 0 broken); register 208 -> 217 (R-1269..R-1277 opened; notes on R-739, R-1267); STATUS + D46; map B1 re-checked; evidence
Every catalog app installed, used, backed up, removed keeping data, reinstalled, restored and removed with data on a
fresh box from the public ISO (demo-hp VM 9360, Tester4), endpoint-level. Worst: a reinstall's capture rewrites the
kept unit so its restore breaks the app (R-1269, P2), the restore still reports success (R-1270, P2), and „use my kept
data" loaded another box's future-dated database (R-1271, P2). Drill catalog fixes for the morning list (n8n usage
data; OpenGist 256M, proven by a cgroup probe). VM 9360 and LXC 9361 destroyed; hub host Tester4-aa9466 left for the
operator. REPORT-catalog-sweep-2026-10-24.md.
2026-10-25 00:13:05 +02:00

86 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""repoint.py drill|live|status — point the sweep box's controller at the drill catalog, or put the saved
controller.yaml back byte for byte.
The drill repo on Gitea is PRIVATE (R-992) and the box holds no catalog credential, so the drill is MIRRORED onto the
box: a bare git repository in the controller's own data volume, loaded from a git bundle, and
`git.repo_url: file:///opt/docker/felhom-controller/drill-catalog.git` — the method of
`audits/burndown-3-2026-10-17/tools/repoint.py`. The first version of this file set repo_url to the Gitea URL and
believed the repo public; the box's clone then failed („could not read Username", 21:18:11) and the controller ran on
the templates it already had — the first drill pass proved nothing (README, „Drill fixes").
`drill` ends with a POSITIVE check, not the absence of an error: the box's catalog cache must be at the drill's main
commit, and every `EXPECT` line must be in the box's copy of that template. Prints repo_url, never a token."""
import os, subprocess, sys, time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault("TARGET", "sweep")
import box_walk as w
DRILL = "/mnt/5_hdd/felhom.eu/drill/app-catalog-drill"
VOL = "/var/lib/docker/volumes/felhom-controller-data/_data" # guest path of the controller's data volume
CVOL = "/opt/docker/felhom-controller" # the same, inside the controller container
SAVE = f"{VOL}/controller.yaml.pre-sweep-drill"
MIRROR_URL = f"file://{CVOL}/drill-catalog.git"
EXPECT = [("n8n/docker-compose.yml", "N8N_DIAGNOSTICS_ENABLED=false"), ("opengist/docker-compose.yml", "256M")]
def status():
print(w.guest(f"""grep -n 'repo_url' {VOL}/controller.yaml; ls -l {SAVE} 2>&1 | tail -1
docker exec felhom-controller sh -c 'git -C {CVOL}/drill-catalog.git log -1 --format="mirror main %h" main 2>&1;
git -C {CVOL}/data/catalog-cache log -1 --format="cache HEAD %h" 2>&1; git -C {CVOL}/data/catalog-cache remote get-url origin'"""))
def mirror():
b = f"/tmp/drill-sweep1024-{os.getpid()}.bundle"
subprocess.run(["git", "-C", DRILL, "bundle", "create", b, "main"], check=True, capture_output=True)
subprocess.run(["scp", "-q", "-o", "StrictHostKeyChecking=accept-new", b, f"{w._T['ssh']}:{b}"], check=True)
subprocess.run(w.ssh_args() + [f"pct push {w.GUEST} {b} {VOL}/{os.path.basename(b)} && rm -f {b}"], check=True)
print(w.guest(f"""set -e
docker exec felhom-controller sh -c 'test -d {CVOL}/drill-catalog.git || git init -q --bare -b main {CVOL}/drill-catalog.git
git -C {CVOL}/drill-catalog.git fetch -q {CVOL}/{os.path.basename(b)} +main:main && rm -f {CVOL}/{os.path.basename(b)}
git -C {CVOL}/drill-catalog.git log -1 --format="mirror main %h" main'"""))
os.remove(b)
def restart_sync():
w.guest("docker restart felhom-controller >/dev/null")
for _ in range(60):
time.sleep(3)
try:
w.login()
break
except SystemExit:
continue
w.sync_rescan()
time.sleep(5)
print(w.guest("docker logs --since 3m felhom-controller 2>&1 | grep -E '\\[sync\\]' | grep -v DEBUG | tail -6 | cut -c1-200"))
def drill():
head = subprocess.run(["git", "-C", DRILL, "rev-parse", "--short=7", "main"], capture_output=True, text=True).stdout.strip()
mirror()
print(w.guest(f"""set -e
test -f {SAVE} || cp -p {VOL}/controller.yaml {SAVE}
sed -i -E 's#^(\\s+repo_url: ).*$#\\1{MIRROR_URL}#' {VOL}/controller.yaml
grep -n 'repo_url' {VOL}/controller.yaml"""))
restart_sync()
cache = w.guest(f"docker exec felhom-controller git -C {CVOL}/data/catalog-cache log -1 --format=%h").strip()
ok = cache.startswith(head)
for f, want in EXPECT:
got = w.guest(f"docker exec felhom-controller grep -c -- '{want}' {CVOL}/data/catalog-cache/templates/{f} || true").strip()
print(f" expect {f} ∋ {want}: {got}")
ok = ok and got not in ("", "0")
print(f"drill main {head}, box cache {cache}: " + ("DRILL-CONFIRMED" if ok else "DRILL-NOT-CONFIRMED"))
sys.exit(0 if ok else 1)
def live():
print(w.guest(f"""set -e
cp -p {SAVE} {VOL}/controller.yaml
cmp {SAVE} {VOL}/controller.yaml && echo RESTORED-IDENTICAL; grep -n 'repo_url' {VOL}/controller.yaml"""))
restart_sync()
status()
{"drill": drill, "live": live, "status": status}[sys.argv[1]]()