Skip to content

Commit 81dfaf0

Browse files
authored
18706 Fix VLAN Assignment checking (#19332)
* 18706 Fix VLAN assignment checking * 18706 add tests * 18706 review feedback
1 parent 584fff9 commit 81dfaf0

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

netbox/ipam/models/vlans.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
2+
from django.contrib.contenttypes.models import ContentType
23
from django.contrib.postgres.fields import ArrayField, IntegerRangeField
34
from django.core.exceptions import ValidationError
45
from django.core.validators import MaxValueValidator, MinValueValidator
56
from django.db import models
67
from django.db.backends.postgresql.psycopg_any import NumericRange
78
from django.utils.translation import gettext_lazy as _
89

9-
from dcim.models import Interface
10+
from dcim.models import Interface, Site, SiteGroup
1011
from ipam.choices import *
1112
from ipam.constants import *
1213
from ipam.querysets import VLANQuerySet, VLANGroupQuerySet
@@ -279,12 +280,20 @@ def clean(self):
279280
super().clean()
280281

281282
# Validate VLAN group (if assigned)
282-
if self.group and self.site and self.group.scope != self.site:
283-
raise ValidationError(
284-
_(
285-
"VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}."
286-
).format(group=self.group, scope=self.group.scope, site=self.site)
287-
)
283+
if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(Site):
284+
if self.site != self.group.scope:
285+
raise ValidationError(
286+
_(
287+
"VLAN is assigned to group {group} (scope: {scope}); cannot also assign to site {site}."
288+
).format(group=self.group, scope=self.group.scope, site=self.site)
289+
)
290+
if self.group and self.site and self.group.scope_type == ContentType.objects.get_for_model(SiteGroup):
291+
if self.site not in self.group.scope.sites.all():
292+
raise ValidationError(
293+
_(
294+
"The assigned site {site} is not a member of the assigned group {group} (scope: {scope})."
295+
).format(group=self.group, scope=self.group.scope, site=self.site)
296+
)
288297

289298
# Check that the VLAN ID is permitted in the assigned group (if any)
290299
if self.group:

netbox/ipam/tests/test_models.py

+53
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from django.contrib.contenttypes.models import ContentType
12
from django.core.exceptions import ValidationError
23
from django.test import TestCase, override_settings
34
from netaddr import IPNetwork, IPSet
45
from utilities.data import string_to_ranges
56

7+
from dcim.models import Site, SiteGroup
68
from ipam.choices import *
79
from ipam.models import *
810

@@ -645,3 +647,54 @@ def test_qinq_role(self):
645647
)
646648
with self.assertRaises(ValidationError):
647649
vlan.full_clean()
650+
651+
def test_vlan_group_site_validation(self):
652+
sitegroup = SiteGroup.objects.create(
653+
name='Site Group 1',
654+
slug='site-group-1',
655+
)
656+
sites = Site.objects.bulk_create((
657+
Site(
658+
name='Site 1',
659+
slug='site-1',
660+
),
661+
Site(
662+
name='Site 2',
663+
slug='site-2',
664+
),
665+
))
666+
sitegroup.sites.add(sites[0])
667+
vlangroups = VLANGroup.objects.bulk_create((
668+
VLANGroup(
669+
name='VLAN Group 1',
670+
slug='vlan-group-1',
671+
scope=sitegroup,
672+
scope_type=ContentType.objects.get_for_model(SiteGroup),
673+
),
674+
VLANGroup(
675+
name='VLAN Group 2',
676+
slug='vlan-group-2',
677+
scope=sites[0],
678+
scope_type=ContentType.objects.get_for_model(Site),
679+
),
680+
VLANGroup(
681+
name='VLAN Group 2',
682+
slug='vlan-group-2',
683+
scope=sites[1],
684+
scope_type=ContentType.objects.get_for_model(Site),
685+
),
686+
))
687+
vlan = VLAN(
688+
name='VLAN 1',
689+
vid=1,
690+
group=vlangroups[0],
691+
site=sites[0],
692+
)
693+
694+
# VLAN Group 1 and 2 should be valid
695+
vlan.full_clean()
696+
vlan.group = vlangroups[1]
697+
vlan.full_clean()
698+
vlan.group = vlangroups[2]
699+
with self.assertRaises(ValidationError):
700+
vlan.full_clean()

0 commit comments

Comments
 (0)