Closes #64: Show neighbors option (#286)

* Add option to show neighbors

* Updated documentation and help text

* Added newlines at end of files where they where missing

* Updated options screenshot

* fix function vars

---------
This commit is contained in:
Mario
2023-04-30 19:09:36 +02:00
committed by GitHub
parent 5e9aaecf9c
commit 5c58f2a9c2
8 changed files with 119 additions and 40 deletions
+5 -3
View File
@@ -99,15 +99,13 @@ Go to the plugins tab in the navbar and click topology or go to `$NETBOX_URL/plu
Select your options for the topology view: Select your options for the topology view:
![selection_options](https://user-images.githubusercontent.com/20901110/220410144-5633d24c-6383-4cba-8d6d-ba77ef3d3cdd.png) ![topology_options](https://user-images.githubusercontent.com/20901110/235302073-234c3ef7-2c2b-4d0c-a674-9909d490d7ea.png)
<dl> <dl>
<dt>Save Coordinates</dt> <dt>Save Coordinates</dt>
<dd>Save the coordinates of devices in the topology view.</dd> <dd>Save the coordinates of devices in the topology view.</dd>
<dt>Show Unconnected</dt> <dt>Show Unconnected</dt>
<dd>Show devices that have no connections or for which no connection is displayed. This option depends on other parameters like 'Show Cables' and 'Show Logical Connections'.</dd> <dd>Show devices that have no connections or for which no connection is displayed. This option depends on other parameters like 'Show Cables' and 'Show Logical Connections'.</dd>
<dt>Show Circuit Terminations</dt>
<dd>Show connections which end at a circuit termination in the topology view. These connections are displayed as blue dashed lines.</dd>
<dt>Show Cables</dt> <dt>Show Cables</dt>
<dd>Show connections between interfaces, front / rear ports, etc., that are connected with one or more cables. These connections are displayed as solid lines in the color of the cable.</dd> <dd>Show connections between interfaces, front / rear ports, etc., that are connected with one or more cables. These connections are displayed as solid lines in the color of the cable.</dd>
<dt>Show Logical Connections</dt> <dt>Show Logical Connections</dt>
@@ -116,6 +114,10 @@ Select your options for the topology view:
intermediate front / rear port connections, etc. This is similar to what was referred to as 'end-to-end' connections in previous versions. These connections are displayed as yellow dotted lines.</dd> intermediate front / rear port connections, etc. This is similar to what was referred to as 'end-to-end' connections in previous versions. These connections are displayed as yellow dotted lines.</dd>
<dt>Show redundant Cable and Locigal Connection</dt> <dt>Show redundant Cable and Locigal Connection</dt>
<dd>Shows a logical connection (in addition to a cable), even if a cable is directly connected. Leaving this option disabled prevents that redundant display. This option only has an effect if 'Show Logical Connections' is activated.</dd> <dd>Shows a logical connection (in addition to a cable), even if a cable is directly connected. Leaving this option disabled prevents that redundant display. This option only has an effect if 'Show Logical Connections' is activated.</dd>
<dt>Show Neighbors</dt>
<dd>Adds neighbors to the filter result set automatically. Link peers will be added if 'Show Cables' is ticked, far-end terminations will be added if 'Show Logical Connections' is ticked.</dd>
<dt>Show Circuit Terminations</dt>
<dd>Show connections which end at a circuit termination in the topology view. These connections are displayed as blue dashed lines.</dd>
<dt>Show Power Feeds</dt> <dt>Show Power Feeds</dt>
<dd>Displays connections between power outlets and power ports. These connections are displayed as solid lines in the color of the cable. This option depends on 'Show Cables'.</dd> <dd>Displays connections between power outlets and power ports. These connections are displayed as solid lines in the color of the cable. This option depends on 'Show Cables'.</dd>
<dt>Show Wireless Links</dt> <dt>Show Wireless Links</dt>
+2 -1
View File
@@ -25,4 +25,5 @@ class DeviceRoleSerializer(ModelSerializer):
class IndividualOptionsSerializer(NetBoxModelSerializer): class IndividualOptionsSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = IndividualOptions model = IndividualOptions
fields = ("ignore_cable_type", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_circuit", "show_power", "show_wireless", "draw_default_layout") fields = ("ignore_cable_type", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_neighbors", "show_circuit", "show_power", "show_wireless", "draw_default_layout")
+21 -15
View File
@@ -80,23 +80,29 @@ class ExportTopoToXML(PermissionRequiredMixin, ViewSet):
user_id=request.user.id, user_id=request.user.id,
) )
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless = get_query_settings(request) if request.GET:
topo_data = get_topology_data(
self.queryset,
individualOptions,
show_unconnected,
save_coords,
show_cables,
show_circuit,
show_logical_connections,
show_single_cable_logical_conns,
show_power,
show_wireless,
)
xml_data = export_data_to_xml(topo_data).decode('utf-8')
return HttpResponse(xml_data, content_type="application/xml; charset=utf-8") save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors = get_query_settings(request)
topo_data = get_topology_data(
queryset=self.queryset,
individualOptions=individualOptions,
save_coords=save_coords,
show_unconnected=show_unconnected,
show_cables=show_cables,
show_logical_connections=show_logical_connections,
show_single_cable_logical_conns=show_single_cable_logical_conns,
show_neighbors=show_neighbors,
show_circuit=show_circuit,
show_power=show_power,
show_wireless=show_wireless,
)
xml_data = export_data_to_xml(topo_data).decode('utf-8')
return HttpResponse(xml_data, content_type="application/xml; charset=utf-8")
else:
return JsonResponse(
{"status": "Missing or malformed request parameters"}, status=400
)
class SaveRoleImageViewSet(PermissionRequiredMixin, ViewSet): class SaveRoleImageViewSet(PermissionRequiredMixin, ViewSet):
queryset = DeviceRole.objects.none() queryset = DeviceRole.objects.none()
+23 -9
View File
@@ -33,9 +33,10 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
"save_coords", "save_coords",
"show_unconnected", "show_unconnected",
"show_cables", "show_cables",
"show_circuit",
"show_logical_connections", "show_logical_connections",
"show_single_cable_logical_conns", "show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power", "show_power",
"show_wireless", "show_wireless",
), ),
@@ -118,17 +119,17 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
show_unconnected = forms.BooleanField( show_unconnected = forms.BooleanField(
label=_("Show Unconnected"), required=False, initial=False label=_("Show Unconnected"), required=False, initial=False
) )
show_cables = forms.BooleanField(
label =_("Show Cables"), required=False, initial=False
)
show_logical_connections = forms.BooleanField( show_logical_connections = forms.BooleanField(
label =_("Show Logical Connections"), required=False, initial=False label =_("Show Logical Connections"), required=False, initial=False
) )
show_single_cable_logical_conns = forms.BooleanField( show_single_cable_logical_conns = forms.BooleanField(
label =_("Show redundant Cable and Locigal Connection"), required=False, initial=False label =_("Show redundant Cable and Locigal Connection"), required=False, initial=False
) )
show_cables = forms.BooleanField( show_neighbors = forms.BooleanField(
label =_("Show Cables"), required=False, initial=False label =_("Show Neighbors"), required=False, initial=False
)
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"), required=False, initial=False
) )
show_circuit = forms.BooleanField( show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"), required=False, initial=False label=_("Show Circuit Terminations"), required=False, initial=False
@@ -136,6 +137,9 @@ class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
show_power = forms.BooleanField( show_power = forms.BooleanField(
label=_("Show Power Feeds"), required=False, initial=False label=_("Show Power Feeds"), required=False, initial=False
) )
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"), required=False, initial=False
)
class IndividualOptionsForm(NetBoxModelForm): class IndividualOptionsForm(NetBoxModelForm):
fieldsets = ( fieldsets = (
@@ -148,9 +152,10 @@ class IndividualOptionsForm(NetBoxModelForm):
"preselected_tags", "preselected_tags",
"show_unconnected", "show_unconnected",
"show_cables", "show_cables",
"show_circuit",
"show_logical_connections", "show_logical_connections",
"show_single_cable_logical_conns", "show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power", "show_power",
"show_wireless", "show_wireless",
"draw_default_layout", "draw_default_layout",
@@ -215,6 +220,14 @@ class IndividualOptionsForm(NetBoxModelForm):
"disabled prevents that redundant display. This option only " "disabled prevents that redundant display. This option only "
"has an effect if 'Show Logical Connections' is activated.") "has an effect if 'Show Logical Connections' is activated.")
) )
show_neighbors = forms.BooleanField(
label =_("Show Neighbors"),
required=False,
initial=False,
help_text=_("Adds neighbors to the filter result set automatically. "
"Link peers will be added if 'Show Cables' is ticked, far-end "
"terminations will be added if 'Show Logical Connections' is ticked.")
)
show_circuit = forms.BooleanField( show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"), label=_("Show Circuit Terminations"),
required=False, required=False,
@@ -248,5 +261,6 @@ class IndividualOptionsForm(NetBoxModelForm):
class Meta: class Meta:
model = IndividualOptions model = IndividualOptions
fields = [ fields = [
'user_id', 'ignore_cable_type', 'preselected_device_roles', 'preselected_tags', 'show_unconnected', 'show_cables', 'show_logical_connections', 'show_single_cable_logical_conns', 'show_circuit', 'show_power', 'show_wireless', 'draw_default_layout' 'user_id', 'ignore_cable_type', 'preselected_device_roles', 'preselected_tags', 'show_unconnected', 'show_cables', 'show_logical_connections', 'show_single_cable_logical_conns', 'show_neighbors', 'show_circuit', 'show_power', 'show_wireless', 'draw_default_layout'
] ]
@@ -0,0 +1,18 @@
# Generated by Django 4.1.8 on 2023-04-29 09:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('netbox_topology_views', '0002_individualoptions'),
]
operations = [
migrations.AddField(
model_name='individualoptions',
name='show_neighbors',
field=models.BooleanField(default=False),
),
]
+3
View File
@@ -137,6 +137,9 @@ class IndividualOptions(NetBoxModel):
show_single_cable_logical_conns = models.BooleanField( show_single_cable_logical_conns = models.BooleanField(
default=False default=False
) )
show_neighbors = models.BooleanField(
default=False
)
show_circuit = models.BooleanField( show_circuit = models.BooleanField(
default=False default=False
) )
+6 -1
View File
@@ -154,8 +154,13 @@ def get_query_settings(request):
if "show_wireless" in request.GET: if "show_wireless" in request.GET:
if request.GET["show_wireless"] == "on" : if request.GET["show_wireless"] == "on" :
show_wireless = True show_wireless = True
show_neighbors = False
if "show_neighbors" in request.GET:
if request.GET["show_neighbors"] == "on" :
show_neighbors = True
return save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless return save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors
class LinePattern(): class LinePattern():
wireless = [2, 10, 2, 10] wireless = [2, 10, 2, 10]
+41 -11
View File
@@ -2,6 +2,7 @@ import json
from functools import reduce from functools import reduce
from typing import DefaultDict, Dict, Optional, Union from typing import DefaultDict, Dict, Optional, Union
import time import time
from itertools import chain
from utilities.htmx import is_htmx from utilities.htmx import is_htmx
from circuits.models import Circuit, CircuitTermination from circuits.models import Circuit, CircuitTermination
@@ -263,6 +264,7 @@ def get_topology_data(
show_circuit: bool, show_circuit: bool,
show_logical_connections: bool, show_logical_connections: bool,
show_single_cable_logical_conns: bool, show_single_cable_logical_conns: bool,
show_neighbors: bool,
show_power: bool, show_power: bool,
show_wireless: bool, show_wireless: bool,
): ):
@@ -290,6 +292,31 @@ def get_topology_data(
device_ids = [d.pk for d in queryset] device_ids = [d.pk for d in queryset]
site_ids = [d.site_id for d in queryset] site_ids = [d.site_id for d in queryset]
if show_neighbors:
interfaces = Interface.objects.filter(
Q(device_id__in=device_ids)
)
frontports = FrontPort.objects.filter(
Q(device_id__in=device_ids)
)
rearports = RearPort.objects.filter(
Q(device_id__in=device_ids)
)
ports = chain(interfaces, frontports, rearports)
for port in ports:
for link_peer in port.link_peers:
if link_peer.device.id not in device_ids:
device_ids.append(link_peer.device.id)
if show_logical_connections:
path_complete_interfaces = Interface.objects.filter(
Q(_path__is_complete=True) & Q(device_id__in=device_ids)
)
for path_complete_interface in path_complete_interfaces:
for connected_endpoint in path_complete_interface.connected_endpoints:
device_ids.append(connected_endpoint.device.id)
if show_circuit: if show_circuit:
circuit_terminations = CircuitTermination.objects.filter( circuit_terminations = CircuitTermination.objects.filter(
Q(site_id__in=site_ids) | Q(provider_network__isnull=False) Q(site_id__in=site_ids) | Q(provider_network__isnull=False)
@@ -600,20 +627,21 @@ class TopologyHomeView(PermissionRequiredMixin, View):
if request.GET: if request.GET:
save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless = get_query_settings(request) save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, show_neighbors = get_query_settings(request)
if not "draw_init" in request.GET or "draw_init" in request.GET and request.GET["draw_init"].lower() == "true": if not "draw_init" in request.GET or "draw_init" in request.GET and request.GET["draw_init"].lower() == "true":
topo_data = get_topology_data( topo_data = get_topology_data(
self.queryset, queryset=self.queryset,
individualOptions, individualOptions=individualOptions,
show_unconnected, save_coords=save_coords,
save_coords, show_unconnected=show_unconnected,
show_cables, show_cables=show_cables,
show_circuit, show_logical_connections=show_logical_connections,
show_logical_connections, show_single_cable_logical_conns=show_single_cable_logical_conns,
show_single_cable_logical_conns, show_neighbors=show_neighbors,
show_power, show_circuit=show_circuit,
show_wireless, show_power=show_power,
show_wireless=show_wireless,
) )
else: else:
@@ -629,6 +657,7 @@ class TopologyHomeView(PermissionRequiredMixin, View):
if individualOptions.show_cables: q['show_cables'] = "on" if individualOptions.show_cables: q['show_cables'] = "on"
if individualOptions.show_logical_connections: q['show_logical_connections'] = "on" if individualOptions.show_logical_connections: q['show_logical_connections'] = "on"
if individualOptions.show_single_cable_logical_conns: q['show_single_cable_logical_conns'] = "on" if individualOptions.show_single_cable_logical_conns: q['show_single_cable_logical_conns'] = "on"
if individualOptions.show_neighbors: q['show_neighbors'] = "on"
if individualOptions.show_circuit: q['show_circuit'] = "on" if individualOptions.show_circuit: q['show_circuit'] = "on"
if individualOptions.show_power: q['show_power'] = "on" if individualOptions.show_power: q['show_power'] = "on"
if individualOptions.show_wireless: q['show_wireless'] = "on" if individualOptions.show_wireless: q['show_wireless'] = "on"
@@ -751,6 +780,7 @@ class TopologyIndividualOptionsView(PermissionRequiredMixin, View):
'show_cables': queryset.show_cables, 'show_cables': queryset.show_cables,
'show_logical_connections': queryset.show_logical_connections, 'show_logical_connections': queryset.show_logical_connections,
'show_single_cable_logical_conns': queryset.show_single_cable_logical_conns, 'show_single_cable_logical_conns': queryset.show_single_cable_logical_conns,
'show_neighbors': queryset.show_neighbors,
'show_circuit': queryset.show_circuit, 'show_circuit': queryset.show_circuit,
'show_power': queryset.show_power, 'show_power': queryset.show_power,
'show_wireless': queryset.show_wireless, 'show_wireless': queryset.show_wireless,