Просмотр исходного кода

Fixes #5038: Fix validation of primary IPs assigned to virtual machines

Jeremy Stretch 5 лет назад
Родитель
Сommit
6e28490b84

+ 8 - 0
docs/release-notes/version-2.9.md

@@ -1,5 +1,13 @@
 # NetBox v2.9
 
+## v2.9.2 (FUTURE)
+
+### Bug Fixes
+
+* [#5038](https://github.com/netbox-community/netbox/issues/5038) - Fix validation of primary IPs assigned to virtual machines
+
+---
+
 ## v2.9.1 (2020-08-22)
 
 ### Enhancements

+ 1 - 1
netbox/dcim/forms.py

@@ -1811,7 +1811,7 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
                     nat_inside__assigned_object_id__in=interface_ids
                 ).prefetch_related('assigned_object')
                 if nat_ips:
-                    ip_list = [(ip.id, f'{ip.address} ({ip.assigned_object})') for ip in nat_ips]
+                    ip_list = [(ip.id, f'{ip.address} (NAT)') for ip in nat_ips]
                     ip_choices.append(('NAT IPs', ip_list))
                 self.fields['primary_ip{}'.format(family)].choices = ip_choices
 

+ 14 - 13
netbox/virtualization/forms.py

@@ -1,4 +1,5 @@
 from django import forms
+from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 
 from dcim.choices import InterfaceModeChoices
@@ -325,28 +326,28 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
             # Compile list of choices for primary IPv4 and IPv6 addresses
             for family in [4, 6]:
                 ip_choices = [(None, '---------')]
+
+                # Gather PKs of all interfaces belonging to this VM
+                interface_ids = self.instance.interfaces.values_list('pk', flat=True)
+
                 # Collect interface IPs
-                interface_ips = IPAddress.objects.prefetch_related('interface').filter(
+                interface_ips = IPAddress.objects.filter(
                     address__family=family,
-                    vminterface__in=self.instance.interfaces.values_list('id', flat=True)
+                    assigned_object_type=ContentType.objects.get_for_model(VMInterface),
+                    assigned_object_id__in=interface_ids
                 )
                 if interface_ips:
-                    ip_choices.append(
-                        ('Interface IPs', [
-                            (ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips
-                        ])
-                    )
+                    ip_list = [(ip.id, f'{ip.address} ({ip.assigned_object})') for ip in interface_ips]
+                    ip_choices.append(('Interface IPs', ip_list))
                 # Collect NAT IPs
                 nat_ips = IPAddress.objects.prefetch_related('nat_inside').filter(
                     address__family=family,
-                    nat_inside__vminterface__in=self.instance.interfaces.values_list('id', flat=True)
+                    nat_inside__assigned_object_type=ContentType.objects.get_for_model(VMInterface),
+                    nat_inside__assigned_object_id__in=interface_ids
                 )
                 if nat_ips:
-                    ip_choices.append(
-                        ('NAT IPs', [
-                            (ip.id, '{} ({})'.format(ip.address, ip.nat_inside.address)) for ip in nat_ips
-                        ])
-                    )
+                    ip_list = [(ip.id, f'{ip.address} (NAT)') for ip in nat_ips]
+                    ip_choices.append(('NAT IPs', ip_list))
                 self.fields['primary_ip{}'.format(family)].choices = ip_choices
 
         else:

+ 3 - 3
netbox/virtualization/models.py

@@ -335,13 +335,13 @@ class VirtualMachine(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
         for field in ['primary_ip4', 'primary_ip6']:
             ip = getattr(self, field)
             if ip is not None:
-                if ip.interface in interfaces:
+                if ip.assigned_object in interfaces:
                     pass
-                elif self.primary_ip4.nat_inside is not None and self.primary_ip4.nat_inside.interface in interfaces:
+                elif ip.nat_inside is not None and ip.nat_inside.assigned_object in interfaces:
                     pass
                 else:
                     raise ValidationError({
-                        field: "The specified IP address ({}) is not assigned to this VM.".format(ip),
+                        field: f"The specified IP address ({ip}) is not assigned to this VM.",
                     })
 
     def to_csv(self):