Files
bf-infra/docs/handoff-20260910-tp44-teilb-sync-live.md
Christoph Emsenhuber 2b856d3d42 TP44 Teil B durch: Prosa auf ✅ + Handoff (Sync live, täglicher Job)
- teilprojekte.md: TP44-Status ✅ DURCH; Teil-B-Ergebnis (Live-Sync als
  täglicher Nautobot-Job, 4/14, 0 Drift); Drift-Korrektur der falschen
  "CF_API_TOKEN kann kein VPC"-Gotcha (live: liest 14/14).
- handoff-20260910: Root-Cause (Wurzel-__init__.py für walk_packages),
  register_jobs im __init__, has_sensitive_variables, VPC service_id-Fix,
  terpene-db service_id-Reconcile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-10 11:15:13 +02:00

4.2 KiB
Raw Permalink Blame History

Handoff 2026-09-10 — TP44 Teil B: CF-Estate-Sync als Nautobot-Job LIVE

Ergebnis: Der Cloudflare-Estate→Nautobot-Sync läuft als täglicher Nautobot-Job (CFEstateSync, grouping TP44 / Cloudflare). Dry-Run + Commit-Run sauber: 4 CloudNetworks / 14 CloudServices, alle CF-Endpoints lesbar, 0 Drift. CF bleibt operativer Master, Nautobot ist read-only Dokumentations-SSoT. TP44 ist damit vollständig durch.

Governance (User, 2026-09-09)

Periodische externe→Nautobot-Syncs leben als Nautobot-Jobs in bf-infra/jobs/ und werden in Nautobot geplant — kein per-Task-Container, kein Cron. Künftige Syncs = weitere Jobs in jobs/.

Was live ist

  • Runtime: jobs/cf_estate_sync.py (CFEstateSync, ORM). Pull der CF-API (urllib+Bearer), Upsert per extra_config-Match (tunnel_id/script/id/service_id), Verwaisung = stale-Flag statt Löschen. 403-tolerant (fehlender Scope kippt den Sync nicht; Verwaisung wird dann übersprungen).
  • Registrierung: jobs/__init__.py ruft register_jobs(CFEstateSync); Repo-Wurzel-__init__.py macht bf_infra als reguläres Paket sichtbar.
  • Token: Nautobot-Secret cf-api-token (Provider environment-variable) → CF_API_TOKEN am nautobot-worker, verdrahtet im Anchor-environment von docs/nas-vlan20/stacks/210-nautobot.yml (gitignored). Wert = der breite CF_API_TOKEN aus ~/.secrets/credentials.env (liest 14/14).
  • Schedule: ScheduledJob "CF Estate Sync – taeglich", interval=daily, start_time=2026-09-11T03:00:00Z (= 05:00 Europe/Vienna, vor den Golden-Config-Läufen), enabled=True, dryrun=False.
  • GitRepository: bf-infra (provided_contents=['extras.job']) — war schon verdrahtet.

Drei load-bearing Funde (sonst lädt/plant der Job nicht)

  1. Repo-Wurzel __init__.py ist Pflicht. Nautobot 3.1.7 lädt Git-Repo-Jobs über import_modules_privately() → pkgutil.walk_packages([GIT_ROOT]). walk_packages entdeckt nur reguläre Pakete (mit __init__.py), keine Namespace-Packages. Ohne die Datei ist der geklonte GIT_ROOT/bf_infra/ unsichtbar → jobs/ wird nie importiert. Symptom: Git-Sync SUCCESS, aber Log „No jobs were registered on loading the bf_infra.jobs submodule" und kein Job-DB-Eintrag. bf-infra ist das erste Git-Repo mit extras.job — daher nie zuvor aufgetreten. Der module_path- Filter des Loaders importiert nur bf_infra + bf_infra.jobs.*; nautobot/, routeros/ etc. bleiben unberührt.
  2. register_jobs() gehört ins Paket-__init__, nicht nur ins Submodul (Doku bestätigt).
  3. Meta.has_sensitive_variables = False nötig — Default True ⇒ Nautobot verweigert das Scheduling („Job may have sensitive input variables"). Der Job nimmt nur dryrun (Boolean); das Token kommt aus dem Secret, nicht aus einer Job-Variable.

Zwei Daten-/Code-Funde beim Dry-Run

  • VPC-Bug: VPC-Directory-Services tragen ihren Identifier in service_id, nicht id. Der Job las id (=None) → per .get(mk)==None matchte er ein Fremdobjekt (App Launcher) und ließ den echten terpene-db auf stale laufen. Fix: VPC nutzt service_id; _upsert überspringt mv=None generell.
  • Seed-Artefakt: der geseedete CloudService terpene-db hatte extra_config.service_id: null (der echte 019fa3d5-… stand beim Seed nur in den Hyperdrive-Einträgen als vpc_service_id). Einmalig reconciled (PATCH service_id=019fa3d5-…) → seither matcht der Sync sauber, 0 Drift.

Drift-Korrektur (nicht stillschweigend)

Die frühere Notiz „Repo-CF_API_TOKEN darf kein Workers-VPC → über den cloudflare-MCP-Credential" (TP44-Prosa + handoff-20260902-…) war falsch. Live getestet liest der CF_API_TOKEN aus ~/.secrets/credentials.env Hyperdrive/VPC/Workers (alle 200). Der schmale Token ist CF_DNS_API_TOKEN (403). Der cloudflare-MCP ist der remote OAuth-MCP (kein API-Token) und für einen serverseitigen Job ohnehin nicht nutzbar.

Nächster CF-Sync = neuer Job im selben Muster

Modul in jobs/ anlegen, Klasse importieren + register_jobs(...) im jobs/__init__.py ergänzen, Meta.has_sensitive_variables=False setzen, Git-Sync, enablen, Dry-Run, dann Schedule. Die Wurzel- __init__.py gilt schon.