Răsfoiți Sursa

Drop family column from Aggregate, Prefix, and IPAddress models

Jeremy Stretch 6 ani în urmă
părinte
comite
b475a575e4

+ 2 - 0
netbox/ipam/fields.py

@@ -63,6 +63,7 @@ IPNetworkField.register_lookup(lookups.NetContained)
 IPNetworkField.register_lookup(lookups.NetContainedOrEqual)
 IPNetworkField.register_lookup(lookups.NetContains)
 IPNetworkField.register_lookup(lookups.NetContainsOrEquals)
+IPNetworkField.register_lookup(lookups.NetFamily)
 IPNetworkField.register_lookup(lookups.NetMaskLength)
 
 
@@ -90,4 +91,5 @@ IPAddressField.register_lookup(lookups.NetContainsOrEquals)
 IPAddressField.register_lookup(lookups.NetHost)
 IPAddressField.register_lookup(lookups.NetIn)
 IPAddressField.register_lookup(lookups.NetHostContained)
+IPAddressField.register_lookup(lookups.NetFamily)
 IPAddressField.register_lookup(lookups.NetMaskLength)

+ 3 - 3
netbox/ipam/filters.py

@@ -91,7 +91,7 @@ class AggregateFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
 
     class Meta:
         model = Aggregate
-        fields = ['family', 'date_added']
+        fields = ('date_added',)
 
     def search(self, queryset, name, value):
         if not value.strip():
@@ -211,7 +211,7 @@ class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
 
     class Meta:
         model = Prefix
-        fields = ['family', 'is_pool']
+        fields = ('is_pool',)
 
     def search(self, queryset, name, value):
         if not value.strip():
@@ -350,7 +350,7 @@ class IPAddressFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedF
 
     class Meta:
         model = IPAddress
-        fields = ['family', 'dns_name']
+        fields = ('dns_name',)
 
     def search(self, queryset, name, value):
         if not value.strip():

+ 9 - 0
netbox/ipam/lookups.py

@@ -154,6 +154,15 @@ class NetHostContained(Lookup):
         return 'CAST(HOST(%s) AS INET) << %s' % (lhs, rhs), params
 
 
+class NetFamily(Transform):
+    lookup_name = 'family'
+    function = 'FAMILY'
+
+    @property
+    def output_field(self):
+        return IntegerField()
+
+
 class NetMaskLength(Transform):
     lookup_name = 'net_mask_length'
     function = 'MASKLEN'

+ 1 - 1
netbox/ipam/managers.py

@@ -13,4 +13,4 @@ class IPAddressManager(models.Manager):
         IP address as a /32 or /128.
         """
         qs = super().get_queryset()
-        return qs.annotate(host=RawSQL('INET(HOST(ipam_ipaddress.address))', [])).order_by('family', 'host')
+        return qs.annotate(host=RawSQL('INET(HOST(ipam_ipaddress.address))', [])).order_by('host')

+ 38 - 0
netbox/ipam/migrations/0035_drop_ip_family.py

@@ -0,0 +1,38 @@
+# Generated by Django 2.2.9 on 2020-02-14 19:36
+
+from django.db import migrations
+import django.db.models.expressions
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('ipam', '0034_fix_ipaddress_status_dhcp'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='aggregate',
+            options={'ordering': ('prefix', 'pk')},
+        ),
+        migrations.AlterModelOptions(
+            name='ipaddress',
+            options={'ordering': ('address', 'pk'), 'verbose_name': 'IP address', 'verbose_name_plural': 'IP addresses'},
+        ),
+        migrations.AlterModelOptions(
+            name='prefix',
+            options={'ordering': (django.db.models.expressions.OrderBy(django.db.models.expressions.F('vrf'), nulls_first=True), 'prefix', 'pk'), 'verbose_name_plural': 'prefixes'},
+        ),
+        migrations.RemoveField(
+            model_name='aggregate',
+            name='family',
+        ),
+        migrations.RemoveField(
+            model_name='ipaddress',
+            name='family',
+        ),
+        migrations.RemoveField(
+            model_name='prefix',
+            name='family',
+        ),
+    ]

+ 26 - 32
netbox/ipam/models.py

@@ -150,9 +150,6 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
     An aggregate exists at the root level of the IP address space hierarchy in NetBox. Aggregates are used to organize
     the hierarchy and track the overall utilization of available address space. Each Aggregate is assigned to a RIR.
     """
-    family = models.PositiveSmallIntegerField(
-        choices=IPAddressFamilyChoices
-    )
     prefix = IPNetworkField()
     rir = models.ForeignKey(
         to='ipam.RIR',
@@ -182,7 +179,7 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
     ]
 
     class Meta:
-        ordering = ('family', 'prefix', 'pk')  # (family, prefix) may be non-unique
+        ordering = ('prefix', 'pk')  # prefix may be non-unique
 
     def __str__(self):
         return str(self.prefix)
@@ -225,12 +222,6 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
                     )
                 })
 
-    def save(self, *args, **kwargs):
-        if self.prefix:
-            # Infer address family from IPNetwork object
-            self.family = self.prefix.version
-        super().save(*args, **kwargs)
-
     def to_csv(self):
         return (
             self.prefix,
@@ -239,6 +230,12 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
             self.description,
         )
 
+    @property
+    def family(self):
+        if self.prefix:
+            return self.prefix.version
+        return None
+
     def get_utilization(self):
         """
         Determine the prefix utilization of the aggregate and return it as a percentage.
@@ -291,10 +288,6 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
     VRFs. A Prefix must be assigned a status and may optionally be assigned a used-define Role. A Prefix can also be
     assigned to a VLAN where appropriate.
     """
