fix(script): update populate script

This commit is contained in:
Damien
2026-02-04 18:23:04 +01:00
parent 0a2f658a2a
commit 4e598ae400
4 changed files with 117 additions and 40 deletions

View File

@@ -27,18 +27,18 @@ uv run python scripts/provision_fabric.py
### Custom Fields
| Object Type | Field | Description |
|-------------|-------|-------------|
| Device | `asn` | BGP ASN |
| Device | `mlag_domain_id` | MLAG domain identifier |
| Device | `mlag_peer_address` | MLAG peer IP |
| Device | `mlag_local_address` | MLAG local IP |
| Device | `mlag_virtual_mac` | Shared virtual MAC |
| Interface | `mlag_peer_link` | Marks peer-link interfaces |
| Interface | `mlag_id` | MLAG ID for host LAGs |
| VRF | `l3vni` | L3 VNI for EVPN |
| VRF | `vrf_vlan` | VLAN for L3 VNI SVI |
| IP Address | `virtual_ip` | Anycast/virtual IP flag |
| Object Type | Field | Description |
| ----------- | -------------------- | -------------------------- |
| Device | `asn` | BGP ASN |
| Device | `mlag_domain_id` | MLAG domain identifier |
| Device | `mlag_peer_address` | MLAG peer IP |
| Device | `mlag_local_address` | MLAG local IP |
| Device | `mlag_virtual_mac` | Shared virtual MAC |
| Interface | `mlag_peer_link` | Marks peer-link interfaces |
| Interface | `mlag_id` | MLAG ID for host LAGs |
| VRF | `l3vni` | L3 VNI for EVPN |
| VRF | `vrf_vlan` | VLAN for L3 VNI SVI |
| IP Address | `virtual_ip` | Anycast/virtual IP flag |
### Organization
@@ -49,14 +49,14 @@ uv run python scripts/provision_fabric.py
### Devices
| Device | Role | ASN | MLAG Domain |
|--------|------|-----|-------------|
| spine1, spine2 | Spine | 65000 | - |
| leaf1, leaf2 | Leaf | 65001 | MLAG1 |
| leaf3, leaf4 | Leaf | 65002 | MLAG2 |
| leaf5, leaf6 | Leaf | 65003 | MLAG3 |
| leaf7, leaf8 | Leaf | 65004 | MLAG4 |
| host1-4 | Server | - | - |
| Device | Role | ASN | MLAG Domain |
| -------------- | ------ | ----- | ----------- |
| spine1, spine2 | Spine | 65000 | - |
| leaf1, leaf2 | Leaf | 65001 | MLAG1 |
| leaf3, leaf4 | Leaf | 65002 | MLAG2 |
| leaf5, leaf6 | Leaf | 65003 | MLAG3 |
| leaf7, leaf8 | Leaf | 65004 | MLAG4 |
| host1-4 | Server | - | - |
### Cabling
@@ -66,14 +66,14 @@ uv run python scripts/provision_fabric.py
### IP Addressing
| Purpose | Prefix |
|---------|--------|
| Spine1-Leaf P2P | 10.0.1.0/24 |
| Spine2-Leaf P2P | 10.0.2.0/24 |
| MLAG iBGP P2P | 10.0.3.0/24 |
| MLAG Peer VLAN | 10.0.199.0/24 |
| Purpose | Prefix |
| --------------------- | ------------- |
| Spine1-Leaf P2P | 10.0.1.0/24 |
| Spine2-Leaf P2P | 10.0.2.0/24 |
| MLAG iBGP P2P | 10.0.3.0/24 |
| MLAG Peer VLAN | 10.0.199.0/24 |
| Loopback0 (Router-ID) | 10.0.250.0/24 |
| Loopback1 (VTEP) | 10.0.255.0/24 |
| Loopback1 (VTEP) | 10.0.255.0/24 |
## Idempotency

View File

