fix(script): update populate script
This commit is contained in:
@@ -34,5 +34,6 @@ ignore = ["E501"]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"basedpyright>=1.37.4",
|
||||
"ruff>=0.14.10",
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
34
uv.lock
generated
34
uv.lock
generated
@@ -2,6 +2,18 @@ version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "basedpyright"
|
||||
version = "1.37.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nodejs-wheel-binaries" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/15/8f335ed50b5fed4d7587e293c200bb498049f4a74d9913c58c26a42d3503/basedpyright-1.37.4.tar.gz", hash = "sha256:f818d8b56c1e7f639dfbdaf875aa6b0bd53eef08204389959027d3d7fb2017ed", size = 25238593, upload-time = "2026-02-04T02:57:15.893Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/b6/f075ecdc60a3e389c32934a98171b7f5c6f12250fc0030e12efc1102a557/basedpyright-1.37.4-py3-none-any.whl", hash = "sha256:bcf61d7d8dbd4570f346008fa591585bd605ce47a0561509899c276f2e53a450", size = 12299643, upload-time = "2026-02-04T02:57:19.915Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.1.4"
|
||||
@@ -224,6 +236,7 @@ dependencies = [
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "basedpyright" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
@@ -236,7 +249,10 @@ requires-dist = [
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "ruff", specifier = ">=0.14.10" }]
|
||||
dev = [
|
||||
{ name = "basedpyright", specifier = ">=1.37.4" },
|
||||
{ name = "ruff", specifier = ">=0.14.10" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "grpcio"
|
||||
@@ -309,6 +325,22 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodejs-wheel-binaries"
|
||||
version = "24.13.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/f1/73182280e2c05f49a7c2c8dbd46144efe3f74f03f798fb90da67b4a93bbf/nodejs_wheel_binaries-24.13.0.tar.gz", hash = "sha256:766aed076e900061b83d3e76ad48bfec32a035ef0d41bd09c55e832eb93ef7a4", size = 8056, upload-time = "2026-01-14T11:05:33.653Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/dc/4d7548aa74a5b446d093f03aff4fb236b570959d793f21c9c42ab6ad870a/nodejs_wheel_binaries-24.13.0-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:356654baa37bfd894e447e7e00268db403ea1d223863963459a0fbcaaa1d9d48", size = 55133268, upload-time = "2026-01-14T11:05:05.335Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/8a/8a4454d28339487240dd2232f42f1090e4a58544c581792d427f6239798c/nodejs_wheel_binaries-24.13.0-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:92fdef7376120e575f8b397789bafcb13bbd22a1b4d21b060d200b14910f22a5", size = 55314800, upload-time = "2026-01-14T11:05:09.121Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/fb/46c600fcc748bd13bc536a735f11532a003b14f5c4dfd6865f5911672175/nodejs_wheel_binaries-24.13.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:3f619ac140e039ecd25f2f71d6e83ad1414017a24608531851b7c31dc140cdfd", size = 59666320, upload-time = "2026-01-14T11:05:12.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/47/d48f11fc5d1541ace5d806c62a45738a1db9ce33e85a06fe4cd3d9ce83f6/nodejs_wheel_binaries-24.13.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:dfb31ebc2c129538192ddb5bedd3d63d6de5d271437cd39ea26bf3fe229ba430", size = 60162447, upload-time = "2026-01-14T11:05:16.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/74/d285c579ae8157c925b577dde429543963b845e69cd006549e062d1cf5b6/nodejs_wheel_binaries-24.13.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fdd720d7b378d5bb9b2710457bbc880d4c4d1270a94f13fbe257198ac707f358", size = 61659994, upload-time = "2026-01-14T11:05:19.68Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/97/88b4254a2ff93ed2eaed725f77b7d3d2d8d7973bf134359ce786db894faf/nodejs_wheel_binaries-24.13.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9ad6383613f3485a75b054647a09f1cd56d12380d7459184eebcf4a5d403f35c", size = 62244373, upload-time = "2026-01-14T11:05:23.987Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/c3/0e13a3da78f08cb58650971a6957ac7bfef84164b405176e53ab1e3584e2/nodejs_wheel_binaries-24.13.0-py2.py3-none-win_amd64.whl", hash = "sha256:605be4763e3ef427a3385a55da5a1bcf0a659aa2716eebbf23f332926d7e5f23", size = 41345528, upload-time = "2026-01-14T11:05:27.67Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/f1/0578d65b4e3dc572967fd702221ea1f42e1e60accfb6b0dd8d8f15410139/nodejs_wheel_binaries-24.13.0-py2.py3-none-win_arm64.whl", hash = "sha256:2e3431d869d6b2dbeef1d469ad0090babbdcc8baaa72c01dd3cc2c6121c96af5", size = 39054688, upload-time = "2026-01-14T11:05:30.739Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
|
||||
Reference in New Issue
Block a user