-    family = models.PositiveSmallIntegerField(
-        choices=IPAddressFamilyChoices,
-        editable=False
-    )
     prefix = IPNetworkField(
         help_text='IPv4 or IPv6 network with mask'
     )
@@ -376,7 +369,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
     }
 
     class Meta:
-        ordering = (F('vrf').asc(nulls_first=True), 'family', 'prefix', 'pk')  # (vrf, family, prefix) may be non-unique
+        ordering = (F('vrf').asc(nulls_first=True), 'prefix', 'pk')  # (vrf, prefix) may be non-unique
         verbose_name_plural = 'prefixes'
 
     def __str__(self):
@@ -423,9 +416,6 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             # Clear host bits from prefix
             self.prefix = self.prefix.cidr
 
-            # Record address family
-            self.family = self.prefix.version
-
         super().save(*args, **kwargs)
 
     def to_csv(self):
@@ -442,6 +432,12 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             self.description,
         )
 
+    @property
+    def family(self):
+        if self.prefix:
+            return self.prefix.version
+        return None
+
     def _set_prefix_length(self, value):
         """
         Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
@@ -501,9 +497,9 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
 
         # All IP addresses within a point-to-point prefix (IPv4 /31 or IPv6 /127) are considered usable
         if (
-            self.family == 4 and self.prefix.prefixlen == 31  # RFC 3021
+            self.prefix.version == 4 and self.prefix.prefixlen == 31  # RFC 3021
         ) or (
-            self.family == 6 and self.prefix.prefixlen == 127  # RFC 6164
+            self.prefix.version == 6 and self.prefix.prefixlen == 127  # RFC 6164
         ):
             return available_ips
 
@@ -546,7 +542,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             # Compile an IPSet to avoid counting duplicate IPs
             child_count = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]).size
             prefix_size = self.prefix.size
-            if self.family == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
+            if self.prefix.version == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
                 prefix_size -= 2
             return int(float(child_count) / prefix_size * 100)
 
@@ -562,10 +558,6 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
     for example, when mapping public addresses to private addresses. When an Interface has been assigned an IPAddress
     which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP.
     """
-    family = models.PositiveSmallIntegerField(
-        choices=IPAddressFamilyChoices,
-        editable=False
-    )
     address = IPAddressField(
         help_text='IPv4 or IPv6 address (with mask)'
     )
@@ -659,7 +651,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
     }
 
     class Meta:
-        ordering = ('family', 'address', 'pk')  # (family, address) may be non-unique
+        ordering = ('address', 'pk')  # address may be non-unique
         verbose_name = 'IP address'
         verbose_name_plural = 'IP addresses'
 
@@ -727,10 +719,6 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
 
     def save(self, *args, **kwargs):
 
-        # Record address family
-        if isinstance(self.address, netaddr.IPNetwork):
-            self.family = self.address.version
-
         # Force dns_name to lowercase
         self.dns_name = self.dns_name.lower()
 
@@ -754,9 +742,9 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
     def to_csv(self):
 
         # Determine if this IP is primary for a Device
-        if self.family == 4 and getattr(self, 'primary_ip4_for', False):
+        if self.address.version == 4 and getattr(self, 'primary_ip4_for', False):
             is_primary = True
-        elif self.family == 6 and getattr(self, 'primary_ip6_for', False):
+        elif self.address.version == 6 and getattr(self, 'primary_ip6_for', False):
             is_primary = True
         else:
             is_primary = False
@@ -775,6 +763,12 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
             self.description,
         )
 
+    @property
+    def family(self):
+        if self.address:
+            return self.address.version
+        return None
+
     def _set_mask_length(self, value):
         """
         Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,

+ 1 - 1
netbox/ipam/views.py

@@ -207,7 +207,7 @@ class RIRListView(PermissionRequiredMixin, ObjectListView):
                 'deprecated': 0,
                 'available': 0,
             }
-            aggregate_list = Aggregate.objects.filter(family=family, rir=rir)
+            aggregate_list = Aggregate.objects.filter(prefix__family=family, rir=rir)
             for aggregate in aggregate_list:
 
                 queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(aggregate.prefix))

+ 1 - 1
netbox/templates/ipam/aggregate.html

@@ -64,7 +64,7 @@
             <table class="table table-hover panel-body attr-table">
                 <tr>
                     <td>Family</td>
-                    <td>{{ aggregate.get_family_display }}</td>
+                    <td>IPv{{ aggregate.family }}</td>
                 </tr>
                 <tr>
                     <td>RIR</td>

+ 1 - 1
netbox/templates/ipam/ipaddress.html

@@ -65,7 +65,7 @@
             <table class="table table-hover panel-body attr-table">
                 <tr>
                     <td>Family</td>
-                    <td>{{ ipaddress.get_family_display }}</td>
+                    <td>IPv{{ ipaddress.family }}</td>
                 </tr>
                 <tr>
                     <td>VRF</td>

+ 1 - 1
netbox/templates/ipam/prefix.html

@@ -85,7 +85,7 @@
                 <table class="table table-hover panel-body attr-table">
                     <tr>
                         <td>Family</td>
-                        <td>{{ prefix.get_family_display }}</td>
+                        <td>IPv{{ prefix.family }}</td>
                     </tr>
                     <tr>
                         <td>VRF</td>