Skip to content

Commit

Permalink
Closes #497: Group by Virtual Chassis (#542)
Browse files Browse the repository at this point in the history
* add virtual chassis to js

* add virtual chassis to py and migrations
  • Loading branch information
dreng authored Jul 29, 2024
1 parent 1048fef commit 6f43b95
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 27 deletions.
2 changes: 1 addition & 1 deletion netbox_topology_views/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ class Meta:
class IndividualOptionsSerializer(NetBoxModelSerializer):
class Meta:
model = IndividualOptions
fields = ("ignore_cable_type", "save_coords", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_neighbors", "show_circuit", "show_power", "show_wireless", "group_sites", "group_locations", "group_racks", "draw_default_layout", "straight_cables")
fields = ("ignore_cable_type", "save_coords", "show_unconnected", "show_cables", "show_logical_connections", "show_single_cable_logical_conns", "show_neighbors", "show_circuit", "show_power", "show_wireless", "group_sites", "group_locations", "group_racks", "group_virtualchassis", "draw_default_layout", "straight_cables")
4 changes: 3 additions & 1 deletion netbox_topology_views/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def list(self, request):

if request.GET:

filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group, show_neighbors, straight_cables = get_query_settings(request)
filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group_virtualchassis, group, show_neighbors, straight_cables = get_query_settings(request)

# Read options from saved filters as NetBox does not handle custom plugin filters
if "filter_id" in request.GET and request.GET["filter_id"] != '':
Expand All @@ -127,6 +127,7 @@ def list(self, request):
if group_sites == False and 'group_sites' in saved_filter_params: group_sites = saved_filter_params['group_sites']
if group_locations == False and 'group_locations' in saved_filter_params: group_locations = saved_filter_params['group_locations']
if group_racks == False and 'group_racks' in saved_filter_params: group_racks = saved_filter_params['group_racks']
if group_virtualchassis == False and 'group_virtualchassis' in saved_filter_params: group_virtualchassis = saved_filter_params['group_virtualchassis']
if show_neighbors == False and 'show_neighbors' in saved_filter_params: show_neighbors = saved_filter_params['show_neighbors']
if straight_cables == False and 'straight_cables' in saved_filter_params: show_neighbors = saved_filter_params['straight_cables']
except SavedFilter.DoesNotExist: # filter_id not found
Expand Down Expand Up @@ -156,6 +157,7 @@ def list(self, request):
group_sites=group_sites,
group_locations=group_locations,
group_racks=group_racks,
group_virtualchassis=group_virtualchassis,
group_id=group_id,
straight_cables=straight_cables,
)
Expand Down
18 changes: 16 additions & 2 deletions netbox_topology_views/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DeviceFilterForm(
FieldSet(
'group', 'save_coords', 'show_unconnected', 'show_cables', 'show_logical_connections',
'show_single_cable_logical_conns', 'show_neighbors', 'show_circuit', 'show_power', 'show_wireless',
'group_sites', 'group_locations', 'group_racks', 'straight_cables', name=_("Options")
'group_sites', 'group_locations', 'group_racks', 'group_virtualchassis', 'straight_cables', name=_("Options")
),
FieldSet('id', name=_("Device")),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_("Location")),
Expand Down Expand Up @@ -310,6 +310,12 @@ class DeviceFilterForm(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
group_virtualchassis = forms.NullBooleanField(
label =_('Group Virtual Chassis'), required=False, initial=False,
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
straight_cables = forms.BooleanField(
label=_('Straight Cables'), required=False, initial=False,
widget=forms.Select(
Expand Down Expand Up @@ -507,6 +513,7 @@ class IndividualOptionsForm(NetBoxModelForm):
'group_sites',
'group_locations',
'group_racks',
'group_virtualchassis',
'draw_default_layout',
'straight_cables',
),
Expand Down Expand Up @@ -629,6 +636,13 @@ class IndividualOptionsForm(NetBoxModelForm):
help_text=_('Draws a rectangle around Devices that belong to the '
'same rack.')
)
group_virtualchassis = forms.BooleanField(
label =_('Group Virtual Chassis'),
required=False,
initial=False,
help_text=_('Draws a rectangle around Devices that belong to the '
'same virtual chassis.')
)
draw_default_layout = forms.BooleanField(
label = ('Draw Default Layout'),
required=False,
Expand All @@ -650,6 +664,6 @@ class Meta:
'user_id', 'ignore_cable_type', 'preselected_device_roles', 'preselected_tags',
'save_coords', 'show_unconnected', 'show_cables', 'show_logical_connections',
'show_single_cable_logical_conns', 'show_neighbors', 'show_circuit', 'show_power',
'show_wireless', 'group_sites', 'group_locations', 'group_racks', 'draw_default_layout',
'show_wireless', 'group_sites', 'group_locations', 'group_racks', 'group_virtualchassis', 'draw_default_layout',
'straight_cables'
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.6 on 2024-07-29 08:54

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_topology_views', '0008_straight_cables'),
]

operations = [
migrations.AddField(
model_name='individualoptions',
name='group_virtualchassis',
field=models.BooleanField(default=False),
),
]
3 changes: 3 additions & 0 deletions netbox_topology_views/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@ class IndividualOptions(NetBoxModel):
group_racks = models.BooleanField(
default=False
)
group_virtualchassis = models.BooleanField(
default=False
)
draw_default_layout = models.BooleanField(
default=False
)
Expand Down
22 changes: 11 additions & 11 deletions netbox_topology_views/static/netbox_topology_views/js/app.js

Large diffs are not rendered by default.

43 changes: 33 additions & 10 deletions netbox_topology_views/static_dev/js/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
const group_sites = topologyData.options.group_sites
const group_locations = topologyData.options.group_locations
const group_racks = topologyData.options.group_racks
const group_virtualchassis = topologyData.options.group_virtualchassis

graph = new Network(container, { nodes, edges }, options)
graph.fit()
Expand Down Expand Up @@ -143,16 +144,17 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
if(group_sites != null && group_sites == 'on') { drawGroupRectangles(canvascontext, groupedNodeSites, siteRectParams); }
if(group_locations != null && group_locations == 'on') { drawGroupRectangles(canvascontext, groupedNodeLocations, locationRectParams); }
if(group_racks != null && group_racks == 'on') { drawGroupRectangles(canvascontext, groupedNodeRacks, rackRectParams); }
if(group_virtualchassis != null && group_virtualchassis == 'on') { drawGroupRectangles(canvascontext, groupedNodeVirtualchassis, virtualchassisRectParams); }
})

