Browse Source

Fixes #1469: Allow a NAT IP to be assigned as the primary IP for a device

Jeremy Stretch 7 years ago
parent
commit
6b53d263fe
2 changed files with 36 additions and 9 deletions
  1. 22 7
      netbox/dcim/forms.py
  2. 14 2
      netbox/dcim/models.py

+ 22 - 7
netbox/dcim/forms.py

@@ -642,13 +642,28 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm):
 
             # Compile list of choices for primary IPv4 and IPv6 addresses
             for family in [4, 6]:
-                ip_choices = []
-                interface_ips = IPAddress.objects.filter(family=family, interface__device=self.instance)
-                ip_choices += [(ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips]
-                nat_ips = IPAddress.objects.filter(family=family, nat_inside__interface__device=self.instance)\
-                    .select_related('nat_inside__interface')
-                ip_choices += [(ip.id, '{} ({} NAT)'.format(ip.address, ip.nat_inside.interface)) for ip in nat_ips]
-                self.fields['primary_ip{}'.format(family)].choices = [(None, '---------')] + ip_choices
+                ip_choices = [(None, '---------')]
+                # Collect interface IPs
+                interface_ips = IPAddress.objects.select_related('interface').filter(
+                    family=family, interface__device=self.instance
+                )
+                if interface_ips:
+                    ip_choices.append(
+                        ('Interface IPs', [
+                            (ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips
+                        ])
+                    )
+                # Collect NAT IPs
+                nat_ips = IPAddress.objects.select_related('nat_inside').filter(
+                    family=family, nat_inside__interface__device=self.instance
+                )
+                if nat_ips:
+                    ip_choices.append(
+                        ('NAT IPs', [
+                            (ip.id, '{} ({})'.format(ip.address, ip.nat_inside.address)) for ip in nat_ips
+                        ])
+                    )
+                self.fields['primary_ip{}'.format(family)].choices = ip_choices
 
             # If editing an existing device, exclude it from the list of occupied rack units. This ensures that a device
             # can be flipped from one face to another.

+ 14 - 2
netbox/dcim/models.py

@@ -891,13 +891,25 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
                 pass
 
         # Validate primary IPv4 address
-        if self.primary_ip4 and (self.primary_ip4.interface is None or self.primary_ip4.interface.device != self):
+        if self.primary_ip4 and (
+            self.primary_ip4.interface is None or
+            self.primary_ip4.interface.device != self
+        ) and (
+            self.primary_ip4.nat_inside.interface is None or
+            self.primary_ip4.nat_inside.interface.device != self
+        ):
             raise ValidationError({
                 'primary_ip4': "The specified IP address ({}) is not assigned to this device.".format(self.primary_ip4),
             })
 
         # Validate primary IPv6 address
-        if self.primary_ip6 and (self.primary_ip6.interface is None or self.primary_ip6.interface.device != self):
+        if self.primary_ip6 and (
+            self.primary_ip6.interface is None or
+            self.primary_ip6.interface.device != self
+        ) and (
+            self.primary_ip6.nat_inside.interface is None or
+            self.primary_ip6.nat_inside.interface.device != self
+        ):
             raise ValidationError({
                 'primary_ip6': "The specified IP address ({}) is not assigned to this device.".format(self.primary_ip6),
             })