Rename vlan_id_ranges to vid_ranges

This commit is contained in:
Jeremy Stretch 2024-07-15 16:52:53 -04:00
parent 77cb678667
commit 9f56745cab
15 changed files with 51 additions and 46 deletions

View File

@ -32,7 +32,7 @@ class VLANGroupSerializer(NetBoxModelSerializer):
) )
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
scope = serializers.SerializerMethodField(read_only=True) scope = serializers.SerializerMethodField(read_only=True)
vlan_id_ranges = IntegerRangeSerializer(many=True, required=False) vid_ranges = IntegerRangeSerializer(many=True, required=False)
utilization = serializers.CharField(read_only=True) utilization = serializers.CharField(read_only=True)
# Related object counts # Related object counts
@ -41,7 +41,7 @@ class VLANGroupSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'vlan_id_ranges', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'vid_ranges',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization' 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization'
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count')

View File

@ -943,7 +943,7 @@ class VLANGroupFilterSet(OrganizationalModelFilterSet):
# TODO: See if this can be optimized without compromising queryset integrity # TODO: See if this can be optimized without compromising queryset integrity
# Expand VLAN ID ranges to query by integer # Expand VLAN ID ranges to query by integer
groups = VLANGroup.objects.raw( groups = VLANGroup.objects.raw(
f'SELECT id FROM {table_name}, unnest(vlan_id_ranges) vid_range WHERE %s <@ vid_range', f'SELECT id FROM {table_name}, unnest(vid_ranges) vid_range WHERE %s <@ vid_range',
params=(value,) params=(value,)
) )
return queryset.filter( return queryset.filter(

View File

@ -472,14 +472,14 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
'group_id': '$clustergroup', 'group_id': '$clustergroup',
} }
) )
vlan_id_ranges = NumericRangeArrayField( vid_ranges = NumericRangeArrayField(
label=_('VLAN ID ranges'), label=_('VLAN ID ranges'),
required=False required=False
) )
model = VLANGroup model = VLANGroup
fieldsets = ( fieldsets = (
FieldSet('site', 'vlan_id_ranges', 'description'), FieldSet('site', 'vid_ranges', 'description'),
FieldSet( FieldSet(
'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster', name=_('Scope') 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster', name=_('Scope')
), ),

View File

@ -412,13 +412,13 @@ class VLANGroupImportForm(NetBoxModelImportForm):
required=False, required=False,
label=_('Scope type (app & model)') label=_('Scope type (app & model)')
) )
vlan_id_ranges = NumericRangeArrayField( vid_ranges = NumericRangeArrayField(
required=False required=False
) )
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = ('name', 'slug', 'scope_type', 'scope_id', 'vlan_id_ranges', 'description', 'tags') fields = ('name', 'slug', 'scope_type', 'scope_id', 'vid_ranges', 'description', 'tags')
labels = { labels = {
'scope_id': 'Scope ID', 'scope_id': 'Scope ID',
} }

View File

