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.NetContainedOrEqual)
 IPNetworkField.register_lookup(lookups.NetContains)
 IPNetworkField.register_lookup(lookups.NetContains)
 IPNetworkField.register_lookup(lookups.NetContainsOrEquals)
 IPNetworkField.register_lookup(lookups.NetContainsOrEquals)
+IPNetworkField.register_lookup(lookups.NetFamily)
 IPNetworkField.register_lookup(lookups.NetMaskLength)
 IPNetworkField.register_lookup(lookups.NetMaskLength)
 
 
 
 
@@ -90,4 +91,5 @@ IPAddressField.register_lookup(lookups.NetContainsOrEquals)
 IPAddressField.register_lookup(lookups.NetHost)
 IPAddressField.register_lookup(lookups.NetHost)
 IPAddressField.register_lookup(lookups.NetIn)
 IPAddressField.register_lookup(lookups.NetIn)
 IPAddressField.register_lookup(lookups.NetHostContained)
 IPAddressField.register_lookup(lookups.NetHostContained)
+IPAddressField.register_lookup(lookups.NetFamily)
 IPAddressField.register_lookup(lookups.NetMaskLength)
 IPAddressField.register_lookup(lookups.NetMaskLength)

+ 3 - 3
netbox/ipam/filters.py

@@ -91,7 +91,7 @@ class AggregateFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
 
 
     class Meta:
     class Meta:
         model = Aggregate
         model = Aggregate
-        fields = ['family', 'date_added']
+        fields = ('date_added',)
 
 
     def search(self, queryset, name, value):
     def search(self, queryset, name, value):
         if not value.strip():
         if not value.strip():
@@ -211,7 +211,7 @@ class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
 
 
     class Meta:
     class Meta:
         model = Prefix
         model = Prefix
-        fields = ['family', 'is_pool']
+        fields = ('is_pool',)
 
 
     def search(self, queryset, name, value):
     def search(self, queryset, name, value):
         if not value.strip():
         if not value.strip():
@@ -350,7 +350,7 @@ class IPAddressFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedF
 
 
     class Meta:
     class Meta:
         model = IPAddress
         model = IPAddress
-        fields = ['family', 'dns_name']
+        fields = ('dns_name',)
 
 
     def search(self, queryset, name, value):
     def search(self, queryset, name, value):
         if not value.strip():
         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
         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):
 class NetMaskLength(Transform):
     lookup_name = 'net_mask_length'
     lookup_name = 'net_mask_length'
     function = 'MASKLEN'
     function = 'MASKLEN'

+ 1 - 1
netbox/ipam/managers.py

@@ -13,4 +13,4 @@ class IPAddressManager(models.Manager):
         IP address as a /32 or /128.
         IP address as a /32 or /128.
         """
         """
         qs = super().get_queryset()
         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
     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.
     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()
     prefix = IPNetworkField()
     rir = models.ForeignKey(
     rir = models.ForeignKey(
         to='ipam.RIR',
         to='ipam.RIR',
@@ -182,7 +179,7 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
     ]
     ]
 
 
     class Meta:
     class Meta:
-        ordering = ('family', 'prefix', 'pk')  # (family, prefix) may be non-unique
+        ordering = ('prefix', 'pk')  # prefix may be non-unique
 
 
     def __str__(self):
     def __str__(self):
         return str(self.prefix)
         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):
     def to_csv(self):
         return (
         return (
             self.prefix,
             self.prefix,
@@ -239,6 +230,12 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
             self.description,
             self.description,
         )
         )
 
 
+    @property
+    def family(self):
+        if self.prefix:
+            return self.prefix.version
+        return None
+
     def get_utilization(self):
     def get_utilization(self):
         """
         """
         Determine the prefix utilization of the aggregate and return it as a percentage.
         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
     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.
     assigned to a VLAN where appropriate.
     """
     """
