1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

822 bulk import of device components (#3711)

Closes #822: CSV import for device components

* Implement CSV import for netbox-community#822

* Comment out default_return_url until there is a proper target

* Fix the default value of `enabled` when not included in the import

* rear_port is definitely required here

* Power Ports don't have a type (yet)

* Add import for console-ports and console-server-ports

* Add import for device-bays
This commit is contained in:
Sander Steffann
2019-12-05 21:36:11 +01:00
committed by Jeremy Stretch
parent f3a41df395
commit adb25fd7d7
23 changed files with 523 additions and 41 deletions

View File

@ -25,7 +25,7 @@ from utilities.forms import (
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, JSONField,
SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES,
)
from virtualization.models import Cluster, ClusterGroup
from virtualization.models import Cluster, ClusterGroup, VirtualMachine
from .choices import *
from .constants import *
from .models import (
@ -2096,6 +2096,21 @@ class ConsolePortCreateForm(ComponentForm):
)
class ConsolePortCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
class Meta:
model = ConsolePort
fields = ConsolePort.csv_headers
#
# Console server ports
#
@ -2168,6 +2183,21 @@ class ConsoleServerPortBulkDisconnectForm(ConfirmationForm):
)
class ConsoleServerPortCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
class Meta:
model = ConsoleServerPort
fields = ConsoleServerPort.csv_headers
#
# Power ports
#
@ -2215,6 +2245,21 @@ class PowerPortCreateForm(ComponentForm):
)
class PowerPortCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
class Meta:
model = PowerPort
fields = PowerPort.csv_headers
#
# Power outlets
#
@ -2280,6 +2325,56 @@ class PowerOutletCreateForm(ComponentForm):
self.fields['power_port'].queryset = PowerPort.objects.filter(device=self.parent)
class PowerOutletCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
power_port = FlexibleModelChoiceField(
queryset=PowerPort.objects.all(),
required=False,
to_field_name='name',
help_text='Name or ID of Power Port',
error_messages={
'invalid_choice': 'Power Port not found.',
}
)
feed_leg = CSVChoiceField(
choices=POWERFEED_LEG_CHOICES,
required=False,
)
class Meta:
model = PowerOutlet
fields = PowerOutlet.csv_headers
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit PowerPort choices to those belonging to this device (or VC master)
if self.is_bound:
try:
device = self.fields['device'].to_python(self.data['device'])
except forms.ValidationError:
device = None
else:
try:
device = self.instance.device
except Device.DoesNotExist:
device = None
if device:
self.fields['power_port'].queryset = PowerPort.objects.filter(
device__in=[device, device.get_vc_master()]
)
else:
self.fields['power_port'].queryset = PowerPort.objects.none()
class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=PowerOutlet.objects.all(),
@ -2531,6 +2626,73 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
self.fields['tagged_vlans'].choices = vlan_choices
class InterfaceCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
required=False,
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
virtual_machine = FlexibleModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
to_field_name='name',
help_text='Name or ID of virtual machine',
error_messages={
'invalid_choice': 'Virtual machine not found.',
}
)
lag = FlexibleModelChoiceField(
queryset=Interface.objects.all(),
required=False,
to_field_name='name',
help_text='Name or ID of LAG interface',
error_messages={
'invalid_choice': 'LAG interface not found.',
}
)
type = CSVChoiceField(
choices=IFACE_TYPE_CHOICES,
)
mode = CSVChoiceField(
choices=IFACE_MODE_CHOICES,
required=False,
)
class Meta:
model = Interface
fields = Interface.csv_headers
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit LAG choices to interfaces belonging to this device (or VC master)
if self.is_bound:
try:
device = self.fields['device'].to_python(self.data['device'])
except forms.ValidationError:
device = None
else:
device = self.instance.device
if device:
self.fields['lag'].queryset = Interface.objects.filter(
device__in=[device, device.get_vc_master()], type=IFACE_TYPE_LAG
)
else:
self.fields['lag'].queryset = Interface.objects.none()
def clean_enabled(self):
# Make sure enabled is True when it's not included in the uploaded data
if 'enabled' not in self.data:
return True
else:
return self.cleaned_data['enabled']
class InterfaceBulkEditForm(InterfaceCommonForm, BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=Interface.objects.all(),
@ -2747,6 +2909,54 @@ class FrontPortCreateForm(ComponentForm):
}
class FrontPortCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
rear_port = FlexibleModelChoiceField(
queryset=RearPort.objects.all(),
to_field_name='name',
help_text='Name or ID of Rear Port',
error_messages={
'invalid_choice': 'Rear Port not found.',
}
)
type = CSVChoiceField(
choices=PORT_TYPE_CHOICES,
)
class Meta:
model = FrontPort
fields = FrontPort.csv_headers
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit RearPort choices to those belonging to this device (or VC master)
if self.is_bound:
try:
device = self.fields['device'].to_python(self.data['device'])
except forms.ValidationError:
device = None
else:
try:
device = self.instance.device
except Device.DoesNotExist:
device = None
if device:
self.fields['rear_port'].queryset = RearPort.objects.filter(
device__in=[device, device.get_vc_master()]
)
else:
self.fields['rear_port'].queryset = RearPort.objects.none()
class FrontPortBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=FrontPort.objects.all(),
@ -2821,6 +3031,24 @@ class RearPortCreateForm(ComponentForm):
)
class RearPortCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
type = CSVChoiceField(
choices=PORT_TYPE_CHOICES,
)
class Meta:
model = RearPort
fields = RearPort.csv_headers
class RearPortBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=RearPort.objects.all(),
@ -3389,6 +3617,56 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
).exclude(pk=device_bay.device.pk)
class DeviceBayCSVForm(forms.ModelForm):
device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Device not found.',
}
)
installed_device = FlexibleModelChoiceField(
queryset=Device.objects.all(),
required=False,
to_field_name='name',
help_text='Name or ID of device',
error_messages={
'invalid_choice': 'Child device not found.',
}
)
class Meta:
model = DeviceBay
fields = DeviceBay.csv_headers
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit installed device choices to devices of the correct type and location
if self.is_bound:
try:
device = self.fields['device'].to_python(self.data['device'])
except forms.ValidationError:
device = None
else:
try:
device = self.instance.device
except Device.DoesNotExist:
device = None
if device:
self.fields['installed_device'].queryset = Device.objects.filter(
site=device.site,
rack=device.rack,
parent_bay__isnull=True,
device_type__u_height=0,
device_type__subdevice_role=SUBDEVICE_ROLE_CHILD
).exclude(pk=device.pk)
else:
self.fields['installed_device'].queryset = Interface.objects.none()
class DeviceBayBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(
queryset=DeviceBay.objects.all(),