Skip to content

Commit deb6b1e

Browse files
committed
Allow bridge when importing interface templates
Adding the field to the InterfaceTemplateImportForm is enough. The two clean_*_type methods are for properly dynamically restricting what values can be selected.
1 parent 9679594 commit deb6b1e

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

netbox/dcim/forms/object_import.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ class InterfaceTemplateImportForm(forms.ModelForm):
8484
label=_('Type'),
8585
choices=InterfaceTypeChoices.CHOICES
8686
)
87+
bridge = forms.ModelChoiceField(
88+
label=_('Bridge'),
89+
queryset=InterfaceTemplate.objects.all(),
90+
to_field_name='name',
91+
required=False
92+
)
8793
poe_mode = forms.ChoiceField(
8894
choices=InterfacePoEModeChoices,
8995
required=False,
@@ -103,10 +109,24 @@ class InterfaceTemplateImportForm(forms.ModelForm):
103109
class Meta:
104110
model = InterfaceTemplate
105111
fields = [
106-
'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'poe_mode',
107-
'poe_type', 'rf_role'
112+
'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge',
113+
'poe_mode', 'poe_type', 'rf_role'
108114
]
109115

116+
def clean_device_type(self):
117+
if device_type := self.cleaned_data['device_type']:
118+
bridge = self.fields['bridge']
119+
bridge.queryset = bridge.queryset.filter(device_type=device_type)
120+
121+
return device_type
122+
123+
def clean_module_type(self):
124+
if module_type := self.cleaned_data['module_type']:
125+
bridge = self.fields['bridge']
126+
bridge.queryset = bridge.queryset.filter(module_type=module_type)
127+
128+
return module_type
129+
110130

111131
class FrontPortTemplateImportForm(forms.ModelForm):
112132
type = forms.ChoiceField(

netbox/dcim/tests/test_views.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,55 @@ def test_import_nodict(self):
10571057
self.assertHttpStatus(response, 200)
10581058
self.assertContains(response, "console-ports[0]: Must be a dictionary.")
10591059

1060+
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
1061+
def test_import_interfacebridge(self):
1062+
IMPORT_DATA = """
1063+
manufacturer: Manufacturer 1
1064+
model: TEST-4000
1065+
slug: test-4000
1066+
u_height: 1
1067+
interfaces:
1068+
- name: Bridge
1069+
type: 1000base-t
1070+
- name: Bridge Interface 1
1071+
type: 1000base-t
1072+
bridge: Bridge
1073+
"""
1074+
1075+
# Add all required permissions to the test user
1076+
self.add_permissions(
1077+
'dcim.view_devicetype',
1078+
'dcim.add_devicetype',
1079+
'dcim.add_consoleporttemplate',
1080+
'dcim.add_consoleserverporttemplate',
1081+
'dcim.add_powerporttemplate',
1082+
'dcim.add_poweroutlettemplate',
1083+
'dcim.add_interfacetemplate',
1084+
'dcim.add_frontporttemplate',
1085+
'dcim.add_rearporttemplate',
1086+
'dcim.add_modulebaytemplate',
1087+
'dcim.add_devicebaytemplate',
1088+
'dcim.add_inventoryitemtemplate',
1089+
)
1090+
1091+
form_data = {
1092+
'data': IMPORT_DATA,
1093+
'format': 'yaml'
1094+
}
1095+
1096+
response = self.client.post(reverse('dcim:devicetype_bulk_import'), data=form_data, follow=True)
1097+
self.assertHttpStatus(response, 200)
1098+
self.assertContains(response, "Imported 1 device types")
1099+
1100+
device_type = DeviceType.objects.get(model='TEST-4000')
1101+
self.assertEqual(device_type.interfacetemplates.count(), 2)
1102+
1103+
interfaces = InterfaceTemplate.objects.all().order_by('id')
1104+
self.assertEqual(interfaces[0].name, 'Bridge')
1105+
self.assertIsNone(interfaces[0].bridge)
1106+
self.assertEqual(interfaces[1].name, 'Bridge Interface 1')
1107+
self.assertEqual(interfaces[1].bridge.name, "Bridge")
1108+
10601109
def test_export_objects(self):
10611110
url = reverse('dcim:devicetype_list')
10621111
self.add_permissions('dcim.view_devicetype')

0 commit comments

Comments
 (0)