From f48f530ae206da0a114828c300350076f736e893 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 3 Oct 2024 13:56:26 -0400 Subject: [PATCH] Closes #17669: Enable filtering VLANs by assigned interface (#17674) * Closes #17669: Enable filtering VLANs by assigned interface * Add tests --- netbox/ipam/filtersets.py | 26 ++++++++++++++++++ netbox/ipam/tests/test_filtersets.py | 40 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index f98f510e57..894219c646 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -1035,6 +1035,16 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet): to_field_name='identifier', label=_('L2VPN'), ) + interface_id = django_filters.ModelChoiceFilter( + queryset=Interface.objects.all(), + method='filter_interface_id', + label=_('Assigned interface') + ) + vminterface_id = django_filters.ModelChoiceFilter( + queryset=VMInterface.objects.all(), + method='filter_vminterface_id', + label=_('Assigned VM interface') + ) class Meta: model = VLAN @@ -1062,6 +1072,22 @@ def get_for_device(self, queryset, name, value): def get_for_virtualmachine(self, queryset, name, value): return queryset.get_for_virtualmachine(value) + def filter_interface_id(self, queryset, name, value): + if value is None: + return queryset.none() + return queryset.filter( + Q(interfaces_as_tagged=value) | + Q(interfaces_as_untagged=value) + ) + + def filter_vminterface_id(self, queryset, name, value): + if value is None: + return queryset.none() + return queryset.filter( + Q(vminterfaces_as_tagged=value) | + Q(vminterfaces_as_untagged=value) + ) + class ServiceTemplateFilterSet(NetBoxModelFilterSet): port = NumericArrayFilter( diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index e149c0a8d7..4e38b14503 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -1658,6 +1658,13 @@ def setUpTestData(cls): ) Device.objects.bulk_create(devices) + interfaces = ( + Interface(device=devices[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[1], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + Interface(device=devices[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED), + ) + Interface.objects.bulk_create(interfaces) + cluster_groups = ( ClusterGroup(name='Cluster Group 1', slug='cluster-group-1'), ClusterGroup(name='Cluster Group 2', slug='cluster-group-2'), @@ -1680,6 +1687,13 @@ def setUpTestData(cls): ) VirtualMachine.objects.bulk_create(virtual_machines) + vm_interfaces = ( + VMInterface(virtual_machine=virtual_machines[0], name='VM Interface 1'), + VMInterface(virtual_machine=virtual_machines[1], name='VM Interface 2'), + VMInterface(virtual_machine=virtual_machines[2], name='VM Interface 3'), + ) + VMInterface.objects.bulk_create(vm_interfaces) + groups = ( # Scoped VLAN groups VLANGroup(name='Region 1', slug='region-1', scope=regions[0]), @@ -1773,6 +1787,22 @@ def setUpTestData(cls): ) VLAN.objects.bulk_create(vlans) + # Assign VLANs to device interfaces + interfaces[0].untagged_vlan = vlans[0] + interfaces[0].tagged_vlans.add(vlans[1]) + interfaces[1].untagged_vlan = vlans[2] + interfaces[1].tagged_vlans.add(vlans[3]) + interfaces[2].untagged_vlan = vlans[4] + interfaces[2].tagged_vlans.add(vlans[5]) + + # Assign VLANs to VM interfaces + vm_interfaces[0].untagged_vlan = vlans[0] + vm_interfaces[0].tagged_vlans.add(vlans[1]) + vm_interfaces[1].untagged_vlan = vlans[2] + vm_interfaces[1].tagged_vlans.add(vlans[3]) + vm_interfaces[2].untagged_vlan = vlans[4] + vm_interfaces[2].tagged_vlans.add(vlans[5]) + def test_q(self): params = {'q': 'foobar1'} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) @@ -1857,6 +1887,16 @@ def test_available_at_site(self): params = {'available_at_site': site_id} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5) # 4 scoped + 1 global group + 1 global + def test_interface(self): + interface_id = Interface.objects.first().pk + params = {'interface_id': interface_id} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + + def test_vminterface(self): + vminterface_id = VMInterface.objects.first().pk + params = {'vminterface_id': vminterface_id} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + class ServiceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = ServiceTemplate.objects.all()