aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/netbox/scripts/netbox2gondul/netbox2gondul.py65
-rw-r--r--tools/netbox/scripts/planning2netbox/planning2netbox.py12
2 files changed, 58 insertions, 19 deletions
diff --git a/tools/netbox/scripts/netbox2gondul/netbox2gondul.py b/tools/netbox/scripts/netbox2gondul/netbox2gondul.py
index 0613350..5fb4ad8 100644
--- a/tools/netbox/scripts/netbox2gondul/netbox2gondul.py
+++ b/tools/netbox/scripts/netbox2gondul/netbox2gondul.py
@@ -1,7 +1,7 @@
import os
from django.contrib.contenttypes.models import ContentType
-from django.db.models import F
+from django.db.models import F, Q
from django.utils.text import slugify
from dcim.choices import DeviceStatusChoices, InterfaceModeChoices, InterfaceTypeChoices, SiteStatusChoices
@@ -16,6 +16,9 @@ import re
import requests
from requests.models import HTTPBasicAuth
+FLOOR = Site.objects.get(slug="floor")
+RING = Site.objects.get(slug="ring")
+
class GondulConfigError(Exception):
def __init__(self, msg):
self.message = msg
@@ -101,19 +104,19 @@ class Netbox2Gondul(Script):
router = None
if prefix_v4:
- subnet4 = str(prefix_v4.prefix)
+ subnet4 = prefix_v4.prefix
gw4 = str(ipaddress.IPv4Network(prefix_v4.prefix)[1])
else:
self.log_warning(f'Network for VLAN <a href="{vlan.get_absolute_url()}">{vlan.name}</a> is missing IPv4 Prefix')
if prefix_v6:
- subnet6 = str(prefix_v6.prefix)
+ subnet6 = prefix_v6.prefix
gw6 = str(ipaddress.IPv6Network(prefix_v6.prefix)[1])
else:
self.log_warning(f'Network for VLAN <a href="{vlan.get_absolute_url()}">{vlan.name}</a> is missing IPv6 Prefix')
try:
- router = str(IPAddress.objects.get(address=gw4))
+ router = str(IPAddress.objects.get(address=f"{gw4}/{subnet4.prefixlen}"))
except IPAddress.DoesNotExist:
self.log_warning(f'Router not found for VLAN <a href="{vlan.get_absolute_url()}">{vlan.name}</a>')
router = "r1.tele"
@@ -125,12 +128,13 @@ class Netbox2Gondul(Script):
vlan_name = override
return {
"name": vlan_name,
- "subnet4": subnet4,
- "subnet6": subnet6,
+ "subnet4": str(subnet4),
+ "subnet6": str(subnet6),
"gw4": gw4,
"gw6": gw6,
"router": router,
"vlan": vlan.vid,
+ "tags": [tag.slug for tag in list(vlan.tags.all())],
}
def switches_to_gondul(self, switches):
@@ -151,7 +155,7 @@ class Netbox2Gondul(Script):
first_ae_interface: Interface = uplink_ae.member_interfaces.first()
cable: Cable = first_ae_interface.cable
# Assuming we only have one entry in the cable termination list.
- distro_interface: Interface = cable.a_terminations[0]
+ distro_interface: Interface = cable.a_terminations[0] if cable.a_terminations[0].device != device else cable.b_terminations[0]
distro = distro_interface.device
# This is the same way as we fetch mgmt vlan in the main run() function.
@@ -197,7 +201,11 @@ class Netbox2Gondul(Script):
input_devices: list[Type[Device]] = data['device']
if len(input_devices) == 0:
- input_devices = Device.objects.all()
+ input_devices = Device.objects.filter(
+ Q(site=FLOOR) | Q(site=RING)
+ ).filter(
+ status=DeviceStatusChoices.STATUS_ACTIVE,
+ )
networks = []
switches = []
@@ -205,28 +213,51 @@ class Netbox2Gondul(Script):
# sanity check
for device in input_devices:
if not device.primary_ip4 and not device.primary_ip6:
- self.log_failure(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv4 and IPv6 address.')
- return
+ self.log_warning(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv4 and IPv6 address, skipping...')
+ continue
vlan: VLAN = None
prefix_v4: Prefix = None
if device.primary_ip4:
- prefix_v4 = Prefix.objects.get(NetHostContained(F('prefix'), str(device.primary_ip4)))
- vlan = prefix_v4.vlan
+ try:
+ prefix_v4 = Prefix.objects.get(NetHostContained(F('prefix'), str(device.primary_ip4)))
+ vlan = prefix_v4.vlan
+ except Exception as e:
+ self.log_warning(f"Failed to configure {device} for import: {e}")
+ continue
else:
- self.log_warning(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv4 address.')
+ self.log_warning(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv4 address. Skipping.')
+ continue
prefix_v6: Prefix = None
if device.primary_ip6:
prefix_v6 = Prefix.objects.get(NetHostContained(F('prefix'), str(device.primary_ip6)))
vlan = prefix_v6.vlan
else:
- self.log_warning(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv6 address.')
+ self.log_warning(f'Device <a href="{device.get_absolute_url()}">{device.name}</a> is missing primary IPv6 address. Skipping.')
+ continue
- if prefix_v4 is not None and prefix_v6 is not None and prefix_v4.vlan != prefix_v6.vlan:
- self.log_failure(f'VLANs differ for the IPv4 and IPv6 addresses.')
- return
+ if not vlan:
+ self.log_warning(f"Skipping {device}: missing vlan")
+ continue
+ if prefix_v4 is not None and prefix_v6 is not None and prefix_v4.vlan != prefix_v6.vlan:
+ self.log_warning(f'VLANs differ for the IPv4 and IPv6 addresses, skipping...')
+ continue
+
+ if (uplink_aes := list(device.interfaces.filter(name="ae0"))):
+ if len(uplink_aes) == 0:
+ self.log_warning(f"Skipping {device}: Missing uplink AE")
+ continue
+
+ uplink_ae = uplink_aes[0]
+ first_uplink_interface = uplink_ae.member_interfaces.first()
+ if first_uplink_interface is None:
+ self.log_warning(f"Skipping {device}: Missing lag member for ae0")
+ continue
+ if not first_uplink_interface.cable:
+ self.log_warning(f"Skipping {device}: Missing netbox cable for uplink AE")
+ continue
networks.append(self.network_to_gondul_format(vlan, prefix_v4, prefix_v6))
switch, traffic_network = self.device_to_gondul_format(device)
diff --git a/tools/netbox/scripts/planning2netbox/planning2netbox.py b/tools/netbox/scripts/planning2netbox/planning2netbox.py
index 5fc53a7..0df6a8f 100644
--- a/tools/netbox/scripts/planning2netbox/planning2netbox.py
+++ b/tools/netbox/scripts/planning2netbox/planning2netbox.py
@@ -231,9 +231,13 @@ class Planning2Netbox(Script):
# Set mgmt ip
mgmt_addr_v4, _ = IPAddress.objects.get_or_create(
address=data['mgmt4'],
+ assigned_object_type=interface_type,
+ assigned_object_id=vlan_interface.id,
)
mgmt_addr_v6, _ = IPAddress.objects.get_or_create(
address=data['mgmt6'],
+ assigned_object_type=interface_type,
+ assigned_object_id=vlan_interface.id,
)
switch.primary_ip4 = mgmt_addr_v4
switch.primary_ip6 = mgmt_addr_v6
@@ -266,11 +270,15 @@ class Planning2Netbox(Script):
# and then some of the features of it doesn't work,
# e.g. prefix.get_first_available_ip().
+ subnet4 = IPNetwork(data['subnet4'])
+ uplink_addr_v4_raw = subnet4[1]
uplink_addr_v4, _ = IPAddress.objects.get_or_create(
- address=IPNetwork(data['subnet4'])[1],
+ address=f"{uplink_addr_v4_raw}/{subnet4.prefixlen}",
)
+ subnet6 = IPNetwork(data['subnet6'])
+ uplink_addr_v6_raw = subnet6[1]
uplink_addr_v6, _ = IPAddress.objects.get_or_create(
- address=IPNetwork(data['subnet6'])[1],
+ address=f"{uplink_addr_v6_raw}/{subnet6.prefixlen}",
)
core_subinterface.ip_addresses.add(uplink_addr_v4)
core_subinterface.ip_addresses.add(uplink_addr_v6)