From edada1df3563a3cc62106485017f452f50d81d59 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Sat, 20 Apr 2024 21:25:38 +0100 Subject: [PATCH 1/9] Update helpers.py to use netbox long / lat fields. updated helper function get_device_location to use netbox's native location fields --- netbox_device_map/helpers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netbox_device_map/helpers.py b/netbox_device_map/helpers.py index 6215ead..fca6175 100644 --- a/netbox_device_map/helpers.py +++ b/netbox_device_map/helpers.py @@ -14,7 +14,10 @@ LatLon = tuple[float, float] def get_device_location(device: Device) -> LatLon | None: - """Extract device geolocation from special custom field""" + """If netbox longitude and latitude fields are populated for a device then use them.""" + if device.longitude and device.latitude: + return (device.longitude, device.latitude) + """... Otherwise extract device geolocation from special custom field""" if location_cf := device.custom_field_data.get(LOCATION_CF_NAME): return tuple(map(float, location_cf.replace(' ', '').split(',', maxsplit=1))) From 93f4691729487f99c87cefed3184a6de91226e0a Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Sat, 20 Apr 2024 21:38:07 +0100 Subject: [PATCH 2/9] Make sure Lat and Long are the right way around! --- netbox_device_map/helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox_device_map/helpers.py b/netbox_device_map/helpers.py index fca6175..a3869a7 100644 --- a/netbox_device_map/helpers.py +++ b/netbox_device_map/helpers.py @@ -15,8 +15,8 @@ LatLon = tuple[float, float] def get_device_location(device: Device) -> LatLon | None: """If netbox longitude and latitude fields are populated for a device then use them.""" - if device.longitude and device.latitude: - return (device.longitude, device.latitude) + if device.latitude and device.longitude: + return (device.latitude, device.longitude) """... Otherwise extract device geolocation from special custom field""" if location_cf := device.custom_field_data.get(LOCATION_CF_NAME): return tuple(map(float, location_cf.replace(' ', '').split(',', maxsplit=1))) From a10435e101105c38f3876b15e5aafcf8b2ad53e2 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Sat, 20 Apr 2024 21:45:56 +0100 Subject: [PATCH 3/9] Get the Lon/Lat fields correct in the comments too.. --- netbox_device_map/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_device_map/helpers.py b/netbox_device_map/helpers.py index a3869a7..b85db72 100644 --- a/netbox_device_map/helpers.py +++ b/netbox_device_map/helpers.py @@ -14,7 +14,7 @@ LatLon = tuple[float, float] def get_device_location(device: Device) -> LatLon | None: - """If netbox longitude and latitude fields are populated for a device then use them.""" + """If netbox latitude and longitude fields are populated for a device then use them.""" if device.latitude and device.longitude: return (device.latitude, device.longitude) """... Otherwise extract device geolocation from special custom field""" From 242fe8e32003dbd0133a3004253bf4f10f292492 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Fri, 3 May 2024 10:20:11 +0100 Subject: [PATCH 4/9] First pass at making VLAN optional --- netbox_device_map/forms.py | 1 + netbox_device_map/views.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox_device_map/forms.py b/netbox_device_map/forms.py index 980ea1a..2d5b9a5 100644 --- a/netbox_device_map/forms.py +++ b/netbox_device_map/forms.py @@ -15,6 +15,7 @@ class DeviceMapFilterForm(BootstrapMixin, forms.Form): ) vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), + required=False, label="VLAN", help_text="Filter devices by VLAN attached to any device interface", query_params={"group_id": "$vlan_group"} diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index 61c7b58..823bdd6 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -28,7 +28,7 @@ class MapView(PermissionRequiredMixin, View): interfaces = Interface.objects.all() vlan = form.cleaned_data['vlan'] - interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) + #interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) devices = Device.objects.filter(interfaces__in=interfaces).distinct() if device_roles := form.cleaned_data['device_roles']: devices = devices.filter(device_role__in=device_roles) From b422a926def7c58eb19fd6aecf73d656f8a0f161 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Fri, 3 May 2024 11:03:44 +0100 Subject: [PATCH 5/9] Remove VLAN --- netbox_device_map/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index 823bdd6..ad4567a 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -26,7 +26,7 @@ class MapView(PermissionRequiredMixin, View): form = self.form(request.GET) if form.is_valid(): interfaces = Interface.objects.all() - vlan = form.cleaned_data['vlan'] + #vlan = form.cleaned_data['vlan'] #interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) devices = Device.objects.filter(interfaces__in=interfaces).distinct() @@ -37,7 +37,7 @@ class MapView(PermissionRequiredMixin, View): non_geolocated_devices = set(devices) - set(geolocated_devices.keys()) map_data = configure_leaflet_map("geomap", geolocated_devices, form.cleaned_data['calculate_connections']) - map_data['vlan'] = vlan.id + #map_data['vlan'] = vlan.id return render(request, self.template_name, context=dict( filter_form=form, map_data=map_data, non_geolocated_devices=non_geolocated_devices )) From 69fbd6aef92d2f89799746b5d1e9f40cd3745b56 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Fri, 3 May 2024 13:55:16 +0100 Subject: [PATCH 6/9] Remove filtering of devices --- netbox_device_map/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index ad4567a..6c2f5e9 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -61,8 +61,9 @@ class ConnectedCpeAjaxView(PermissionRequiredMixin, View): form = self.form(request.GET) if form.is_valid(): data = form.cleaned_data - connected_devices_qs = get_connected_devices(device, vlan=data['vlan'])\ - .filter(device_role__name=plugin_settings['cpe_device_role']).order_by() + connected_devices_qs = get_connected_devices(device, vlan=data['vlan']) + #\ + # .filter(device_role__name=plugin_settings['cpe_device_role']).order_by() connected_devices = [dict(id=d.id, name=d.name, url=d.get_absolute_url(), comments=d.comments) for d in connected_devices_qs] # Sorting list of CPE devices by the sequence of integers contained in the comments From 974870adeb6c60382249f2d408455e31cd214fa5 Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Fri, 3 May 2024 15:49:07 +0100 Subject: [PATCH 7/9] Attempt to fix the filter by role (no longer device_role) --- netbox_device_map/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index 6c2f5e9..f6d71a7 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -31,7 +31,7 @@ class MapView(PermissionRequiredMixin, View): #interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) devices = Device.objects.filter(interfaces__in=interfaces).distinct() if device_roles := form.cleaned_data['device_roles']: - devices = devices.filter(device_role__in=device_roles) + devices = devices.filter(role=device_roles) geolocated_devices = {d: coords for d in devices if (coords := get_device_location(d))} non_geolocated_devices = set(devices) - set(geolocated_devices.keys()) @@ -66,8 +66,7 @@ class ConnectedCpeAjaxView(PermissionRequiredMixin, View): # .filter(device_role__name=plugin_settings['cpe_device_role']).order_by() connected_devices = [dict(id=d.id, name=d.name, url=d.get_absolute_url(), comments=d.comments) for d in connected_devices_qs] - # Sorting list of CPE devices by the sequence of integers contained in the comments - connected_devices.sort(key=lambda d: tuple(int(n) for n in INTEGER_REGEXP.findall(d['comments']))) + return JsonResponse(dict(status=True, cpe_devices=connected_devices, device_type=f'{device.device_type.manufacturer.name} {device.device_type.model}')) else: From 598461654da0506b9b30146d14f32845fe62290a Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Fri, 3 May 2024 19:22:27 +0100 Subject: [PATCH 8/9] role should be checked against a set of roles not just one --- netbox_device_map/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index f6d71a7..cfb807a 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -31,7 +31,8 @@ class MapView(PermissionRequiredMixin, View): #interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) devices = Device.objects.filter(interfaces__in=interfaces).distinct() if device_roles := form.cleaned_data['device_roles']: - devices = devices.filter(role=device_roles) + devices = devices.filter(role__in=device_roles) + print(f"Device roles are :{device_roles}") geolocated_devices = {d: coords for d in devices if (coords := get_device_location(d))} non_geolocated_devices = set(devices) - set(geolocated_devices.keys()) From c2d6b459c52b70bcba215780f6ca1ff5b4f5e5ba Mon Sep 17 00:00:00 2001 From: Seb Harrington Date: Tue, 6 Aug 2024 09:52:11 +0100 Subject: [PATCH 9/9] Just use all devices --- netbox_device_map/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox_device_map/views.py b/netbox_device_map/views.py index cfb807a..b3fe485 100644 --- a/netbox_device_map/views.py +++ b/netbox_device_map/views.py @@ -25,11 +25,11 @@ class MapView(PermissionRequiredMixin, View): """Device map view""" form = self.form(request.GET) if form.is_valid(): - interfaces = Interface.objects.all() + #interfaces = Interface.objects.all() #vlan = form.cleaned_data['vlan'] #interfaces = interfaces.filter(Q(untagged_vlan=vlan) | Q(tagged_vlans=vlan)) - devices = Device.objects.filter(interfaces__in=interfaces).distinct() + devices = Device.objects.all().distinct() if device_roles := form.cleaned_data['device_roles']: devices = devices.filter(role__in=device_roles) print(f"Device roles are :{device_roles}")