Fixes #11991 - Add vdcs to InterfaceImportForm and InterfaceBulkEditForm (#11996)

* Add vdcs to InterfaceImportForm and InterfaceBulkEditForm

* Filter vdcs queryset by device when bulk importing interfaces
This commit is contained in:
kkthxbye 2023-03-28 19:20:23 +02:00 committed by Jeremy Stretch
parent 9946ae2981
commit 2840f9d71d
2 changed files with 27 additions and 4 deletions

View File

@ -1175,6 +1175,14 @@ class InterfaceBulkEditForm(
}, },
label=_('LAG') label=_('LAG')
) )
vdcs = DynamicModelMultipleChoiceField(
queryset=VirtualDeviceContext.objects.all(),
required=False,
label='Virtual Device Contexts',
query_params={
'device_id': '$device',
}
)
speed = forms.IntegerField( speed = forms.IntegerField(
required=False, required=False,
widget=SelectSpeedWidget(), widget=SelectSpeedWidget(),
@ -1240,14 +1248,14 @@ class InterfaceBulkEditForm(
fieldsets = ( fieldsets = (
(None, ('module', 'type', 'label', 'speed', 'duplex', 'description')), (None, ('module', 'type', 'label', 'speed', 'duplex', 'description')),
('Addressing', ('vrf', 'mac_address', 'wwn')), ('Addressing', ('vrf', 'mac_address', 'wwn')),
('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), ('Operation', ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
('PoE', ('poe_mode', 'poe_type')), ('PoE', ('poe_mode', 'poe_type')),
('Related Interfaces', ('parent', 'bridge', 'lag')), ('Related Interfaces', ('parent', 'bridge', 'lag')),
('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')),
('Wireless', ('rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width')), ('Wireless', ('rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width')),
) )
nullable_fields = ( nullable_fields = (
'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'description', 'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'vdcs', 'mtu', 'description',
'poe_mode', 'poe_type', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'poe_mode', 'poe_type', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
'vlan_group', 'untagged_vlan', 'tagged_vlans', 'vrf', 'vlan_group', 'untagged_vlan', 'tagged_vlans', 'vrf',
) )

View File

@ -11,7 +11,9 @@ from dcim.models import *
from ipam.models import VRF from ipam.models import VRF
from netbox.forms import NetBoxModelImportForm from netbox.forms import NetBoxModelImportForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField from utilities.forms import (
CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField, CSVModelMultipleChoiceField
)
from virtualization.models import Cluster from virtualization.models import Cluster
from wireless.choices import WirelessRoleChoices from wireless.choices import WirelessRoleChoices
from .common import ModuleCommonForm from .common import ModuleCommonForm
@ -667,6 +669,12 @@ class InterfaceImportForm(NetBoxModelImportForm):
to_field_name='name', to_field_name='name',
help_text=_('Parent LAG interface') help_text=_('Parent LAG interface')
) )
vdcs = CSVModelMultipleChoiceField(
queryset=VirtualDeviceContext.objects.all(),
required=False,
to_field_name='name',
help_text='VDC names separated by commas, encased with double quotes (e.g. "vdc1, vdc2, vdc3")'
)
type = CSVChoiceField( type = CSVChoiceField(
choices=InterfaceTypeChoices, choices=InterfaceTypeChoices,
help_text=_('Physical medium') help_text=_('Physical medium')
@ -706,7 +714,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
model = Interface model = Interface
fields = ( fields = (
'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled', 'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled',
'mark_connected', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode', 'mark_connected', 'mac_address', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode',
'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags' 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags'
) )
@ -722,6 +730,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params) self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params)
self.fields['bridge'].queryset = self.fields['bridge'].queryset.filter(**params) self.fields['bridge'].queryset = self.fields['bridge'].queryset.filter(**params)
self.fields['lag'].queryset = self.fields['lag'].queryset.filter(**params) self.fields['lag'].queryset = self.fields['lag'].queryset.filter(**params)
self.fields['vdcs'].queryset = self.fields['vdcs'].queryset.filter(**params)
def clean_enabled(self): def clean_enabled(self):
# Make sure enabled is True when it's not included in the uploaded data # Make sure enabled is True when it's not included in the uploaded data
@ -730,6 +739,12 @@ class InterfaceImportForm(NetBoxModelImportForm):
else: else:
return self.cleaned_data['enabled'] return self.cleaned_data['enabled']
def clean_vdcs(self):
for vdc in self.cleaned_data['vdcs']:
if vdc.device != self.cleaned_data['device']:
raise forms.ValidationError(f"VDC {vdc} is not assigned to device {self.cleaned_data['device']}")
return self.cleaned_data['vdcs']
class FrontPortImportForm(NetBoxModelImportForm): class FrontPortImportForm(NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(