diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 0ae9db7b2..e8b3dff0a 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -734,13 +734,12 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): }) # Enforce unique IP space (if applicable) - if self.role not in IPADDRESS_ROLES_NONUNIQUE and (( - self.vrf is None and settings.ENFORCE_GLOBAL_UNIQUE - ) or ( - self.vrf and self.vrf.enforce_unique - )): + if (self.vrf is None and settings.ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique): duplicate_ips = self.get_duplicates() - if duplicate_ips: + if duplicate_ips and ( + self.role not in IPADDRESS_ROLES_NONUNIQUE or + any(dip.role not in IPADDRESS_ROLES_NONUNIQUE for dip in duplicate_ips) + ): raise ValidationError({ 'address': "Duplicate IP address found in {}: {}".format( "VRF {}".format(self.vrf) if self.vrf else "global table", diff --git a/netbox/ipam/tests/test_models.py b/netbox/ipam/tests/test_models.py index 6091aa70e..a47862165 100644 --- a/netbox/ipam/tests/test_models.py +++ b/netbox/ipam/tests/test_models.py @@ -259,6 +259,18 @@ class TestIPAddress(TestCase): duplicate_ip = IPAddress(vrf=vrf, address=netaddr.IPNetwork('192.0.2.1/24')) self.assertRaises(ValidationError, duplicate_ip.clean) + @override_settings(ENFORCE_GLOBAL_UNIQUE=True) + def test_duplicate_nonunique_nonrole_role(self): + IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24')) + duplicate_ip = IPAddress(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP) + self.assertRaises(ValidationError, duplicate_ip.clean) + + @override_settings(ENFORCE_GLOBAL_UNIQUE=True) + def test_duplicate_nonunique_role_nonrole(self): + IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP) + duplicate_ip = IPAddress(address=netaddr.IPNetwork('192.0.2.1/24')) + self.assertRaises(ValidationError, duplicate_ip.clean) + @override_settings(ENFORCE_GLOBAL_UNIQUE=True) def test_duplicate_nonunique_role(self): IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)