@ -633,13 +633,13 @@ class VLANGroupForm(NetBoxModelForm):
} }
) )
slug = SlugField() slug = SlugField()
vlan_id_ranges = NumericRangeArrayField( vid_ranges = NumericRangeArrayField(
label=_('VLAN IDs') label=_('VLAN IDs')
) )
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'description', 'tags', name=_('VLAN Group')), FieldSet('name', 'slug', 'description', 'tags', name=_('VLAN Group')),
FieldSet('vlan_id_ranges', name=_('Child VLANs')), FieldSet('vid_ranges', name=_('Child VLANs')),
FieldSet( FieldSet(
'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster', 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster',
name=_('Scope') name=_('Scope')
@ -650,7 +650,7 @@ class VLANGroupForm(NetBoxModelForm):
model = VLANGroup model = VLANGroup
fields = [ fields = [
'name', 'slug', 'description', 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'name', 'slug', 'description', 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack',
'clustergroup', 'cluster', 'vlan_id_ranges', 'tags', 'clustergroup', 'cluster', 'vid_ranges', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -251,7 +251,7 @@ class VLANType(NetBoxObjectType):
class VLANGroupType(OrganizationalObjectType): class VLANGroupType(OrganizationalObjectType):
vlans: List[VLANType] vlans: List[VLANType]
vlan_id_ranges: List[str] vid_ranges: List[str]
@strawberry_django.field @strawberry_django.field
def scope(self) -> Annotated[Union[ def scope(self) -> Annotated[Union[

View File

@ -10,12 +10,12 @@ def move_min_max(apps, schema_editor):
VLANGroup = apps.get_model('ipam', 'VLANGroup') VLANGroup = apps.get_model('ipam', 'VLANGroup')
for group in VLANGroup.objects.all(): for group in VLANGroup.objects.all():
if group.min_vid or group.max_vid: if group.min_vid or group.max_vid:
group.vlan_id_ranges = [ group.vid_ranges = [
NumericRange(group.min_vid, group.max_vid, bounds='[]') NumericRange(group.min_vid, group.max_vid, bounds='[]')
] ]
group._total_vlan_ids = 0 group._total_vlan_ids = 0
for vlan_range in group.vlan_id_ranges: for vlan_range in group.vid_ranges:
group._total_vlan_ids += int(vlan_range.upper) - int(vlan_range.lower) + 1 group._total_vlan_ids += int(vlan_range.upper) - int(vlan_range.lower) + 1
group.save() group.save()
@ -30,10 +30,10 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='vlangroup', model_name='vlangroup',
name='vlan_id_ranges', name='vid_ranges',
field=django.contrib.postgres.fields.ArrayField( field=django.contrib.postgres.fields.ArrayField(
base_field=django.contrib.postgres.fields.ranges.IntegerRangeField(), base_field=django.contrib.postgres.fields.ranges.IntegerRangeField(),
default=ipam.models.vlans.default_vlan_id_ranges, default=ipam.models.vlans.default_vid_ranges,
size=None size=None
), ),
), ),

View File

@ -21,7 +21,7 @@ __all__ = (
) )
def default_vlan_id_ranges(): def default_vid_ranges():
return [ return [
NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]') NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]')
] ]
@ -54,10 +54,10 @@ class VLANGroup(OrganizationalModel):
ct_field='scope_type', ct_field='scope_type',
fk_field='scope_id' fk_field='scope_id'
) )
vlan_id_ranges = ArrayField( vid_ranges = ArrayField(
IntegerRangeField(), IntegerRangeField(),
verbose_name=_('VLAN ID ranges'), verbose_name=_('VLAN ID ranges'),
default=default_vlan_id_ranges default=default_vid_ranges
) )
_total_vlan_ids = models.PositiveBigIntegerField( _total_vlan_ids = models.PositiveBigIntegerField(
default=VLAN_VID_MAX - VLAN_VID_MIN + 1 default=VLAN_VID_MAX - VLAN_VID_MIN + 1
@ -96,20 +96,20 @@ class VLANGroup(OrganizationalModel):
raise ValidationError(_("Cannot set scope_id without scope_type.")) raise ValidationError(_("Cannot set scope_id without scope_type."))
# Validate vlan ranges # Validate vlan ranges
if self.vlan_id_ranges and check_ranges_overlap(self.vlan_id_ranges): if self.vid_ranges and check_ranges_overlap(self.vid_ranges):
raise ValidationError({'vlan_id_ranges': _("Ranges cannot overlap.")}) raise ValidationError({'vid_ranges': _("Ranges cannot overlap.")})
for vid_range in self.vlan_id_ranges: for vid_range in self.vid_ranges:
if vid_range.lower >= vid_range.upper: if vid_range.lower >= vid_range.upper:
raise ValidationError({ raise ValidationError({
'vlan_id_ranges': _( 'vid_ranges': _(
"Maximum child VID must be greater than or equal to minimum child VID ({value})" "Maximum child VID must be greater than or equal to minimum child VID ({value})"
).format(value=vid_range) ).format(value=vid_range)
}) })
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self._total_vlan_ids = 0 self._total_vlan_ids = 0
for vid_range in self.vlan_id_ranges: for vid_range in self.vid_ranges:
self._total_vlan_ids += vid_range.upper - vid_range.lower + 1 self._total_vlan_ids += vid_range.upper - vid_range.lower + 1
super().save(*args, **kwargs) super().save(*args, **kwargs)
@ -119,7 +119,7 @@ class VLANGroup(OrganizationalModel):
Return all available VLANs within this group. Return all available VLANs within this group.
""" """
available_vlans = {} available_vlans = {}
for vlan_range in self.vlan_id_ranges: for vlan_range in self.vid_ranges:
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper)} available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper)}
available_vlans -= set(VLAN.objects.filter(group=self).values_list('vid', flat=True)) available_vlans -= set(VLAN.objects.filter(group=self).values_list('vid', flat=True))
@ -141,8 +141,8 @@ class VLANGroup(OrganizationalModel):
return VLAN.objects.filter(group=self).order_by('vid') return VLAN.objects.filter(group=self).order_by('vid')
@property @property
def vlan_ranges(self): def vid_ranges_list(self):
return ranges_to_string(self.vlan_id_ranges) return ranges_to_string(self.vid_ranges)
class VLAN(PrimaryModel): class VLAN(PrimaryModel):
@ -250,9 +250,9 @@ class VLAN(PrimaryModel):
) )
# Validate group min/max VIDs # Validate group min/max VIDs
if self.group and self.group.vlan_id_ranges: if self.group and self.group.vid_ranges:
in_bounds = False in_bounds = False
for vid_range in self.group.vlan_id_ranges: for vid_range in self.group.vid_ranges:
if vid_range.lower <= self.vid <= vid_range.upper: if vid_range.lower <= self.vid <= vid_range.upper:
in_bounds = True in_bounds = True
@ -260,7 +260,7 @@ class VLAN(PrimaryModel):
raise ValidationError({ raise ValidationError({
'vid': _( 'vid': _(
"VID must be in ranges {ranges} for VLANs in group {group}" "VID must be in ranges {ranges} for VLANs in group {group}"
).format(ranges=ranges_to_string(self.group.vlan_id_ranges), group=self.group) ).format(ranges=ranges_to_string(self.group.vid_ranges), group=self.group)
}) })
def get_status_color(self): def get_status_color(self):

