netbox-migration

Modularer, dreistufiger NetBox-Import für die RZ-Erstmigration. Nimmt die
*_v4.json Consolidated-Payloads aus dem Gather (serverfacts_v4), sortiert sie
nach Typ und importiert sie in Abhängigkeitsreihenfolge nach NetBox.

Warum drei Ordner + drei Pässe?

Der erste Migrationslauf hat alles als Bare-Metal angelegt. Jetzt trennen wir
sauber auf — und weil is_virtual/pve_version nur aus einer dmidecode-Heuristik
kommen, sind Fehlklassifizierungen erwartbar. Die drei Ordner geben dir einen
Human-in-the-Loop-Checkpoint: zwischen den Pässen kannst du eine falsch
einsortierte JSON per Hand in den richtigen Ordner schieben.

Reihenfolge ist zwingend:

  1. Pass 1 — PVE legt Cluster + Hypervisor an. Muss zuerst laufen, denn …
  2. Pass 2 — VMs hängen die VMs an den in Pass 1 erzeugten Cluster (mit
    konditionalem Cleanup: ein fälschlich angelegtes physisches Device gleichen
    Namens wird entfernt — aber nur, wenn es real existiert).
  3. Pass 3 — Bare-Metal importiert den Rest (spiegelbildlicher Cleanup einer
    fälschlich angelegten VM).

Struktur

netbox-migration/
├── ansible.cfg
├── inventory.ini
├── group_vars/all.yml          # ← hier alles konfigurieren (URL, Token, Site, Flags)
├── site.yml                    # Orchestrator (alle 3 Pässe)
├── 01_import_pve.yml           # Pass 1
├── 02_import_vms.yml           # Pass 2
├── 03_import_bare_metal.yml    # Pass 3
├── query_inventory.yml         # Bestandsreport (Pre-/Post-Flight)
├── scripts/classify_nodes.py   # sortiert inventar/*_v4.json -> Unterordner
├── roles/netbox_import/
│   ├── defaults/main.yml
│   └── tasks/
│       ├── pve.yml             # 1 PVE-Node verarbeiten
│       ├── vm.yml              # 1 VM verarbeiten (+ Cleanup)
│       ├── bare_metal.yml      # 1 phys. Server verarbeiten (+ Cleanup)
│       ├── _scaffold_device.yml# Manufacturer/Type/Role (geteilt)
│       └── _interfaces.yml     # Interfaces/MAC/IP + primary_ip4 (Device & VM)
├── credentials/                # gitignored — netbox_api_token hier ablegen
│   └── netbox_api_token.sample
└── inventar/
    ├── *.sample_v4.json        # eingecheckte Demodaten
    ├── 1_pve_cluster/
    ├── 2_vms/
    └── 3_bare_metal/

Voraussetzungen

  • netbox.netbox Collection + pynetbox in der venv (nutzt ../.venv des
    Root-Repos — Pfad in group_vars/all.yml anpassen, falls anders).
  • NetBox 4.2+ (das MAC-Objektmodell in _interfaces.yml braucht ≥ 4.2).
  • API-Token nach credentials/netbox_api_token legen (ohne .sample).

Ablauf

cp credentials/netbox_api_token.sample credentials/netbox_api_token   # echten Token eintragen
# group_vars/all.yml prüfen: netbox_url, netbox_site, netbox_validate_certs

# 0) JSONs sortieren (Quelle: inventar/)
python3 scripts/classify_nodes.py            # --move zum Verschieben
#    -> danach die drei Ordner kurz durchsehen und ggf. von Hand korrigieren

# 1) Bestand VOR dem Import festhalten
ansible-playbook query_inventory.yml

# 2) Pass für Pass (beim ersten Mal einzeln, dazwischen prüfen)
ansible-playbook 01_import_pve.yml
ansible-playbook 02_import_vms.yml
ansible-playbook 03_import_bare_metal.yml
#    ... oder alles am Stück:  ansible-playbook site.yml

# 3) Verifizieren
ansible-playbook query_inventory.yml         # netbox_inventory_report.md

Overrides jederzeit per -e, z. B.:
ansible-playbook 01_import_pve.yml -e netbox_url=https://inv.test.net -e cleanup_wrong_type=false

Zur netbox_id

Ein separates Vorab-Abfragen der ID pro Host ist nicht nötig — die
netbox.netbox-Module lösen idempotent über den natürlichen Schlüssel auf
(name+site beim Device, name+cluster bei der VM) und geben das Objekt
inkl. .id zurück (siehe primary_ip4-Zuweisung in _interfaces.yml).
Explizite ID-Abfragen (via uri) nutzen wir nur für den konditionalen
Cleanup
und den Report — dort brauchen wir die Existenz/ID wirklich.

Bessere Cluster-Zuordnung (optional, empfohlen)

Der Clustername wird sonst aus dem FQDN geraten (pve01.testcluster1...
testcluster1). Verlässlicher ist die PVE-API als Autorität:
GET /api2/json/cluster/resources?type=vm liefert die echte VM↔Node-Zugehörigkeit.
Für einen festen Namen: -e netbox_cluster_name=testcluster1.