Skip to content

Commit 7eb23fe

Browse files
VLAN Filter Feature (#72)
Implement VLAN filter feature
1 parent a13efda commit 7eb23fe

File tree

2 files changed

+111
-3
lines changed

2 files changed

+111
-3
lines changed

nextbox_ui_plugin/forms.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from django import forms
2+
from ipam.models import VLAN
23
from utilities.forms import (
3-
BootstrapMixin, DynamicModelMultipleChoiceField,
4+
BootstrapMixin,
5+
DynamicModelMultipleChoiceField,
6+
DynamicModelChoiceField
47
)
58
from .models import SavedTopology
69
from dcim.models import Device, Site, Region
@@ -40,6 +43,12 @@ class TopologyFilterForm(BootstrapMixin, forms.Form):
4043
to_field_name='id',
4144
null_option='None',
4245
)
46+
vlan_id = DynamicModelChoiceField(
47+
queryset=VLAN.objects.all(),
48+
required=False,
49+
to_field_name='id',
50+
null_option='None',
51+
)
4352
region_id = DynamicModelMultipleChoiceField(
4453
queryset=Region.objects.all(),
4554
required=False,
@@ -50,6 +59,7 @@ class TopologyFilterForm(BootstrapMixin, forms.Form):
5059
device_id.label = _('Devices')
5160
location_id.label = _('Location')
5261
site_id.label = _('Sites')
62+
vlan_id.label = _('Vlan')
5363
region_id.label = _('Regions')
5464

5565

nextbox_ui_plugin/views.py

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.shortcuts import render
44
from django.views.generic import View
55
from dcim.models import Cable, Device, Interface, DeviceRole
6+
from ipam.models import VLAN
67
from .models import SavedTopology
78
from . import forms, filters
89
from django.contrib.auth.mixins import PermissionRequiredMixin
@@ -11,6 +12,7 @@
1112
import json
1213
import re
1314

15+
1416
NETBOX_CURRENT_VERSION = version.parse(settings.VERSION)
1517

1618
# Default NeXt UI icons
@@ -227,6 +229,91 @@ def filter_tags(tags):
227229
tags = filtered_tags
228230
return tags
229231

232+
def get_vlan_topology(nb_devices_qs, vlans):
233+
234+
topology_dict = {'nodes': [], 'links': []}
235+
device_roles = set()
236+
all_device_tags = set()
237+
multi_cable_connections = []
238+
vlan = VLAN.objects.get(id=vlans[0])
239+
interfaces = vlan.get_interfaces()
240+
filtred_devices = [d.id for d in nb_devices_qs]
241+
filtred_interfaces = []
242+
for interface in interfaces:
243+
if interface.is_connectable:
244+
direct_device_id = interface.device.id
245+
interface_trace = interface.trace()
246+
if len(interface_trace) != 0:
247+
termination_b_iface = interface_trace[-1][-1]
248+
connected_device_id = termination_b_iface.device.id
249+
if (direct_device_id in filtred_devices) or (direct_device_id in filtred_devices):
250+
filtred_interfaces.append(interface)
251+
252+
253+
254+
devices = []
255+
for interface in filtred_interfaces:
256+
if interface.is_connectable:
257+
if interface.device not in devices:
258+
devices.append(interface.device)
259+
interface_trace = interface.trace()
260+
if len(interface_trace) != 0:
261+
termination_b_iface = interface_trace[-1][-1]
262+
if termination_b_iface.device not in devices:
263+
devices.append(termination_b_iface.device)
264+
265+
266+
device_ids = [d.id for d in devices]
267+
for device in devices:
268+
device_is_passive = False
269+
device_url = device.get_absolute_url()
270+
primary_ip = ''
271+
if device.primary_ip:
272+
primary_ip = str(device.primary_ip.address)
273+
tags = [str(tag) for tag in device.tags.names()]
274+
for tag in tags:
275+
all_device_tags.add((tag, not tag_is_hidden(tag)))
276+
topology_dict['nodes'].append({
277+
'id': device.id,
278+
'name': device.name,
279+
'dcimDeviceLink': device_url,
280+
'primaryIP': primary_ip,
281+
'serial_number': device.serial,
282+
'model': device.device_type.model,
283+
'deviceRole': device.device_role.slug,
284+
'layerSortPreference': get_node_layer_sort_preference(
285+
device.device_role.slug
286+
),
287+
'icon': get_icon_type(
288+
device.id
289+
),
290+
'isPassive': device_is_passive,
291+
'tags': tags,
292+
})
293+
is_visible = not (device.device_role.slug in UNDISPLAYED_DEVICE_ROLE_SLUGS)
294+
device_roles.add((device.device_role.slug, device.device_role.name, is_visible))
295+
296+
mapped_links = []
297+
for interface in filtred_interfaces:
298+
if interface.is_connectable:
299+
interface_trace = interface.trace()
300+
if len(interface_trace) != 0:
301+
source_cable = interface_trace[0]
302+
dest_cable = interface_trace[-1]
303+
mapping_link = [source_cable[0].device.id,dest_cable[-1].device.id]
304+
if (mapping_link not in mapped_links) and (mapping_link.reverse() not in mapped_links):
305+
mapped_links.append(mapping_link)
306+
307+
topology_dict['links'].append({
308+
'id': source_cable[1].id,
309+
'source': source_cable[0].device.id,
310+
'target': dest_cable[-1].device.id,
311+
"srcIfName": if_shortname(source_cable[0].name),
312+
"tgtIfName": if_shortname(dest_cable[-1].name),
313+
})
314+
315+
return topology_dict, device_roles, multi_cable_connections, list(all_device_tags)
316+
230317

231318
def get_topology(nb_devices_qs):
232319
topology_dict = {'nodes': [], 'links': []}
@@ -398,8 +485,19 @@ def get(self, request):
398485
if saved_topology_id is not None:
399486
topology_dict, device_roles, device_tags, layout_context = get_saved_topology(saved_topology_id)
400487
else:
401-
self.queryset = self.filterset(request.GET, self.queryset).qs
402-
topology_dict, device_roles, multi_cable_connections, device_tags = get_topology(self.queryset)
488+
vlans = []
489+
if 'vlan_id' in request.GET:
490+
clean_request = request.GET.copy()
491+
clean_request.pop('vlan_id')
492+
vlans = request.GET.get('vlan_id')
493+
else:
494+
clean_request = request.GET.copy()
495+
496+
self.queryset = self.filterset(clean_request, self.queryset).qs
497+
if len(vlans) == 0:
498+
topology_dict, device_roles, multi_cable_connections, device_tags = get_topology(self.queryset)
499+
else:
500+
topology_dict, device_roles, multi_cable_connections, device_tags = get_vlan_topology(self.queryset, vlans)
403501

404502
return render(request, self.template_name, {
405503
'source_data': json.dumps(topology_dict),

0 commit comments

Comments
 (0)