Skip to content

Commit 9ae53fc

Browse files
committed
Fixes #20560: Fix VLAN disambiguation in prefix bulk import
1 parent da1e0f4 commit 9ae53fc

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

netbox/ipam/forms/bulk_import.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,6 @@ def __init__(self, data=None, *args, **kwargs):
230230
query |= Q(**{
231231
f"site__{self.fields['vlan_site'].to_field_name}": vlan_site
232232
})
233-
# Don't Forget to include VLANs without a site in the filter
234-
query |= Q(**{
235-
f"site__{self.fields['vlan_site'].to_field_name}__isnull": True
236-
})
237233

238234
if vlan_group:
239235
query &= Q(**{

netbox/ipam/tests/test_views.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,82 @@ def test_prefix_import_with_vlan_group(self):
564564
self.assertEqual(prefix.vlan.vid, 102)
565565
self.assertEqual(prefix.scope, site)
566566

567+
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
568+
def test_prefix_import_with_vlan_site_multiple_vlans_same_vid(self):
569+
"""
570+
Test import when multiple VLANs exist with the same vid but different sites.
571+
Ref: #20560
572+
"""
573+
site1 = Site.objects.get(name='Site 1')
574+
site2 = Site.objects.get(name='Site 2')
575+
576+
# Create VLANs with the same vid but different sites
577+
vlan1 = VLAN.objects.create(vid=1, name='VLAN1-Site1', site=site1)
578+
VLAN.objects.create(vid=1, name='VLAN1-Site2', site=site2) # Create ambiguity
579+
580+
# Import prefix with vlan_site specified
581+
IMPORT_DATA = f"""
582+
prefix: 10.11.0.0/22
583+
status: active
584+
scope_type: dcim.site
585+
scope_id: {site1.pk}
586+
vlan_site: {site1.name}
587+
vlan: 1
588+
description: LOC02-MGMT
589+
"""
590+
591+
# Add all required permissions to the test user
592+
self.add_permissions('ipam.view_prefix', 'ipam.add_prefix')
593+
594+
form_data = {
595+
'data': IMPORT_DATA,
596+
'format': 'yaml'
597+
}
598+
response = self.client.post(reverse('ipam:prefix_bulk_import'), data=form_data, follow=True)
599+
self.assertHttpStatus(response, 200)
600+
601+
# Verify the prefix was created with the correct VLAN
602+
prefix = Prefix.objects.get(prefix='10.11.0.0/22')
603+
self.assertEqual(prefix.vlan, vlan1)
604+
605+
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
606+
def test_prefix_import_with_vlan_site_and_global_vlan(self):
607+
"""
608+
Test import when a global VLAN (no site) and site-specific VLAN exist with same vid.
609+
When vlan_site is specified, should prefer the site-specific VLAN.
610+
Ref: #20560
611+
"""
612+
site1 = Site.objects.get(name='Site 1')
613+
614+
# Create a global VLAN (no site) and a site-specific VLAN with the same vid
615+
VLAN.objects.create(vid=10, name='VLAN10-Global', site=None) # Create ambiguity
616+
vlan_site = VLAN.objects.create(vid=10, name='VLAN10-Site1', site=site1)
617+
618+
# Import prefix with vlan_site specified
619+
IMPORT_DATA = f"""
620+
prefix: 10.12.0.0/22
621+
status: active
622+
scope_type: dcim.site
623+
scope_id: {site1.pk}
624+
vlan_site: {site1.name}
625+
vlan: 10
626+
description: Test Site-Specific VLAN
627+
"""
628+
629+
# Add all required permissions to the test user
630+
self.add_permissions('ipam.view_prefix', 'ipam.add_prefix')
631+
632+
form_data = {
633+
'data': IMPORT_DATA,
634+
'format': 'yaml'
635+
}
636+
response = self.client.post(reverse('ipam:prefix_bulk_import'), data=form_data, follow=True)
637+
self.assertHttpStatus(response, 200)
638+
639+
# Verify the prefix was created with the site-specific VLAN (not the global one)
640+
prefix = Prefix.objects.get(prefix='10.12.0.0/22')
641+
self.assertEqual(prefix.vlan, vlan_site)
642+
567643

568644
class IPRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
569645
model = IPRange

0 commit comments

Comments
 (0)