-    family = models.PositiveSmallIntegerField(
-        choices=IPAddressFamilyChoices,
-        editable=False
-    )
     prefix = IPNetworkField(
     prefix = IPNetworkField(
         help_text='IPv4 or IPv6 network with mask'
         help_text='IPv4 or IPv6 network with mask'
     )
     )
@@ -376,7 +369,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
     }
     }
 
 
     class Meta:
     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'
         verbose_name_plural = 'prefixes'
 
 
     def __str__(self):
     def __str__(self):
@@ -423,9 +416,6 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             # Clear host bits from prefix
             # Clear host bits from prefix
             self.prefix = self.prefix.cidr
             self.prefix = self.prefix.cidr
 
 
-            # Record address family
-            self.family = self.prefix.version
-
         super().save(*args, **kwargs)
         super().save(*args, **kwargs)
 
 
     def to_csv(self):
     def to_csv(self):
@@ -442,6 +432,12 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             self.description,
             self.description,
         )
         )
 
 
+    @property
+    def family(self):
+        if self.prefix:
+            return self.prefix.version
+        return None
+
     def _set_prefix_length(self, value):
     def _set_prefix_length(self, value):
         """
         """
         Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
         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
         # All IP addresses within a point-to-point prefix (IPv4 /31 or IPv6 /127) are considered usable
         if (
         if (
-            self.family == 4 and self.prefix.prefixlen == 31  # RFC 3021
+            self.prefix.version == 4 and self.prefix.prefixlen == 31  # RFC 3021
         ) or (
         ) 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
             return available_ips
 
 
@@ -546,7 +542,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel):
             # Compile an IPSet to avoid counting duplicate IPs
             # Compile an IPSet to avoid counting duplicate IPs
             child_count = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]).size
             child_count = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]).size
             prefix_size = self.prefix.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
                 prefix_size -= 2
             return int(float(child_count) / prefix_size * 100)
             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
     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.
     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(
     address = IPAddressField(
         help_text='IPv4 or IPv6 address (with mask)'
         help_text='IPv4 or IPv6 address (with mask)'
     )
     )
@@ -659,7 +651,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
     }
     }
 
 
     class Meta:
     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 = 'IP address'
         verbose_name_plural = 'IP addresses'
         verbose_name_plural = 'IP addresses'
 
 
@@ -727,10 +719,6 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
 
 
     def save(self, *args, **kwargs):
     def save(self, *args, **kwargs):
 
 
-        # Record address family
-        if isinstance(self.address, netaddr.IPNetwork):
-            self.family = self.address.version
-
         # Force dns_name to lowercase
         # Force dns_name to lowercase
         self.dns_name = self.dns_name.lower()
         self.dns_name = self.dns_name.lower()
 
 
@@ -754,9 +742,9 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
     def to_csv(self):
     def to_csv(self):
 
 
         # Determine if this IP is primary for a Device
         # 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
             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
             is_primary = True
         else:
         else:
             is_primary = False
             is_primary = False
@@ -775,6 +763,12 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
             self.description,
             self.description,
         )
         )
 
 
+    @property
+    def family(self):
+        if self.address:
+            return self.address.version
+        return None
+
     def _set_mask_length(self, value):
     def _set_mask_length(self, value):
         """
         """
         Expose the IPNetwork object's prefixlen attribute on the parent model so that it can be manipulated directly,
         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,
                 'deprecated': 0,
                 'available': 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:
             for aggregate in aggregate_list:
 
 
                 queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(aggregate.prefix))
                 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">
             <table class="table table-hover panel-body attr-table">
                 <tr>
                 <tr>
                     <td>Family</td>
                     <td>Family</td>
-                    <td>{{ aggregate.get_family_display }}</td>
+                    <td>IPv{{ aggregate.family }}</td>
                 </tr>
                 </tr>
                 <tr>
                 <tr>
                     <td>RIR</td>
                     <td>RIR</td>

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

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

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

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