瀏覽代碼

fix(ipam): Correct VLAN ID range calculation logic

Adjust VLAN ID range calculation to use half‑open intervals for
consistency. Add a test to validate `_total_vlan_ids`.

Fixes #20610
Martin Hauser 3 月之前
父節點
當前提交
afc62b6ffd

+ 27 - 0
netbox/ipam/migrations/0083_vlangroup_populate_total_vlan_ids.py

@@ -0,0 +1,27 @@
+from django.db import migrations
+
+
+def populate_vlangroup_total_vlan_ids(apps, schema_editor):
+    VLANGroup = apps.get_model('ipam', 'VLANGroup')
+    db_alias = schema_editor.connection.alias
+
+    vlan_groups = VLANGroup.objects.using(db_alias).only('id', 'vid_ranges')
+    for group in vlan_groups:
+        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
+        group._total_vlan_ids = total_vlan_ids
+    VLANGroup.objects.using(db_alias).bulk_update(vlan_groups, ['_total_vlan_ids'], batch_size=100)
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ('ipam', '0082_add_prefix_network_containment_indexes'),
+    ]
+
+    operations = [
+        migrations.RunPython(populate_vlangroup_total_vlan_ids, migrations.RunPython.noop),
+    ]

+ 2 - 1
netbox/ipam/models/vlans.py

@@ -132,7 +132,8 @@ class VLANGroup(OrganizationalModel):
     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)
 

+ 4 - 0
netbox/ipam/tests/test_models.py

@@ -661,6 +661,10 @@ class TestVLANGroup(TestCase):
         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):