View File

@ -72,8 +72,8 @@ class VLANGroupTable(NetBoxTable):
linkify=True, linkify=True,
orderable=False orderable=False
) )
vlan_ranges = tables.Column( vid_ranges_list = tables.Column(
verbose_name=_('VLAN Ranges'), verbose_name=_('VID Ranges'),
orderable=False orderable=False
) )
vlan_count = columns.LinkedCountColumn( vlan_count = columns.LinkedCountColumn(
@ -95,7 +95,7 @@ class VLANGroupTable(NetBoxTable):
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = VLANGroup model = VLANGroup
fields = ( fields = (
'pk', 'id', 'name', 'scope_type', 'scope', 'vlan_ranges', 'vlan_count', 'slug', 'description', 'pk', 'id', 'name', 'scope_type', 'scope', 'vid_ranges_list', 'vlan_count', 'slug', 'description',
'tags', 'created', 'last_updated', 'actions', 'utilization', 'tags', 'created', 'last_updated', 'actions', 'utilization',
) )
default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'utilization', 'description') default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'utilization', 'description')

View File

@ -883,7 +883,7 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
vlangroup = VLANGroup.objects.create( vlangroup = VLANGroup.objects.create(
name='VLAN Group X', name='VLAN Group X',
slug='vlan-group-x', slug='vlan-group-x',
vlan_id_ranges=string_to_range_array(f"{MIN_VID}-{MAX_VID}") vid_ranges=string_to_range_array(f"{MIN_VID}-{MAX_VID}")
) )
# Create a set of VLANs within the group # Create a set of VLANs within the group

View File

