diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index 47d2d6607..fa389e904 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -11,6 +11,7 @@ from ipam.choices import * from ipam.constants import * from ipam.querysets import VLANQuerySet, VLANGroupQuerySet from netbox.models import OrganizationalModel, PrimaryModel +from utilities.data import check_ranges_overlap from virtualization.models import VMInterface __all__ = ( @@ -89,10 +90,14 @@ class VLANGroup(OrganizationalModel): if self.scope_id and not self.scope_type: raise ValidationError(_("Cannot set scope_id without scope_type.")) + # Validate vlan ranges + if check_ranges_overlap(self.vlan_id_ranges): + raise ValidationError(_("Ranges cannot overlap.")) + def save(self, *args, **kwargs): self._total_vlan_ids = 0 for vlan_range in self.vlan_id_ranges: - self._total_vlan_ids += int(vlan_range.upper) - int(vlan_range.lower) + 1 + self._total_vlan_ids += vlan_range.upper - vlan_range.lower + 1 super().save(*args, **kwargs) diff --git a/netbox/utilities/data.py b/netbox/utilities/data.py index 62eb68854..cdde68a5f 100644 --- a/netbox/utilities/data.py +++ b/netbox/utilities/data.py @@ -4,6 +4,7 @@ from itertools import count, groupby __all__ = ( 'array_to_ranges', 'array_to_string', + 'check_ranges_overlap', 'deepmerge', 'drange', 'flatten_dict', @@ -113,3 +114,18 @@ def drange(start, end, step=decimal.Decimal(1)): while start > end: yield start start += step + + +def check_ranges_overlap(ranges): + """ + Check if array of ranges overlap + """ + + # sort the ranges in increasing order + ranges.sort(key=lambda x: x.lower) + + for i in range(1, len(ranges)): + if (ranges[i - 1].upper > ranges[i].lower): + return True + + return False diff --git a/netbox/utilities/forms/fields/array.py b/netbox/utilities/forms/fields/array.py index 197588006..447ace9d2 100644 --- a/netbox/utilities/forms/fields/array.py +++ b/netbox/utilities/forms/fields/array.py @@ -52,5 +52,5 @@ class NumericRangeArrayField(forms.CharField): values = [] for dash_range in value.split(','): lower, upper = dash_range.split('-') - values.append(NumericRange(lower, upper)) + values.append(NumericRange(int(lower), int(upper))) return values