@@ -521,6 +521,7 @@ def create_vlans(nb: pynetbox.api, site) -> dict:
nb.ipam.vlans,
{"vid": vlan["vid"], "group_id": vlan_group.id},
{
"vid": vlan["vid"],
"name": vlan["name"],
"description": vlan.get("description", ""),
"group": vlan_group.id, # Create expects 'group', filter expects 'group_id'
@@ -546,7 +547,7 @@ def create_vrfs(nb: pynetbox.api) -> dict:
rt_obj, created = get_or_create(
nb.ipam.route_targets,
{"name": rt},
{"description": f"Import RT for {vrf_def['name']}"},
{"name": rt, "description": f"Import RT for {vrf_def['name']}"},
)
import_rts.append(rt_obj.id)
log_result("RouteTarget", "RouteTarget", rt, created)
@@ -561,6 +562,7 @@ def create_vrfs(nb: pynetbox.api) -> dict:
nb.ipam.vrfs,
{"name": vrf_def["name"]},
{
"name": vrf_def["name"],
"rd": vrf_def.get("rd"),
"import_targets": import_rts,
"export_targets": export_rts,
@@ -587,7 +589,10 @@ def create_prefixes(nb: pynetbox.api, vrfs: dict):
if vrf_id:
vrf_id = vrf_id.id
create_params = {"prefix": prefix_def["prefix"], "description": prefix_def.get("description", "")}
create_params = {
"prefix": prefix_def["prefix"],
"description": prefix_def.get("description", ""),
}
if vrf_id:
create_params["vrf"] = vrf_id
@@ -610,6 +615,7 @@ def create_devices(nb: pynetbox.api, org: dict) -> dict:
nb.dcim.devices,
{"name": spine["name"]},
{
"name": spine["name"],
"device_type": org["device_type"].id,
"role": org["roles"]["spine"].id,
"site": org["site"].id,
@@ -635,6 +641,7 @@ def create_devices(nb: pynetbox.api, org: dict) -> dict:
nb.dcim.devices,
{"name": leaf["name"]},
{
"name": leaf["name"],
"device_type": org["device_type"].id,
"role": org["roles"]["leaf"].id,
"site": org["site"].id,
@@ -651,6 +658,7 @@ def create_devices(nb: pynetbox.api, org: dict) -> dict:
nb.dcim.devices,
{"name": host["name"]},
{
"name": host["name"],
"device_type": org["server_type"].id,
"role": org["roles"]["server"].id,
"site": org["site"].id,
@@ -717,11 +725,13 @@ def create_interfaces(nb: pynetbox.api, devices: dict) -> dict:
intf = existing
created = False
else:
intf = nb.dcim.interfaces.create({
"device": device.id,
"name": intf_name,
"type": intf_type,
})
intf = nb.dcim.interfaces.create(
{
"device": device.id,
"name": intf_name,
"type": intf_type,
}
)
created = True
# Set custom fields for MLAG peer-link
@@ -755,11 +765,19 @@ def create_ip_addresses(nb: pynetbox.api, devices: dict, interfaces: dict, vrfs:
},
{
"address": spine["loopback0"],
"role": "loopback",
"assigned_object_type": "dcim.interface",
"assigned_object_id": intf.id,
"description": f"{spine['name']} Router-ID",
},
)
if not created:
current_role = ip.role.value if hasattr(ip.role, "value") else ip.role
if current_role != "loopback":
ip.role = "loopback"
ip.save()
log_result("IP", "IP Address", f"{spine['loopback0']} (updated role)", True)
log_result("IP", "IP Address", spine["loopback0"], created)
# Loopback addresses for leafs
@@ -776,11 +794,19 @@ def create_ip_addresses(nb: pynetbox.api, devices: dict, interfaces: dict, vrfs:
},
{
"address": leaf["loopback0"],
"role": "loopback",
"assigned_object_type": "dcim.interface",
"assigned_object_id": intf.id,
"description": f"{leaf['name']} Router-ID",
},
)
if not created:
current_role = ip.role.value if hasattr(ip.role, "value") else ip.role
if current_role != "loopback":
ip.role = "loopback"
ip.save()
log_result("IP", "IP Address", f"{leaf['loopback0']} (updated role)", True)
log_result("IP", "IP Address", leaf["loopback0"], created)
# Loopback1 (VTEP)
@@ -793,11 +819,19 @@ def create_ip_addresses(nb: pynetbox.api, devices: dict, interfaces: dict, vrfs:
},
{
"address": leaf["loopback1"],
"role": "anycast",
"assigned_object_type": "dcim.interface",
"assigned_object_id": intf.id,
"description": f"{leaf['name']} VTEP",
},
)
if not created:
current_role = ip.role.value if hasattr(ip.role, "value") else ip.role
if current_role != "anycast":
ip.role = "anycast"
ip.save()
log_result("IP", "IP Address", f"{leaf['loopback1']} (updated role)", True)
log_result("IP", "IP Address", leaf["loopback1"], created)
# P2P addresses for Spine1-Leaf links
@@ -881,7 +915,9 @@ def create_cables(nb: pynetbox.api, interfaces: dict):
b_intf = interfaces.get(leaf, {}).get(leaf_intf)
if not a_intf or not b_intf:
print(f" [Skip] Cable: {spine}:{spine_intf} <-> {leaf}:{leaf_intf} (interface not found)")
print(
f" [Skip] Cable: {spine}:{spine_intf} <-> {leaf}:{leaf_intf} (interface not found)"
)
continue
# Check if cable already exists
@@ -943,8 +979,12 @@ def create_cables(nb: pynetbox.api, interfaces: dict):
try:
cable = nb.dcim.cables.create(
{
"a_terminations": [{"object_type": "dcim.interface", "object_id": a_intf.id}],
"b_terminations": [{"object_type": "dcim.interface", "object_id": host_eth1.id}],
"a_terminations": [
{"object_type": "dcim.interface", "object_id": a_intf.id}
],
"b_terminations": [
{"object_type": "dcim.interface", "object_id": host_eth1.id}
],
"status": "connected",
"type": "cat6a",
}
@@ -965,8 +1005,12 @@ def create_cables(nb: pynetbox.api, interfaces: dict):
try:
cable = nb.dcim.cables.create(
{
"a_terminations": [{"object_type": "dcim.interface", "object_id": b_intf.id}],
"b_terminations": [{"object_type": "dcim.interface", "object_id": host_eth2.id}],
"a_terminations": [
{"object_type": "dcim.interface", "object_id": b_intf.id}
],
"b_terminations": [
{"object_type": "dcim.interface", "object_id": host_eth2.id}
],
"status": "connected",
"type": "cat6a",
}