Merge von claude/nervous-williams-acf000 (d5b3ce3) plus Ergebnis der
Vor-Ort-Session vom 2026-08-31.
Ergebnis
- je ein cloudflared 2026.6.1 auf ap1/ap2/ap3, bf-public healthy/12
(vorher 0 Connectoren), Flash je AP 54-55 MiB frei, WLAN zurueck.
Drei Runbook-Fehler aufgedeckt und korrigiert (§2.2, §3.3, §3.5, §8)
- Flash-Budget war Faktor 2,5 zu optimistisch: cloudflared entpackt
69,5 MiB (gemessen mit docker export), nicht 28 MB -- das offizielle
Image passt auf keinen der drei APs. Ersatz: eigenes FROM-scratch-Image
mit 35,3 MiB aus dem statisch gelinkten Binary, Binary-SHA e93824f6
gepinnt, Neubau byte-identisch. tools/build-cfd-image.py.
- docker save schreibt seit Docker 25 OCI statt docker-v1 -> RouterOS
meldet "no config found in manifest". tools/oci2docker.py als Konverter.
- /container/envs nimmt list=, nicht name= (auch MikroMCPs
manage_container_env ist dadurch fuer dieses Feld unbrauchbar).
Weitere Funde
- Der device-mode-Bestaetigungs-Boot installiert keine Pakete; erst
Paket-Reboot, dann device-mode.
- "A - AVAILABLE" in /system package print ist ein Download-Katalog,
kein Paket auf dem Geraet (Gegenprobe am Core: 2,9 MB frei, listet
10,1 MB wifi-qcom als verfuegbar).
- MikroMCPs export_config exportiert unvollstaendig (301 B statt 6,2 KiB).
Offen und entscheidungsbeduerftig
- Compliance 128/135: §3.4 verlangt Direkt-Writes fuer ip address/nat,
die unter GC-Kontrolle stehen -> sechs neue extra-Drifts, zwei je AP.
Inhaltlich richtig, gehoeren ins Soll -- kein Re-Baseline, kein Rueckbau.
- Zwei Nautobot-Tokens sind in dieser Session ins Transkript geraten
(unzureichende sed-Maskierung) -> Rotation noetig, TP30. Merkregel in
CLAUDE.md ergaenzt.
Merge-Konflikte aufgeloest
- Nummernkonflikt: beide Branches hatten ein TP37. main behaelt TP37
(Nautobot als Netzwerkdoku, User-Okay 08-30), OOB-Mgmt wird TP38.
Braucht noch Christophs Okay.
- Drei CF-Rollback-Snapshots hatten gleichen Namen bei verschiedenem
Inhalt -> aelterer Stand als *-vor-hostname-schnitt.json erhalten,
keiner verworfen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
2.6 KiB
Python
Executable File
60 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Baut ein minimales docker-v1-Image-Archiv (nur cloudflared + CA-Bundle),
|
|
wie RouterOS /container es einliest. Kein Docker noetig, damit das Format
|
|
nicht vom containerd-Store der Build-Maschine abhaengt."""
|
|
import hashlib, io, json, os, sys, tarfile, time
|
|
|
|
binp, cap, out = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
MTIME = 0 # feste mtime -> reproduzierbares Archiv
|
|
|
|
def add(tf, name, data, mode, typ=tarfile.REGTYPE):
|
|
ti = tarfile.TarInfo(name)
|
|
ti.mode, ti.mtime, ti.uid, ti.gid, ti.type = mode, MTIME, 0, 0, typ
|
|
ti.size = len(data) if typ == tarfile.REGTYPE else 0
|
|
tf.addfile(ti, io.BytesIO(data) if typ == tarfile.REGTYPE else None)
|
|
|
|
# --- Layer bauen ---
|
|
layer = io.BytesIO()
|
|
with tarfile.open(fileobj=layer, mode="w", format=tarfile.GNU_FORMAT) as tf:
|
|
for d in ("usr/", "usr/local/", "usr/local/bin/", "etc/", "etc/ssl/",
|
|
"etc/ssl/certs/", "tmp/"):
|
|
add(tf, d, b"", 0o755 if d != "tmp/" else 0o1777, tarfile.DIRTYPE)
|
|
add(tf, "usr/local/bin/cloudflared", open(binp, "rb").read(), 0o755)
|
|
add(tf, "etc/ssl/certs/ca-certificates.crt", open(cap, "rb").read(), 0o644)
|
|
layer_bytes = layer.getvalue()
|
|
diff_id = "sha256:" + hashlib.sha256(layer_bytes).hexdigest()
|
|
|
|
# --- Image-Config ---
|
|
cfg = {
|
|
"architecture": "arm64",
|
|
"os": "linux",
|
|
"config": {
|
|
"Env": ["PATH=/usr/local/bin:/usr/bin:/bin",
|
|
"SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"],
|
|
"Entrypoint": ["/usr/local/bin/cloudflared"],
|
|
"Cmd": ["version"],
|
|
"WorkingDir": "/",
|
|
},
|
|
"rootfs": {"type": "layers", "diff_ids": [diff_id]},
|
|
"history": [{"created": "1970-01-01T00:00:00Z",
|
|
"created_by": "bf-infra TP16.3: cloudflared + CA, FROM scratch"}],
|
|
}
|
|
cfg_raw = json.dumps(cfg, sort_keys=True, separators=(",", ":")).encode()
|
|
cfg_name = hashlib.sha256(cfg_raw).hexdigest() + ".json"
|
|
|
|
manifest = json.dumps([{"Config": cfg_name,
|
|
"RepoTags": ["cfd-min:2026.6.1"],
|
|
"Layers": ["layer/layer.tar"]}]).encode()
|
|
|
|
with tarfile.open(out, "w", format=tarfile.GNU_FORMAT) as tf:
|
|
add(tf, cfg_name, cfg_raw, 0o644)
|
|
add(tf, "layer/", b"", 0o755, tarfile.DIRTYPE)
|
|
add(tf, "layer/VERSION", b"1.0", 0o644)
|
|
add(tf, "layer/json", json.dumps({"id": "layer"}).encode(), 0o644)
|
|
add(tf, "layer/layer.tar", layer_bytes, 0o644)
|
|
add(tf, "manifest.json", manifest, 0o644)
|
|
|
|
print(f"Layer roh : {len(layer_bytes)} B ({len(layer_bytes)/1048576:.1f} MiB)")
|
|
print(f"Archiv : {os.path.getsize(out)} B ({os.path.getsize(out)/1048576:.1f} MiB)")
|
|
print(f"diff_id : {diff_id}")
|