From 54f9a22be49411da8f23147137d3f99793c591a5 Mon Sep 17 00:00:00 2001 From: Erik Hansson Date: Wed, 19 Oct 2022 11:53:36 +0200 Subject: [PATCH] Add IPAM parent property Closes #10691 --- netbox/ipam/models/ip.py | 29 +++++++++++++++++++++++++++++ netbox/ipam/tests/test_models.py | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index 456bab4f0..93152120a 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -461,6 +461,16 @@ class Prefix(GetAvailablePrefixesMixin, NetBoxModel): f'prefix__{lookup}': self.prefix }) + @property + def parent_prefix(self): + """ + Return smallest containing Prefix in the hierarchy. + """ + return Prefix.objects.filter( + vrf= self.vrf, + prefix__net_contains= self.prefix + ).order_by("-prefix__net_mask_length").first() + def get_children(self, include_self=False): """ Return all covered Prefixes in the hierarchy. @@ -957,6 +967,25 @@ class IPAddress(NetBoxModel): return self.address.version return None + @property + def parent_prefix(self): + """ + Return smallest containing Prefix in the hierarchy. + """ + return Prefix.objects.filter( + vrf= self.vrf, + prefix__net_contains= self.address.ip + ).order_by("-prefix__net_mask_length").first() + + @property + def parent_range(self): + """ + Return the range containing this address, if any. + """ + return IPRange.objects.filter( + start_address__lte=self.address, + end_address__gte=self.address).order_by("size").first() + def _set_mask_length(self, value): """ Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly, diff --git a/netbox/ipam/tests/test_models.py b/netbox/ipam/tests/test_models.py index 94a315be5..16fc6d5ad 100644 --- a/netbox/ipam/tests/test_models.py +++ b/netbox/ipam/tests/test_models.py @@ -117,6 +117,24 @@ class TestPrefix(TestCase): # VRF container is limited to its own VRF self.assertSetEqual(child_ip_pks, {ips[1].pk}) + def test_get_parent_prefix(self): + prefixes = Prefix.objects.bulk_create(( + Prefix(prefix=IPNetwork('10.0.0.0/16'), status=PrefixStatusChoices.STATUS_CONTAINER), + Prefix(prefix=IPNetwork('10.0.0.0/24'), status=PrefixStatusChoices.STATUS_ACTIVE) + )) + ips = IPAddress.objects.bulk_create(( + IPAddress(address=IPNetwork('10.0.0.1/24')), + IPAddress(address=IPNetwork('10.0.0.2/24')), + )) + ranges = IPRange.objects.bulk_create(( + IPRange(start_address=IPNetwork('10.0.0.1/24'), end_address=IPNetwork('10.0.0.10/24'), size=10), + IPRange(start_address=IPNetwork('10.0.0.11/24'), end_address=IPNetwork('10.0.0.17/24'), size=7), + IPRange(start_address=IPNetwork('10.0.0.1/24'), end_address=IPNetwork('10.0.0.17/24'), size=17), + )) + self.assertEqual(prefixes[1], ips[0].parent_prefix) + self.assertEqual(prefixes[0], prefixes[1].parent_prefix) + self.assertEqual(ranges[0], ips[0].parent_range) + def test_get_available_prefixes(self): prefixes = Prefix.objects.bulk_create((