Skip to content

Commit 8dfec7e

Browse files
authored
Closes #14538 - Add available_at_site filter (#14541)
* Closes #14538 - Add available_at_site filter * Add tests * Fix tests
1 parent c1cf037 commit 8dfec7e

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

netbox/ipam/filtersets.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,10 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
950950
choices=VLANStatusChoices,
951951
null_value=None
952952
)
953+
available_at_site = django_filters.ModelChoiceFilter(
954+
queryset=Site.objects.all(),
955+
method='get_for_site'
956+
)
953957
available_on_device = django_filters.ModelChoiceFilter(
954958
queryset=Device.objects.all(),
955959
method='get_for_device'
@@ -984,6 +988,10 @@ def search(self, queryset, name, value):
984988
pass
985989
return queryset.filter(qs_filter)
986990

991+
@extend_schema_field(OpenApiTypes.STR)
992+
def get_for_site(self, queryset, name, value):
993+
return queryset.get_for_site(value)
994+
987995
@extend_schema_field(OpenApiTypes.STR)
988996
def get_for_device(self, queryset, name, value):
989997
return queryset.get_for_device(value)

netbox/ipam/querysets.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,35 @@ def annotate_utilization(self):
6969

7070
class VLANQuerySet(RestrictedQuerySet):
7171

72+
def get_for_site(self, site):
73+
"""
74+
Return all VLANs in the specified site
75+
"""
76+
from .models import VLANGroup
77+
q = Q()
78+
q |= Q(
79+
scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'),
80+
scope_id=site.pk
81+
)
82+
83+
if site.region:
84+
q |= Q(
85+
scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'),
86+
scope_id__in=site.region.get_ancestors(include_self=True)
87+
)
88+
if site.group:
89+
q |= Q(
90+
scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'),
91+
scope_id__in=site.group.get_ancestors(include_self=True)
92+
)
93+
94+
return self.filter(
95+
Q(group__in=VLANGroup.objects.filter(q)) |
96+
Q(site=site) |
97+
Q(group__scope_id__isnull=True, site__isnull=True) | # Global group VLANs
98+
Q(group__isnull=True, site__isnull=True) # Global VLANs
99+
)
100+
72101
def get_for_device(self, device):
73102
"""
74103
Return all VLANs available to the specified Device.

netbox/ipam/tests/test_filtersets.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ def setUpTestData(cls):
13591359
VLANGroup(name='VLAN Group 1', slug='vlan-group-1'),
13601360
VLANGroup(name='VLAN Group 2', slug='vlan-group-2'),
13611361
VLANGroup(name='VLAN Group 3', slug='vlan-group-3'),
1362+
VLANGroup(name='VLAN Group 4', slug='vlan-group-4'),
13621363
)
13631364
VLANGroup.objects.bulk_create(groups)
13641365

@@ -1415,6 +1416,9 @@ def setUpTestData(cls):
14151416
VLAN(vid=301, name='VLAN 301', site=sites[5], group=groups[23], role=roles[2], tenant=tenants[2], status=VLANStatusChoices.STATUS_RESERVED),
14161417
VLAN(vid=302, name='VLAN 302', site=sites[5], group=groups[23], role=roles[2], tenant=tenants[2], status=VLANStatusChoices.STATUS_RESERVED),
14171418

1419+
# Create one globally available VLAN on a VLAN group
1420+
VLAN(vid=500, name='VLAN Group 1', group=groups[24]),
1421+
14181422
# Create one globally available VLAN
14191423
VLAN(vid=1000, name='Global VLAN'),
14201424
)
@@ -1488,12 +1492,17 @@ def test_tenant_group(self):
14881492
def test_available_on_device(self):
14891493
device_id = Device.objects.first().pk
14901494
params = {'available_on_device': device_id}
1491-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) # 5 scoped + 1 global
1495+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 7) # 5 scoped + 1 global group + 1 global
14921496

14931497
def test_available_on_virtualmachine(self):
14941498
vm_id = VirtualMachine.objects.first().pk
14951499
params = {'available_on_virtualmachine': vm_id}
1496-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) # 5 scoped + 1 global
1500+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 7) # 5 scoped + 1 global group + 1 global
1501+
1502+
def test_available_at_site(self):
1503+
site_id = Site.objects.first().pk
1504+
params = {'available_at_site': site_id}
1505+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5) # 4 scoped + 1 global group + 1 global
14971506

14981507

14991508
class ServiceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):

0 commit comments

Comments
 (0)