@ -1466,7 +1466,7 @@ class FHRPGroupAssignmentTestCase(TestCase, ChangeLoggedFilterSetTests):
class VLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests): class VLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VLANGroup.objects.all() queryset = VLANGroup.objects.all()
filterset = VLANGroupFilterSet filterset = VLANGroupFilterSet
ignore_fields = ('vlan_id_ranges',) ignore_fields = ('vid_ranges',)
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
@ -1499,46 +1499,46 @@ class VLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
VLANGroup( VLANGroup(
name='VLAN Group 1', name='VLAN Group 1',
slug='vlan-group-1', slug='vlan-group-1',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(100, 200)], vid_ranges=[NumericRange(1, 11), NumericRange(100, 200)],
scope=region, scope=region,
description='foobar1' description='foobar1'
), ),
VLANGroup( VLANGroup(
name='VLAN Group 2', name='VLAN Group 2',
slug='vlan-group-2', slug='vlan-group-2',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(200, 300)], vid_ranges=[NumericRange(1, 11), NumericRange(200, 300)],
scope=sitegroup, scope=sitegroup,
description='foobar2' description='foobar2'
), ),
VLANGroup( VLANGroup(
name='VLAN Group 3', name='VLAN Group 3',
slug='vlan-group-3', slug='vlan-group-3',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(300, 400)], vid_ranges=[NumericRange(1, 11), NumericRange(300, 400)],
scope=site, scope=site,
description='foobar3' description='foobar3'
), ),
VLANGroup( VLANGroup(
name='VLAN Group 4', name='VLAN Group 4',
slug='vlan-group-4', slug='vlan-group-4',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(400, 500)], vid_ranges=[NumericRange(1, 11), NumericRange(400, 500)],
scope=location scope=location
), ),
VLANGroup( VLANGroup(
name='VLAN Group 5', name='VLAN Group 5',
slug='vlan-group-5', slug='vlan-group-5',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(500, 600)], vid_ranges=[NumericRange(1, 11), NumericRange(500, 600)],
scope=rack scope=rack
), ),
VLANGroup( VLANGroup(
name='VLAN Group 6', name='VLAN Group 6',
slug='vlan-group-6', slug='vlan-group-6',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(600, 700)], vid_ranges=[NumericRange(1, 11), NumericRange(600, 700)],
scope=clustergroup scope=clustergroup
), ),
VLANGroup( VLANGroup(
name='VLAN Group 7', name='VLAN Group 7',
slug='vlan-group-7', slug='vlan-group-7',
vlan_id_ranges=[NumericRange(1, 11), NumericRange(700, 800)], vid_ranges=[NumericRange(1, 11), NumericRange(700, 800)],
scope=cluster scope=cluster
), ),
VLANGroup( VLANGroup(

View File

@ -510,7 +510,7 @@ class TestVLANGroup(TestCase):
vlangroup = VLANGroup.objects.create( vlangroup = VLANGroup.objects.create(
name='VLAN Group 1', name='VLAN Group 1',
slug='vlan-group-1', slug='vlan-group-1',
vlan_id_ranges=string_to_range_array('100-199'), vid_ranges=string_to_range_array('100-199'),
) )
VLAN.objects.bulk_create(( VLAN.objects.bulk_create((
VLAN(name='VLAN 100', vid=100, group=vlangroup), VLAN(name='VLAN 100', vid=100, group=vlangroup),

View File

@ -765,7 +765,7 @@ class VLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
'name': 'VLAN Group X', 'name': 'VLAN Group X',
'slug': 'vlan-group-x', 'slug': 'vlan-group-x',
'description': 'A new VLAN group', 'description': 'A new VLAN group',
'vlan_id_ranges': '100-199,300-399', 'vid_ranges': '100-199,300-399',
'tags': [t.pk for t in tags], 'tags': [t.pk for t in tags],
} }

View File

@ -136,8 +136,8 @@ def add_available_vlans(vlans, vlan_group=None):
Create fake records for all gaps between used VLANs Create fake records for all gaps between used VLANs
""" """
new_vlans = [] new_vlans = []
if vlan_group and vlan_group.vlan_id_ranges: if vlan_group and vlan_group.vid_ranges:
for vlan_range in vlan_group.vlan_id_ranges: for vlan_range in vlan_group.vid_ranges:
new_vlans.extend(available_vlans_from_range(vlans, vlan_group, vlan_range)) new_vlans.extend(available_vlans_from_range(vlans, vlan_group, vlan_range))
else: else:
new_vlans = available_vlans_from_range(vlans, vlan_group, vlan_range) new_vlans = available_vlans_from_range(vlans, vlan_group, vlan_range)

View File

@ -142,7 +142,12 @@ def ranges_to_string(ranges):
""" """
if not ranges: if not ranges:
return '' return ''
return ','.join([f"{r.lower}-{r.upper - 1}" for r in ranges]) output = []
for r in ranges:
lower = r.lower if r.lower_inc else r.lower + 1
upper = r.upper if r.upper_inc else r.upper - 1
output.append(f'{lower}-{upper}')
return ','.join(output)
def string_to_range_array(value): def string_to_range_array(value):