diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 705472ac5..cd15c8459 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -11,6 +11,7 @@ * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation +* [#6896](https://github.com/netbox-community/netbox/issues/6896) - Fix validation of IP address assigned as device/VM primary via NAT relation * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index cd5b89cfe..b428e4be7 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -649,18 +649,15 @@ class IPAddress(PrimaryModel): # Check for primary IP assignment that doesn't match the assigned device/VM if self.pk: - device = Device.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() - if device: - if getattr(self.assigned_object, 'device', None) != device: - raise ValidationError({ - 'interface': f"IP address is primary for device {device} but not assigned to it!" - }) - vm = VirtualMachine.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() - if vm: - if getattr(self.assigned_object, 'virtual_machine', None) != vm: - raise ValidationError({ - 'vminterface': f"IP address is primary for virtual machine {vm} but not assigned to it!" - }) + for cls, attr in ((Device, 'device'), (VirtualMachine, 'virtual_machine')): + parent = cls.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() + if parent and getattr(self.assigned_object, attr) != parent: + # Check for a NAT relationship + if not self.nat_inside or getattr(self.nat_inside.assigned_object, attr) != parent: + raise ValidationError({ + 'interface': f"IP address is primary for {cls._meta.model_name} {parent} but " + f"not assigned to it!" + }) # Validate IP status selection if self.status == IPAddressStatusChoices.STATUS_SLAAC and self.family != 6: