mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 08:38:16 -06:00
Fix logic for upper range boundaries
This commit is contained in:
parent
f6c2396a30
commit
c1a0eb8b37
@ -10,7 +10,9 @@ 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 = [NumericRange(group.min_vid, group.max_vid)]
|
group.vlan_id_ranges = [
|
||||||
|
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.vlan_id_ranges:
|
||||||
@ -31,7 +33,7 @@ class Migration(migrations.Migration):
|
|||||||
name='vlan_id_ranges',
|
name='vlan_id_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_vland_id_ranges,
|
default=ipam.models.vlans.default_vlan_id_ranges,
|
||||||
size=None
|
size=None
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -21,7 +21,7 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def default_vland_id_ranges():
|
def default_vlan_id_ranges():
|
||||||
return [
|
return [
|
||||||
NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]')
|
NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]')
|
||||||
]
|
]
|
||||||
@ -57,7 +57,7 @@ class VLANGroup(OrganizationalModel):
|
|||||||
vlan_id_ranges = ArrayField(
|
vlan_id_ranges = ArrayField(
|
||||||
IntegerRangeField(),
|
IntegerRangeField(),
|
||||||
verbose_name=_('VLAN ID ranges'),
|
verbose_name=_('VLAN ID ranges'),
|
||||||
default=default_vland_id_ranges
|
default=default_vlan_id_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
|
||||||
@ -120,7 +120,7 @@ class VLANGroup(OrganizationalModel):
|
|||||||
"""
|
"""
|
||||||
available_vlans = {}
|
available_vlans = {}
|
||||||
for vlan_range in self.vlan_id_ranges:
|
for vlan_range in self.vlan_id_ranges:
|
||||||
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper + 1)}
|
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))
|
||||||
|
|
||||||
return sorted(available_vlans)
|
return sorted(available_vlans)
|
||||||
|
@ -9,6 +9,7 @@ from utilities.querysets import RestrictedQuerySet
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'ASNRangeQuerySet',
|
'ASNRangeQuerySet',
|
||||||
'PrefixQuerySet',
|
'PrefixQuerySet',
|
||||||
|
'VLANGroupQuerySet',
|
||||||
'VLANQuerySet',
|
'VLANQuerySet',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ class IntegerRangeSerializer(serializers.Serializer):
|
|||||||
if type(data[0]) is not int or type(data[1]) is not int:
|
if type(data[0]) is not int or type(data[1]) is not int:
|
||||||
raise ValidationError(_("Range boundaries must be defined as integers."))
|
raise ValidationError(_("Range boundaries must be defined as integers."))
|
||||||
|
|
||||||
return NumericRange(data[0], data[1])
|
return NumericRange(data[0], data[1], bounds='[]')
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
return instance.lower, instance.upper
|
return instance.lower, instance.upper - 1
|
||||||
|
@ -138,27 +138,25 @@ def ranges_to_string(ranges):
|
|||||||
"""
|
"""
|
||||||
Generate a human-friendly string from a set of ranges. Intended for use with ArrayField.
|
Generate a human-friendly string from a set of ranges. Intended for use with ArrayField.
|
||||||
For example:
|
For example:
|
||||||
[Range(1, 100), Range(200, 300)] => "1-100, 200-300"
|
[[1, 100)], [200, 300)] => "1-99,200-299"
|
||||||
"""
|
"""
|
||||||
if not ranges:
|
if not ranges:
|
||||||
return ''
|
return ''
|
||||||
return ', '.join([f"{r.lower}-{r.upper}" for r in ranges])
|
return ','.join([f"{r.lower}-{r.upper - 1}" for r in ranges])
|
||||||
|
|
||||||
|
|
||||||
def string_to_range_array(value):
|
def string_to_range_array(value):
|
||||||
"""
|
"""
|
||||||
Given a string in the format "1-100, 200-300" create an array of ranges. Intended for use with ArrayField.
|
Given a string in the format "1-100, 200-300" create an array of ranges. Intended for use with ArrayField.
|
||||||
For example:
|
For example:
|
||||||
"1-100, 200-300" => [1-100, 200-300]
|
"1-99,200-299" => [NumericRange(1, 100), NumericRange(200, 300)]
|
||||||
"""
|
"""
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
ranges = value.split(",")
|
|
||||||
values = []
|
values = []
|
||||||
for dash_range in value.split(','):
|
for dash_range in value.split(','):
|
||||||
if '-' not in dash_range:
|
if '-' not in dash_range:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
lower, upper = dash_range.split('-')
|
lower, upper = dash_range.split('-')
|
||||||
values.append(NumericRange(int(lower), int(upper)))
|
values.append(NumericRange(int(lower), int(upper), bounds='[]'))
|
||||||
return values
|
return values
|
||||||
|
@ -2,7 +2,7 @@ import json
|
|||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField, RangeField
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db.models import ManyToManyField, ManyToManyRel, JSONField
|
from django.db.models import ManyToManyField, ManyToManyRel, JSONField
|
||||||
from django.forms.models import model_to_dict
|
from django.forms.models import model_to_dict
|
||||||
@ -12,6 +12,7 @@ from taggit.managers import TaggableManager
|
|||||||
|
|
||||||
from core.models import ObjectType
|
from core.models import ObjectType
|
||||||
from users.models import ObjectPermission
|
from users.models import ObjectPermission
|
||||||
|
from utilities.data import ranges_to_string
|
||||||
from utilities.object_types import object_type_identifier
|
from utilities.object_types import object_type_identifier
|
||||||
from utilities.permissions import resolve_permission_type
|
from utilities.permissions import resolve_permission_type
|
||||||
from .utils import DUMMY_CF_DATA, extract_form_failures
|
from .utils import DUMMY_CF_DATA, extract_form_failures
|
||||||
@ -139,6 +140,9 @@ class ModelTestCase(TestCase):
|
|||||||
if type(field.base_field) is ArrayField:
|
if type(field.base_field) is ArrayField:
|
||||||
# Handle nested arrays (e.g. choice sets)
|
# Handle nested arrays (e.g. choice sets)
|
||||||
model_dict[key] = '\n'.join([f'{k},{v}' for k, v in value])
|
model_dict[key] = '\n'.join([f'{k},{v}' for k, v in value])
|
||||||
|
elif issubclass(type(field.base_field), RangeField):
|
||||||
|
# Handle arrays of numeric ranges (e.g. VLANGroup VLAN ID ranges)
|
||||||
|
model_dict[key] = ranges_to_string(value)
|
||||||
else:
|
else:
|
||||||
model_dict[key] = ','.join([str(v) for v in value])
|
model_dict[key] = ','.join([str(v) for v in value])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user