graph.on('click', (canvascontext) => {
allRectangles.forEach(key => {
// Is the mouse pointer inside of the current rectangle?
if(canvascontext.pointer.canvas.x > (key.x1 - key.border / 2 - 1) && canvascontext.pointer.canvas.x < (key.x2 + key.border / 2 + 1)
&& canvascontext.pointer.canvas.y > (key.y1 - key.border / 2 - 1) && canvascontext.pointer.canvas.y < (key.y2 + key.border / 2 + 1)) {
if(canvascontext.pointer.canvas.x > (key.x1 - key.border / 2 - 3) && canvascontext.pointer.canvas.x < (key.x2 + key.border / 2 + 3)
&& canvascontext.pointer.canvas.y > (key.y1 - key.border / 2 - 3) && canvascontext.pointer.canvas.y < (key.y2 + key.border / 2 + 3)) {
// We just want to react when the border has been clicked, not the whole rectangle
if (canvascontext.pointer.canvas.x < (key.x1 + key.border / 2 + 1) || canvascontext.pointer.canvas.x > (key.x2 - key.border / 2 - 1)
|| canvascontext.pointer.canvas.y < (key.y1 + key.border / 2 + 1) || canvascontext.pointer.canvas.y > (key.y2 - key.border / 2 - 1)) {
if (canvascontext.pointer.canvas.x < (key.x1 + key.border / 2 + 3) || canvascontext.pointer.canvas.x > (key.x2 - key.border / 2 - 3)
|| canvascontext.pointer.canvas.y < (key.y1 + key.border / 2 + 3) || canvascontext.pointer.canvas.y > (key.y2 - key.border / 2 - 3)) {
// Generate an array of affected nodes in order to pass it to the select.Nodes() function
let arr = [];
if(key.category == "Site") {
Expand Down Expand Up @@ -182,13 +184,22 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
});
});
}
if(key.category == "Virtual Chassis") {
groupedNodeVirtualchassis.forEach(subArray => {
subArray.forEach(element => {
if (element[1] === key.id) {
arr.push(element[0]);
}
});
});
}
graph.selectNodes(arr);
}
}
});
})

// Add information on which node belongs to which group (site/location/rack).
// Add information on which node belongs to which group (site/location/rack/virtualchassis).
// Create an array for each group in order to loop through that arrays later
function combineNodeInfo(typeId, type) {
let nodesArray = [];
Expand Down Expand Up @@ -238,7 +249,7 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
allRectangles.push({category: rectangle.category, id: rectangle.id, x1: rectangle.x, y1: rectangle.y, x2: rectangle.x + rectangle.width, y2: rectangle.y + rectangle.height, border: rectangle.lineWidth})
}

