- 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>
4.2 KiB
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, groupingTP44 / 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 perextra_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__.pyruftregister_jobs(CFEstateSync); Repo-Wurzel-__init__.pymachtbf_infraals reguläres Paket sichtbar. - Token: Nautobot-Secret
cf-api-token(Providerenvironment-variable) →CF_API_TOKENamnautobot-worker, verdrahtet im Anchor-environmentvondocs/nas-vlan20/stacks/210-nautobot.yml(gitignored). Wert = der breiteCF_API_TOKENaus~/.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)
- Repo-Wurzel
__init__.pyist Pflicht. Nautobot 3.1.7 lädt Git-Repo-Jobs überimport_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 geklonteGIT_ROOT/bf_infra/unsichtbar →jobs/wird nie importiert. Symptom: Git-Sync SUCCESS, aber Log „No jobs were registered on loading thebf_infra.jobssubmodule" und kein Job-DB-Eintrag. bf-infra ist das erste Git-Repo mitextras.job— daher nie zuvor aufgetreten. Dermodule_path- Filter des Loaders importiert nurbf_infra+bf_infra.jobs.*;nautobot/,routeros/etc. bleiben unberührt. register_jobs()gehört ins Paket-__init__, nicht nur ins Submodul (Doku bestätigt).Meta.has_sensitive_variables = Falsenötig — DefaultTrue⇒ Nautobot verweigert das Scheduling („Job may have sensitive input variables"). Der Job nimmt nurdryrun(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, nichtid. Der Job lasid(=None) → per.get(mk)==Nonematchte er ein Fremdobjekt (App Launcher) und ließ den echtenterpene-dbauf stale laufen. Fix: VPC nutztservice_id;_upsertüberspringtmv=Nonegenerell. - Seed-Artefakt: der geseedete CloudService
terpene-dbhatteextra_config.service_id: null(der echte019fa3d5-…stand beim Seed nur in den Hyperdrive-Einträgen alsvpc_service_id). Einmalig reconciled (PATCHservice_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.