Parcourir la source

Closes #901: Support for filtering prefixes and IP addresses by mask length

Jeremy Stretch il y a 8 ans
Parent
commit
db60e8868c
4 fichiers modifiés avec 40 ajouts et 3 suppressions
  1. 3 1
      netbox/ipam/fields.py
  2. 18 0
      netbox/ipam/filters.py
  3. 9 1
      netbox/ipam/forms.py
  4. 10 1
      netbox/ipam/lookups.py

+ 3 - 1
netbox/ipam/fields.py

@@ -6,7 +6,7 @@ from django.db import models
 from .formfields import IPFormField
 from .lookups import (
     EndsWith, IEndsWith, IRegex, IStartsWith, NetContained, NetContainedOrEqual, NetContains, NetContainsOrEquals,
-    NetHost, Regex, StartsWith,
+    NetHost, NetMaskLength, Regex, StartsWith,
 )
 
 
@@ -67,6 +67,7 @@ IPNetworkField.register_lookup(NetContainedOrEqual)
 IPNetworkField.register_lookup(NetContains)
 IPNetworkField.register_lookup(NetContainsOrEquals)
 IPNetworkField.register_lookup(NetHost)
+IPNetworkField.register_lookup(NetMaskLength)
 
 
 class IPAddressField(BaseIPField):
@@ -90,3 +91,4 @@ IPAddressField.register_lookup(NetContainedOrEqual)
 IPAddressField.register_lookup(NetContains)
 IPAddressField.register_lookup(NetContainsOrEquals)
 IPAddressField.register_lookup(NetHost)
+IPAddressField.register_lookup(NetMaskLength)

+ 18 - 0
netbox/ipam/filters.py

@@ -92,6 +92,10 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
         method='search_by_parent',
         label='Parent prefix',
     )
+    mask_length = django_filters.NumberFilter(
+        method='filter_mask_length',
+        label='Mask length',
+    )
     vrf_id = NullableModelMultipleChoiceFilter(
         name='vrf_id',
         queryset=VRF.objects.all(),
@@ -171,6 +175,11 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
         except AddrFormatError:
             return queryset.none()
 
+    def filter_mask_length(self, queryset, name, value):
+        if not value:
+            return queryset
+        return queryset.filter(prefix__net_mask_length=value)
+
 
 class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
     q = django_filters.CharFilter(
@@ -181,6 +190,10 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
         method='search_by_parent',
         label='Parent prefix',
     )
+    mask_length = django_filters.NumberFilter(
+        method='filter_mask_length',
+        label='Mask length',
+    )
     vrf_id = NullableModelMultipleChoiceFilter(
         name='vrf_id',
         queryset=VRF.objects.all(),
@@ -245,6 +258,11 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
         except AddrFormatError:
             return queryset.none()
 
+    def filter_mask_length(self, queryset, name, value):
+        if not value:
+            return queryset
+        return queryset.filter(address__net_mask_length=value)
+
 
 class VLANGroupFilter(django_filters.FilterSet):
     site_id = NullableModelMultipleChoiceFilter(

+ 9 - 1
netbox/ipam/forms.py

@@ -21,6 +21,12 @@ IP_FAMILY_CHOICES = [
     (6, 'IPv6'),
 ]
 
+PREFIX_MASK_LENGTH_CHOICES = [
+    ('', '---------'),
+] + [(i, i) for i in range(1, 128)]
+
+IPADDRESS_MASK_LENGTH_CHOICES = PREFIX_MASK_LENGTH_CHOICES + [(128, 128)]
+
 
 #
 # VRFs
@@ -266,6 +272,7 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
         'placeholder': 'Prefix',
     }))
     family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address family')
+    mask_length = forms.ChoiceField(required=False, choices=PREFIX_MASK_LENGTH_CHOICES, label='Mask length')
     vrf = FilterChoiceField(
         queryset=VRF.objects.annotate(filter_count=Count('prefixes')),
         to_field_name='rd',
@@ -503,7 +510,8 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
     parent = forms.CharField(required=False, label='Parent Prefix', widget=forms.TextInput(attrs={
         'placeholder': 'Prefix',
     }))
-    family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
+    family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address family')
+    mask_length = forms.ChoiceField(required=False, choices=IPADDRESS_MASK_LENGTH_CHOICES, label='Mask length')
     vrf = FilterChoiceField(
         queryset=VRF.objects.annotate(filter_count=Count('ip_addresses')),
         to_field_name='rd',

+ 10 - 1
netbox/ipam/lookups.py

@@ -1,4 +1,4 @@
-from django.db.models import Lookup
+from django.db.models import Lookup, Transform, IntegerField
 from django.db.models.lookups import BuiltinLookup
 
 
@@ -87,3 +87,12 @@ class NetHost(Lookup):
             rhs_params[0] = rhs_params[0].split('/')[0]
         params = lhs_params + rhs_params
         return 'HOST(%s) = %s' % (lhs, rhs), params
+
+
+class NetMaskLength(Transform):
+    lookup_name = 'net_mask_length'
+    function = 'MASKLEN'
+
+    @property
+    def output_field(self):
+        return IntegerField()