Only accept networks for IPNetworkVar

This commit is contained in:
Saria Hajjar 2020-01-16 22:11:25 +00:00
parent 7a83c0f79d
commit 6c905d4f00
5 changed files with 27 additions and 45 deletions

View File

@ -160,11 +160,14 @@ An uploaded file. Note that uploaded files are present in memory only for the du
### IPAddressVar ### IPAddressVar
An IPv4 or IPv6 address (CIDR mask not allowed). An IPv4 or IPv6 address. Returns an instance of `netaddr.IPNetwork`. Options include:
* `min_prefix_length` - Minimum length of the mask (default: none)
* `max_prefix_length` - Maximum length of the mask (default: none)
### IPNetworkVar ### IPNetworkVar
An IPv4 or IPv6 network with a mask. Options include: Similar to `IPAddressVar` but will only accept networks (i.e. host-bits cannot be set). Options include:
* `min_prefix_length` - Minimum length of the mask (default: none) * `min_prefix_length` - Minimum length of the mask (default: none)
* `max_prefix_length` - Maximum length of the mask (default: none) * `max_prefix_length` - Maximum length of the mask (default: none)

View File

@ -14,7 +14,8 @@ from django.db import transaction
from mptt.forms import TreeNodeChoiceField, TreeNodeMultipleChoiceField from mptt.forms import TreeNodeChoiceField, TreeNodeMultipleChoiceField
from mptt.models import MPTTModel from mptt.models import MPTTModel
from ipam.formfields import IPAddressFormField, IPNetworkFormField from ipam.fields import prefix_validator
from ipam.formfields import IPFormField
from utilities.exceptions import AbortTransaction from utilities.exceptions import AbortTransaction
from utilities.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator from utilities.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
@ -201,14 +202,7 @@ class IPAddressVar(ScriptVariable):
""" """
An IPv4 or IPv6 address. An IPv4 or IPv6 address.
""" """
form_field = IPAddressFormField form_field = IPFormField
class IPNetworkVar(ScriptVariable):
"""
An IPv4 or IPv6 prefix.
"""
form_field = IPNetworkFormField
def __init__(self, min_prefix_length=None, max_prefix_length=None, *args, **kwargs): def __init__(self, min_prefix_length=None, max_prefix_length=None, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -226,6 +220,19 @@ class IPNetworkVar(ScriptVariable):
) )
class IPNetworkVar(IPAddressVar):
"""
An IPv4 or IPv6 prefix.
"""
form_field = IPFormField
def __init__(self, min_prefix_length=None, max_prefix_length=None, *args, **kwargs):
super().__init__(*args, **kwargs)
# Reject prefixes with any host-bits set
self.field_attrs['validators'].append(prefix_validator)
# #
# Scripts # Scripts
# #

View File

@ -1,6 +1,6 @@
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase from django.test import TestCase
from netaddr import IPAddress, IPNetwork from netaddr import IPNetwork
from dcim.models import DeviceRole from dcim.models import DeviceRole
from extras.scripts import * from extras.scripts import *
@ -198,17 +198,11 @@ class ScriptVariablesTest(TestCase):
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors) self.assertIn('var1', form.errors)
# Subnet masks are not accepted
data = {'var1': '192.0.2.0/24'}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors)
# Validate valid data # Validate valid data
data = {'var1': '192.0.2.0'} data = {'var1': '192.0.2.1/24'}
form = TestScript().as_form(data, None) form = TestScript().as_form(data, None)
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], IPAddress(data['var1'])) self.assertEqual(form.cleaned_data['var1'], IPNetwork(data['var1']))
def test_ipnetworkvar(self): def test_ipnetworkvar(self):

View File

@ -3,7 +3,7 @@ from django.db import models
from netaddr import AddrFormatError, IPNetwork, IPAddress from netaddr import AddrFormatError, IPNetwork, IPAddress
from . import lookups from . import lookups
from .formfields import IPNetworkFormField from .formfields import IPFormField
def prefix_validator(prefix): def prefix_validator(prefix):
@ -40,7 +40,7 @@ class BaseIPField(models.Field):
return str(self.to_python(value)) return str(self.to_python(value))
def form_class(self): def form_class(self):
return IPNetworkFormField return IPFormField
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': self.form_class()} defaults = {'form_class': self.form_class()}

View File

@ -7,29 +7,7 @@ from netaddr import IPAddress, IPNetwork, AddrFormatError
# Form fields # Form fields
# #
class IPAddressFormField(forms.Field): class IPFormField(forms.Field):
default_error_messages = {
'invalid': "Enter a valid IPv4 or IPv6 address (without CIDR mask).",
}
def to_python(self, value):
if not value:
return None
if isinstance(value, IPAddress):
return value
# Prevent CIDR masks; an IPAddress doesn't have one
if len(value.split('/')) != 1:
raise ValidationError('CIDR mask (e.g. /24) is not allowed.')
try:
return IPAddress(value)
except AddrFormatError:
raise ValidationError("Please specify a valid IPv4 or IPv6 address.")
class IPNetworkFormField(forms.Field):
default_error_messages = { default_error_messages = {
'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).", 'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).",
} }