diff --git a/netbox/dns/formfields.py b/netbox/dns/formfields.py new file mode 100644 index 000000000..6c1049f65 --- /dev/null +++ b/netbox/dns/formfields.py @@ -0,0 +1,41 @@ +from netaddr import IPNetwork, AddrFormatError +import netaddr + +from django import forms +from django.core.exceptions import ValidationError + +from ipam.models import IPAddress, Prefix + + +# +# Form fields +# + +class AddressFormField(forms.Field): + default_error_messages = { + 'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).", + } + + def to_python(self, value): + if not value: + return None + + # Ensure that a subnet mask has been specified. This prevents IPs from defaulting to a /32 or /128. + if len(value.split('/')) != 2: + raise ValidationError('CIDR mask (e.g. /24) is required.') + + try: + net = IPNetwork(value) + except AddrFormatError: + raise ValidationError("Please specify a valid IPv4 or IPv6 address.") + + ip = IPAddress.objects.filter(address=value) + if not ip: + net = IPNetwork(value) + obj = IPAddress(address=net) + obj.save() + return obj + else: + return ip[0] + + diff --git a/netbox/dns/forms.py b/netbox/dns/forms.py index f2f0df617..94f3d3ffe 100644 --- a/netbox/dns/forms.py +++ b/netbox/dns/forms.py @@ -11,6 +11,8 @@ from .models import ( Record, ) +from .formfields import AddressFormField + # # Zones # @@ -73,6 +75,8 @@ class ZoneFilterForm(forms.Form, BootstrapMixin): class RecordForm(forms.ModelForm, BootstrapMixin): + address = AddressFormField(required=False) + class Meta: model=Record fields = ['name', 'record_type', 'priority', 'zone', 'address', 'value', 'description'] @@ -88,10 +92,11 @@ class RecordForm(forms.ModelForm, BootstrapMixin): 'value': 'Text value else, in CNAME records for instance' } + class RecordFromCSVForm(forms.ModelForm): zone = forms.ModelChoiceField(queryset=Zone.objects.all(), to_field_name='name', error_messages={'invalid_choice': 'Zone not found.'}) - address = forms.ModelChoiceField(queryset=IPAddress.objects.all(), to_field_name='address', error_messages={'invalid_choice': 'IP Address not found.'}, required=False) + address = AddressFormField(required=False) class Meta: model=Record @@ -114,7 +119,7 @@ class RecordBulkEditForm(forms.Form, BootstrapMixin): record_type = forms.CharField(max_length=100, required=False, label='Type') priority = forms.IntegerField(required=False) zone = forms.ModelChoiceField(queryset=Zone.objects.all(), required=False) - address = forms.ModelChoiceField(queryset=IPAddress.objects.all(), required=False) + address = AddressFormField(required=False) value = forms.CharField(max_length=100, required=False) class RecordBulkDeleteForm(ConfirmationForm): diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 988332de2..c4a731ad5 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -523,8 +523,7 @@ class IPAddress(CreatedUpdatedModel): name = record_name, record_type = record_type, zone = which_zone, - address = self, - description = 'gen by netbox' + address = self ) def to_csv(self):