diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 7e0867396f..4f1d7228db 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1228,15 +1228,12 @@ class InterfaceConnectionFilterForm(forms.Form, BootstrapMixin): # IP addresses # -class IPAddressForm(forms.ModelForm, BootstrapMixin): +class IPAddressForm(BootstrapMixin, CustomFieldForm): set_as_primary = forms.BooleanField(label='Set as primary IP for device', required=False) class Meta: model = IPAddress - fields = ['address', 'vrf', 'interface', 'set_as_primary'] - help_texts = { - 'address': 'IPv4 or IPv6 address (with mask)' - } + fields = ['address', 'vrf', 'tenant', 'status', 'interface', 'description'] def __init__(self, device, *args, **kwargs): diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 7f4bbeadeb..2d603d8e91 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -572,7 +572,8 @@ def device(request, pk): secrets = device.secrets.all() # Find all IP addresses assigned to this device - ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface').order_by('address') + ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface', 'vrf')\ + .order_by('address') # Find any related devices for convenient linking in the UI related_devices = [] @@ -1530,6 +1531,7 @@ def ipaddress_assign(request, pk): ipaddress = form.save(commit=False) ipaddress.interface = form.cleaned_data['interface'] ipaddress.save() + form.save_custom_fields() messages.success(request, u"Added new IP address {} to interface {}.".format(ipaddress, ipaddress.interface)) if form.cleaned_data['set_as_primary']: diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 039475d036..de6d599157 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -284,16 +284,12 @@ class IPAddressForm(BootstrapMixin, CustomFieldForm): livesearch = forms.CharField(required=False, label='IP Address', widget=Livesearch( query_key='q', query_url='ipam-api:ipaddress_list', field_to_update='nat_inside', obj_label='address') ) - nat_inside = forms.ModelChoiceField(queryset=IPAddress.objects.all(), required=False, label='NAT (Inside)', - widget=APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}', - display_field='address')) class Meta: model = IPAddress - fields = ['address', 'vrf', 'tenant', 'status', 'nat_device', 'nat_inside', 'description'] - help_texts = { - 'address': "IPv4 or IPv6 address and mask", - 'vrf': "VRF (if applicable)", + fields = ['address', 'vrf', 'tenant', 'status', 'nat_inside', 'description'] + widgets ={ + 'nat_inside': APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}', display_field='address') } def __init__(self, *args, **kwargs): diff --git a/netbox/ipam/migrations/0010_ipaddress_help_texts.py b/netbox/ipam/migrations/0010_ipaddress_help_texts.py new file mode 100644 index 0000000000..a1e05171df --- /dev/null +++ b/netbox/ipam/migrations/0010_ipaddress_help_texts.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-11-01 17:46 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import ipam.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('ipam', '0009_ipaddress_add_status'), + ] + + operations = [ + migrations.AlterField( + model_name='ipaddress', + name='address', + field=ipam.fields.IPAddressField(help_text=b'IPv4 or IPv6 address (with mask)'), + ), + migrations.AlterField( + model_name='ipaddress', + name='nat_inside', + field=models.OneToOneField(blank=True, help_text=b'The IP for which this address is the "outside" IP', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='nat_outside', to='ipam.IPAddress', verbose_name=b'NAT (Inside)'), + ), + ] diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index e8f4238b84..163712d1e7 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -346,7 +346,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel): 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=AF_CHOICES, editable=False) - address = IPAddressField() + address = IPAddressField(help_text="IPv4 or IPv6 address (with mask)") vrf = models.ForeignKey('VRF', related_name='ip_addresses', on_delete=models.PROTECT, blank=True, null=True, verbose_name='VRF') tenant = models.ForeignKey(Tenant, related_name='ip_addresses', blank=True, null=True, on_delete=models.PROTECT) @@ -354,7 +354,8 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel): interface = models.ForeignKey(Interface, related_name='ip_addresses', on_delete=models.CASCADE, blank=True, null=True) nat_inside = models.OneToOneField('self', related_name='nat_outside', on_delete=models.SET_NULL, blank=True, - null=True, verbose_name='NAT IP (inside)') + null=True, verbose_name='NAT (Inside)', + help_text="The IP for which this address is the \"outside\" IP") description = models.CharField(max_length=100, blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') diff --git a/netbox/templates/dcim/inc/_ipaddress.html b/netbox/templates/dcim/inc/_ipaddress.html index 3f805b611e..7bdc8bc1e3 100644 --- a/netbox/templates/dcim/inc/_ipaddress.html +++ b/netbox/templates/dcim/inc/_ipaddress.html @@ -2,6 +2,9 @@ {{ ip }} + + {{ ip.vrf|default:"Global" }} + {{ ip.interface }} {% if device.primary_ip4 == ip or device.primary_ip6 == ip %} diff --git a/netbox/templates/dcim/ipaddress_assign.html b/netbox/templates/dcim/ipaddress_assign.html index 212a374580..538023d088 100644 --- a/netbox/templates/dcim/ipaddress_assign.html +++ b/netbox/templates/dcim/ipaddress_assign.html @@ -1,7 +1,7 @@ {% extends '_base.html' %} {% load form_helpers %} -{% block title %}Add an IP Address{% endblock %} +{% block title %}Assign an IP Address{% endblock %} {% block content %}
@@ -18,10 +18,34 @@ {% endif %}
- Add an IP Address + IP Address
- {% render_form form %} + {% render_field form.address %} + {% render_field form.vrf %} + {% render_field form.tenant %} + {% render_field form.status %} + {% render_field form.description %} +
+
+
+
+ Interface Assignment +
+
+
+ +
+

{{ device }}

+
+
+ {% render_field form.interface %} +
+
+
+
Custom Fields
+
+ {% render_custom_fields form %}