Forráskód Böngészése

18706 Fix VLAN Assignment checking (#19332)

* 18706 Fix VLAN assignment checking

* 18706 add tests

* 18706 review feedback
Arthur Hanson 9 hónapja
szülő
commit
81dfaf0d67
2 módosított fájl, 69 hozzáadás és 7 törlés
  1. 16 7
      netbox/ipam/models/vlans.py
  2. 53 0
      netbox/ipam/tests/test_models.py

+ 16 - 7
netbox/ipam/models/vlans.py

@@ -1,4 +1,5 @@
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
+from django.contrib.contenttypes.models import ContentType
 from django.contrib.postgres.fields import ArrayField, IntegerRangeField
 from django.contrib.postgres.fields import ArrayField, IntegerRangeField
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.core.validators import MaxValueValidator, MinValueValidator
@@ -6,7 +7,7 @@ from django.db import models
 from django.db.backends.postgresql.psycopg_any import NumericRange
 from django.db.backends.postgresql.psycopg_any import NumericRange
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
 
 
-from dcim.models import Interface
+from dcim.models import Interface, Site, SiteGroup
 from ipam.choices import *
 from ipam.choices import *
 from ipam.constants import *
 from ipam.constants import *
 from ipam.querysets import VLANQuerySet, VLANGroupQuerySet
 from ipam.querysets import VLANQuerySet, VLANGroupQuerySet
@@ -279,12 +280,20 @@ class VLAN(PrimaryModel):
         super().clean()
         super().clean()
 
 
         # Validate VLAN group (if assigned)
         # Validate VLAN group (if assigned)
-        if self.group and self.site and self.group.scope != self.site:
-            raise ValidationError(
-                _(
-                    "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}."
-                ).format(group=self.group, scope=self.group.scope, site=self.site)
-            )
+        if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(Site):
+            if self.site != self.group.scope:
+                raise ValidationError(
+                    _(
+                        "VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}."
+                    ).format(group=self.group, scope=self.group.scope, site=self.site)
+                )
+        if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(SiteGroup):
+            if self.site not in self.group.scope.sites.all():
+                raise ValidationError(
+                    _(
+                        "The assigned site {site} is not a member of the assigned group {group} (scope: {scope})."
+                    ).format(group=self.group, scope=self.group.scope, site=self.site)
+                )
 
 
         # Check that the VLAN ID is permitted in the assigned group (if any)
         # Check that the VLAN ID is permitted in the assigned group (if any)
         if self.group:
         if self.group:

+ 53 - 0
netbox/ipam/tests/test_models.py

@@ -1,8 +1,10 @@
+from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.test import TestCase, override_settings
 from django.test import TestCase, override_settings
 from netaddr import IPNetwork, IPSet
 from netaddr import IPNetwork, IPSet
 from utilities.data import string_to_ranges
 from utilities.data import string_to_ranges
 
 
+from dcim.models import Site, SiteGroup
 from ipam.choices import *
 from ipam.choices import *
 from ipam.models import *
 from ipam.models import *
 
 
@@ -645,3 +647,54 @@ class TestVLAN(TestCase):
         )
         )
         with self.assertRaises(ValidationError):
         with self.assertRaises(ValidationError):
             vlan.full_clean()
             vlan.full_clean()
+
+    def test_vlan_group_site_validation(self):
+        sitegroup = SiteGroup.objects.create(
+            name='Site Group 1',
+            slug='site-group-1',
+        )
+        sites = Site.objects.bulk_create((
+            Site(
+                name='Site 1',
+                slug='site-1',
+            ),
+            Site(
+                name='Site 2',
+                slug='site-2',
+            ),
+        ))
+        sitegroup.sites.add(sites[0])
+        vlangroups = VLANGroup.objects.bulk_create((
+            VLANGroup(
+                name='VLAN Group 1',
+                slug='vlan-group-1',
+                scope=sitegroup,
+                scope_type=ContentType.objects.get_for_model(SiteGroup),
+            ),
+            VLANGroup(
+                name='VLAN Group 2',
+                slug='vlan-group-2',
+                scope=sites[0],
+                scope_type=ContentType.objects.get_for_model(Site),
+            ),
+            VLANGroup(
+                name='VLAN Group 2',
+                slug='vlan-group-2',
+                scope=sites[1],
+                scope_type=ContentType.objects.get_for_model(Site),
+            ),
+        ))
+        vlan = VLAN(
+            name='VLAN 1',
+            vid=1,
+            group=vlangroups[0],
+            site=sites[0],
+        )
+
+        # VLAN Group 1 and 2 should be valid
+        vlan.full_clean()
+        vlan.group = vlangroups[1]
+        vlan.full_clean()
+        vlan.group = vlangroups[2]
+        with self.assertRaises(ValidationError):
+            vlan.full_clean()