Просмотр исходного кода

Fixes #21533: Fix missing `family`/`mask_length` in API when creating IP-related objects (#21546)

Johannes Rueschel 13 часов назад
Родитель
Сommit
3ce2bf75b4
2 измененных файлов с 60 добавлено и 9 удалено
  1. 25 9
      netbox/ipam/models/ip.py
  2. 35 0
      netbox/ipam/tests/test_models.py

+ 25 - 9
netbox/ipam/models/ip.py

@@ -159,9 +159,11 @@ class Aggregate(ContactsMixin, GetAvailablePrefixesMixin, PrimaryModel):
 
 
     @property
     @property
     def family(self):
     def family(self):
-        if self.prefix:
-            return self.prefix.version
-        return None
+        if not self.prefix:
+            return None
+        if isinstance(self.prefix, str):
+            return netaddr.IPNetwork(self.prefix).version
+        return self.prefix.version
 
 
     @property
     @property
     def ipv6_full(self):
     def ipv6_full(self):
@@ -335,11 +337,19 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary
 
 
     @property
     @property
     def family(self):
     def family(self):
-        return self.prefix.version if self.prefix else None
+        if not self.prefix:
+            return None
+        if isinstance(self.prefix, str):
+            return netaddr.IPNetwork(self.prefix).version
+        return self.prefix.version
 
 
     @property
     @property
     def mask_length(self):
     def mask_length(self):
-        return self.prefix.prefixlen if self.prefix else None
+        if not self.prefix:
+            return None
+        if isinstance(self.prefix, str):
+            return netaddr.IPNetwork(self.prefix).prefixlen
+        return self.prefix.prefixlen
 
 
     @property
     @property
     def ipv6_full(self):
     def ipv6_full(self):
@@ -642,7 +652,11 @@ class IPRange(ContactsMixin, PrimaryModel):
 
 
     @property
     @property
     def family(self):
     def family(self):
-        return self.start_address.version if self.start_address else None
+        if not self.start_address:
+            return None
+        if isinstance(self.start_address, str):
+            return netaddr.IPAddress(self.start_address.split('/')[0]).version
+        return self.start_address.version
 
 
     @property
     @property
     def range(self):
     def range(self):
@@ -990,9 +1004,11 @@ class IPAddress(ContactsMixin, PrimaryModel):
 
 
     @property
     @property
     def family(self):
     def family(self):
-        if self.address:
-            return self.address.version
-        return None
+        if not self.address:
+            return None
+        if isinstance(self.address, str):
+            return netaddr.IPNetwork(self.address).version
+        return self.address.version
 
 
     @property
     @property
     def is_oob_ip(self):
     def is_oob_ip(self):

+ 35 - 0
netbox/ipam/tests/test_models.py

@@ -11,6 +11,13 @@ from utilities.data import string_to_ranges
 
 
 class TestAggregate(TestCase):
 class TestAggregate(TestCase):
 
 
+    def test_family_string(self):
+        # Test property when prefix is a string
+        agg = Aggregate(prefix='10.0.0.0/8')
+        self.assertEqual(agg.family, 4)
+        agg_v6 = Aggregate(prefix='2001:db8::/32')
+        self.assertEqual(agg_v6.family, 6)
+
     def test_get_utilization(self):
     def test_get_utilization(self):
         rir = RIR.objects.create(name='RIR 1', slug='rir-1')
         rir = RIR.objects.create(name='RIR 1', slug='rir-1')
         aggregate = Aggregate(prefix=IPNetwork('10.0.0.0/8'), rir=rir)
         aggregate = Aggregate(prefix=IPNetwork('10.0.0.0/8'), rir=rir)
@@ -40,6 +47,13 @@ class TestAggregate(TestCase):
 
 
 class TestIPRange(TestCase):
 class TestIPRange(TestCase):
 
 
+    def test_family_string(self):
+        # Test property when start_address is a string
+        ip_range = IPRange(start_address='10.0.0.1/24', end_address='10.0.0.254/24')
+        self.assertEqual(ip_range.family, 4)
+        ip_range_v6 = IPRange(start_address='2001:db8::1/64', end_address='2001:db8::ffff/64')
+        self.assertEqual(ip_range_v6.family, 6)
+
     def test_overlapping_range(self):
     def test_overlapping_range(self):
         iprange_192_168 = IPRange.objects.create(
         iprange_192_168 = IPRange.objects.create(
             start_address=IPNetwork('192.168.0.1/22'), end_address=IPNetwork('192.168.0.49/22')
             start_address=IPNetwork('192.168.0.1/22'), end_address=IPNetwork('192.168.0.49/22')
@@ -90,6 +104,20 @@ class TestIPRange(TestCase):
 
 
 class TestPrefix(TestCase):
 class TestPrefix(TestCase):
 
 
+    def test_family_string(self):
+        # Test property when prefix is a string
+        prefix = Prefix(prefix='10.0.0.0/8')
+        self.assertEqual(prefix.family, 4)
+        prefix_v6 = Prefix(prefix='2001:db8::/32')
+        self.assertEqual(prefix_v6.family, 6)
+
+    def test_mask_length_string(self):
+        # Test property when prefix is a string
+        prefix = Prefix(prefix='10.0.0.0/8')
+        self.assertEqual(prefix.mask_length, 8)
+        prefix_v6 = Prefix(prefix='2001:db8::/32')
+        self.assertEqual(prefix_v6.mask_length, 32)
+
     def test_get_duplicates(self):
     def test_get_duplicates(self):
         prefixes = Prefix.objects.bulk_create((
         prefixes = Prefix.objects.bulk_create((
             Prefix(prefix=IPNetwork('192.0.2.0/24')),
             Prefix(prefix=IPNetwork('192.0.2.0/24')),
@@ -533,6 +561,13 @@ class TestPrefixHierarchy(TestCase):
 
 
 class TestIPAddress(TestCase):
 class TestIPAddress(TestCase):
 
 
+    def test_family_string(self):
+        # Test property when address is a string
+        ip = IPAddress(address='10.0.0.1/24')
+        self.assertEqual(ip.family, 4)
+        ip_v6 = IPAddress(address='2001:db8::1/64')
+        self.assertEqual(ip_v6.family, 6)
+
     def test_get_duplicates(self):
     def test_get_duplicates(self):
         ips = IPAddress.objects.bulk_create((
         ips = IPAddress.objects.bulk_create((
             IPAddress(address=IPNetwork('192.0.2.1/24')),
             IPAddress(address=IPNetwork('192.0.2.1/24')),