From e98dd4832cf142b5a0467967f15be0b984d1cfb8 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 25 Aug 2023 18:56:08 +0530 Subject: [PATCH 1/4] adds parent filter on iprange #13313 --- netbox/ipam/filtersets.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index 9b57cb273cf..e02761fd6d2 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -467,6 +467,10 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet): choices=IPRangeStatusChoices, null_value=None ) + parent = MultiValueCharFilter( + method='search_by_parent', + label=_('Parent prefix'), + ) class Meta: model = IPRange @@ -500,6 +504,18 @@ def filter_address(self, queryset, name, value): return queryset.filter(**{f'{name}__net_in': value}) except ValidationError: return queryset.none() + + def search_by_parent(self, queryset, name, value): + if not value: + return queryset + q = Q() + for prefix in value: + try: + query = str(netaddr.IPNetwork(prefix.strip()).cidr) + q |= Q(start_address__net_host_contained=query) + except (AddrFormatError, ValueError): + return queryset.none() + return queryset.filter(q) class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet): From ded2a33948381dbea1d29330519f57b3bc2054aa Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 25 Aug 2023 19:55:29 +0530 Subject: [PATCH 2/4] lint fix --- netbox/ipam/filtersets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index e02761fd6d2..80cf1da2e03 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -504,7 +504,7 @@ def filter_address(self, queryset, name, value): return queryset.filter(**{f'{name}__net_in': value}) except ValidationError: return queryset.none() - + def search_by_parent(self, queryset, name, value): if not value: return queryset From ff4d2f2cdc879c553180ab5f5670b9112b11e9eb Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 25 Aug 2023 20:01:32 +0530 Subject: [PATCH 3/4] adds filterset test --- netbox/ipam/tests/test_filtersets.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index 0ae7544ab9a..b25c4230b64 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -10,7 +10,6 @@ from utilities.testing import ChangeLoggedFilterSetTests, create_test_device, create_test_virtualmachine from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from tenancy.models import Tenant, TenantGroup -from rest_framework import serializers class ASNRangeTestCase(TestCase, ChangeLoggedFilterSetTests): @@ -741,6 +740,8 @@ def setUpTestData(cls): ) Tenant.objects.bulk_create(tenants) + Prefix.objects.create(prefix='10.0.1.0/24') + ip_ranges = ( IPRange(start_address='10.0.1.100/24', end_address='10.0.1.199/24', size=100, vrf=None, tenant=None, role=None, status=IPRangeStatusChoices.STATUS_ACTIVE, description='foobar1'), IPRange(start_address='10.0.2.100/24', end_address='10.0.2.199/24', size=100, vrf=vrfs[0], tenant=tenants[0], role=roles[0], status=IPRangeStatusChoices.STATUS_ACTIVE, description='foobar2'), @@ -807,6 +808,11 @@ def test_description(self): params = {'description': ['foobar1', 'foobar2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_parent(self): + prefix = Prefix.objects.get(prefix='10.0.1.0/24') + params = {'parent': [prefix.prefix]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = IPAddress.objects.all() From 2b0f0b04e855a00718724ccb2f7dc1a6d46dd652 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 28 Aug 2023 08:47:51 -0400 Subject: [PATCH 4/4] Filter should match both start & end of IP range --- netbox/ipam/filtersets.py | 2 +- netbox/ipam/tests/test_filtersets.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index 80cf1da2e03..bc918128651 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -512,7 +512,7 @@ def search_by_parent(self, queryset, name, value): for prefix in value: try: query = str(netaddr.IPNetwork(prefix.strip()).cidr) - q |= Q(start_address__net_host_contained=query) + q |= Q(start_address__net_host_contained=query, end_address__net_host_contained=query) except (AddrFormatError, ValueError): return queryset.none() return queryset.filter(q) diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py index b25c4230b64..0aa78e6221d 100644 --- a/netbox/ipam/tests/test_filtersets.py +++ b/netbox/ipam/tests/test_filtersets.py @@ -740,8 +740,6 @@ def setUpTestData(cls): ) Tenant.objects.bulk_create(tenants) - Prefix.objects.create(prefix='10.0.1.0/24') - ip_ranges = ( IPRange(start_address='10.0.1.100/24', end_address='10.0.1.199/24', size=100, vrf=None, tenant=None, role=None, status=IPRangeStatusChoices.STATUS_ACTIVE, description='foobar1'), IPRange(start_address='10.0.2.100/24', end_address='10.0.2.199/24', size=100, vrf=vrfs[0], tenant=tenants[0], role=roles[0], status=IPRangeStatusChoices.STATUS_ACTIVE, description='foobar2'), @@ -809,9 +807,10 @@ def test_description(self): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) def test_parent(self): - prefix = Prefix.objects.get(prefix='10.0.1.0/24') - params = {'parent': [prefix.prefix]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + params = {'parent': ['10.0.1.0/24', '10.0.2.0/24']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'parent': ['10.0.1.0/25']} # Range 10.0.1.100-199 is not fully contained by 10.0.1.0/25 + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0) class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):