/* Draw all rectangles of a given group (site/location/rack)
/* Draw all rectangles of a given group (site/location//virtualchassis)
rectParams expects an object that consists of the following keys:
lineWidth: border width (string)
color: border color (string)
Expand Down Expand Up @@ -303,8 +314,8 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
color: "#337ab7",
paddingX: 77,
paddingY: 77,
textPaddingX: 12,
textPaddingY: 22,
textPaddingX: 22,
textPaddingY: 29,
font: "14px helvetica",
category: "Location"
}
Expand All @@ -315,11 +326,23 @@ const coordSaveCheckbox = document.querySelector('#id_save_coords')
color: "green",
paddingX: 70,
paddingY: 70,
textPaddingX: 8,
textPaddingY: 30,
textPaddingX: 15,
textPaddingY: 36,
font: "14px helvetica",
category: "Rack"
}

let groupedNodeVirtualchassis = combineNodeInfo('virtual_chassis_id', 'virtual_chassis');
let virtualchassisRectParams = {
lineWidth: "5",
color: "orange",
paddingX: 63,
paddingY: 63,
textPaddingX: 8,
textPaddingY: 43,
font: "14px helvetica",
category: "Virtual Chassis"
}
})()

// Download Graph
Expand Down
7 changes: 6 additions & 1 deletion netbox_topology_views/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ def get_query_settings(request):
if request.GET["group_racks"] == "True" :
group_racks = True

group_virtualchassis = False
if "group_virtualchassis" in request.GET:
if request.GET["group_virtualchassis"] == "True" :
group_virtualchassis = True

group = False
if "group" in request.GET:
group = request.GET["group"]
Expand All @@ -187,7 +192,7 @@ def get_query_settings(request):
if request.GET["straight_cables"] == "True":
straight_cables = True

return filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group, show_neighbors, straight_cables
return filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group_virtualchassis, group, show_neighbors, straight_cables

class LinePattern():
wireless = [2, 10, 2, 10]
Expand Down
12 changes: 11 additions & 1 deletion netbox_topology_views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ def create_node(
if device.rack is not None:
node["rack"] = device.rack.name
node["rack_id"] = device.rack_id
if device.virtual_chassis is not None:
node["virtual_chassis"] = device.virtual_chassis.name
node["virtual_chassis_id"] = device.virtual_chassis_id

if device.role.color != "":
node["color.border"] = "#" + device.role.color
Expand Down Expand Up @@ -342,6 +345,7 @@ def get_topology_data(
group_sites: bool,
group_locations: bool,
group_racks: bool,
group_virtualchassis: bool,
group_id,
straight_cables: bool,
):
Expand Down Expand Up @@ -680,6 +684,8 @@ def get_topology_data(
options['group_racks'] = 'on'
if group_sites:
options['group_sites'] = 'on'
if group_virtualchassis:
options['group_virtualchassis'] = 'on'

for qs_device in queryset:
if qs_device.pk not in nodes_devices and show_unconnected:
Expand Down Expand Up @@ -719,7 +725,7 @@ def get(self, request):

if request.GET:

filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group, show_neighbors, straight_cables = get_query_settings(request)
filter_id, save_coords, show_unconnected, show_power, show_circuit, show_logical_connections, show_single_cable_logical_conns, show_cables, show_wireless, group_sites, group_locations, group_racks, group_virtualchassis, group, show_neighbors, straight_cables = get_query_settings(request)

# Read options from saved filters as NetBox does not handle custom plugin filters
if "filter_id" in request.GET and request.GET["filter_id"] != '':
Expand All @@ -737,6 +743,7 @@ def get(self, request):
if group_sites == False and 'group_sites' in saved_filter_params: group_sites = saved_filter_params['group_sites']
if group_locations == False and 'group_locations' in saved_filter_params: group_locations = saved_filter_params['group_locations']
if group_racks == False and 'group_racks' in saved_filter_params: group_racks = saved_filter_params['group_racks']
if group_virtualchassis == False and 'group_virtualchassis' in saved_filter_params: group_virtualchassis = saved_filter_params['group_virtualchassis']
if show_neighbors == False and 'show_neighbors' in saved_filter_params: show_neighbors = saved_filter_params['show_neighbors']
if straight_cables == False and 'straight_cables' in saved_filter_params: straight_cables = saved_filter_params['straight_cables']
except SavedFilter.DoesNotExist: # filter_id not found
Expand Down Expand Up @@ -768,6 +775,7 @@ def get(self, request):
group_sites=group_sites,
group_locations=group_locations,
group_racks=group_racks,
group_virtualchassis=group_virtualchassis,
group_id=group_id,
straight_cables=straight_cables,
)
Expand All @@ -793,6 +801,7 @@ def get(self, request):
if individualOptions.group_sites: q['group_sites'] = "True"
if individualOptions.group_locations: q['group_locations'] = "True"
if individualOptions.group_racks: q['group_racks'] = "True"
if individualOptions.group_virtualchassis: q['group_virtualchassis'] = "True"
if individualOptions.straight_cables: q['straight_cables'] = "True"
if individualOptions.draw_default_layout:
q['draw_init'] = "True"
Expand Down Expand Up @@ -1151,6 +1160,7 @@ def get(self, request):
'group_sites': queryset.group_sites,
'group_locations': queryset.group_locations,
'group_racks': queryset.group_racks,
'group_virtualchassis': queryset.group_virtualchassis,
'draw_default_layout': queryset.draw_default_layout,
'straight_cables': queryset.straight_cables,
},
Expand Down

0 comments on commit 6f43b95

Please sign in to comment.