diff --git a/netbox/ipam/migrations/0083_vlangroup_populate_total_vlan_ids.py b/netbox/ipam/migrations/0083_vlangroup_populate_total_vlan_ids.py new file mode 100644 index 00000000000..cdf25a17bd5 --- /dev/null +++ b/netbox/ipam/migrations/0083_vlangroup_populate_total_vlan_ids.py @@ -0,0 +1,26 @@ +from django.db import migrations + + +def populate_vlangroup_total_vlan_ids(apps, schema_editor): + VLANGroup = apps.get_model('ipam', 'VLANGroup') + db = schema_editor.connection.alias + + qs = VLANGroup.objects.using(db).only('id', 'vid_ranges') + for group in qs.iterator(): + total_vlan_ids = 0 + if group.vid_ranges: + for r in group.vid_ranges: + # Half-open [lo, hi): length is (hi - lo). + if r is not None and r.lower is not None and r.upper is not None: + total_vlan_ids += r.upper - r.lower + VLANGroup.objects.using(db).filter(pk=group.pk).update(_total_vlan_ids=total_vlan_ids) + + +class Migration(migrations.Migration): + dependencies = [ + ('ipam', '0082_add_prefix_network_containment_indexes'), + ] + + operations = [ + migrations.RunPython(populate_vlangroup_total_vlan_ids, migrations.RunPython.noop), + ] diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index efa1ed39ed3..030633330a4 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -132,7 +132,8 @@ def clean(self): def save(self, *args, **kwargs): self._total_vlan_ids = 0 for vid_range in self.vid_ranges: - self._total_vlan_ids += vid_range.upper - vid_range.lower + 1 + # VID range is inclusive on lower-bound, exclusive on upper-bound + self._total_vlan_ids += vid_range.upper - vid_range.lower super().save(*args, **kwargs) diff --git a/netbox/ipam/tests/test_models.py b/netbox/ipam/tests/test_models.py index 656f62d87c2..c93a47d21fe 100644 --- a/netbox/ipam/tests/test_models.py +++ b/netbox/ipam/tests/test_models.py @@ -661,6 +661,10 @@ def test_overlapping_vlan(self): vlangroup.full_clean() vlangroup.save() + def test_total_vlan_ids(self): + vlangroup = VLANGroup.objects.first() + self.assertEqual(vlangroup._total_vlan_ids, 100) + class TestVLAN(TestCase):