|
|
@@ -1,43 +1,21 @@
|
|
|
from django import forms
|
|
|
|
|
|
-from dcim.choices import *
|
|
|
-from dcim.constants import *
|
|
|
from dcim.models import *
|
|
|
-from extras.forms import CustomFieldModelForm, CustomFieldsMixin
|
|
|
+from extras.forms import CustomFieldModelForm
|
|
|
from extras.models import Tag
|
|
|
-from ipam.models import VLAN
|
|
|
from utilities.forms import (
|
|
|
- add_blank_choice, BootstrapMixin, ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
|
|
- ExpandableNameField, StaticSelect,
|
|
|
+ BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField,
|
|
|
)
|
|
|
-from wireless.choices import *
|
|
|
-from .common import InterfaceCommonForm
|
|
|
|
|
|
__all__ = (
|
|
|
- 'ConsolePortCreateForm',
|
|
|
- 'ConsolePortTemplateCreateForm',
|
|
|
- 'ConsoleServerPortCreateForm',
|
|
|
- 'ConsoleServerPortTemplateCreateForm',
|
|
|
- 'DeviceBayCreateForm',
|
|
|
- 'DeviceBayTemplateCreateForm',
|
|
|
+ 'ComponentCreateForm',
|
|
|
'FrontPortCreateForm',
|
|
|
'FrontPortTemplateCreateForm',
|
|
|
- 'InterfaceCreateForm',
|
|
|
- 'InterfaceTemplateCreateForm',
|
|
|
- 'InventoryItemCreateForm',
|
|
|
- 'ModuleBayCreateForm',
|
|
|
- 'ModuleBayTemplateCreateForm',
|
|
|
- 'PowerOutletCreateForm',
|
|
|
- 'PowerOutletTemplateCreateForm',
|
|
|
- 'PowerPortCreateForm',
|
|
|
- 'PowerPortTemplateCreateForm',
|
|
|
- 'RearPortCreateForm',
|
|
|
- 'RearPortTemplateCreateForm',
|
|
|
'VirtualChassisCreateForm',
|
|
|
)
|
|
|
|
|
|
|
|
|
-class ComponentForm(BootstrapMixin, forms.Form):
|
|
|
+class ComponentCreateForm(BootstrapMixin, forms.Form):
|
|
|
"""
|
|
|
Subclass this form when facilitating the creation of one or more device component or component templates based on
|
|
|
a name pattern.
|
|
|
@@ -65,215 +43,14 @@ class ComponentForm(BootstrapMixin, forms.Form):
|
|
|
}, code='label_pattern_mismatch')
|
|
|
|
|
|
|
|
|
-class VirtualChassisCreateForm(CustomFieldModelForm):
|
|
|
- region = DynamicModelChoiceField(
|
|
|
- queryset=Region.objects.all(),
|
|
|
- required=False,
|
|
|
- initial_params={
|
|
|
- 'sites': '$site'
|
|
|
- }
|
|
|
- )
|
|
|
- site_group = DynamicModelChoiceField(
|
|
|
- queryset=SiteGroup.objects.all(),
|
|
|
- required=False,
|
|
|
- initial_params={
|
|
|
- 'sites': '$site'
|
|
|
- }
|
|
|
- )
|
|
|
- site = DynamicModelChoiceField(
|
|
|
- queryset=Site.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'region_id': '$region',
|
|
|
- 'group_id': '$site_group',
|
|
|
- }
|
|
|
- )
|
|
|
- rack = DynamicModelChoiceField(
|
|
|
- queryset=Rack.objects.all(),
|
|
|
- required=False,
|
|
|
- null_option='None',
|
|
|
- query_params={
|
|
|
- 'site_id': '$site'
|
|
|
- }
|
|
|
- )
|
|
|
- members = DynamicModelMultipleChoiceField(
|
|
|
- queryset=Device.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'site_id': '$site',
|
|
|
- 'rack_id': '$rack',
|
|
|
- }
|
|
|
- )
|
|
|
- initial_position = forms.IntegerField(
|
|
|
- initial=1,
|
|
|
- required=False,
|
|
|
- help_text='Position of the first member device. Increases by one for each additional member.'
|
|
|
- )
|
|
|
- tags = DynamicModelMultipleChoiceField(
|
|
|
- queryset=Tag.objects.all(),
|
|
|
- required=False
|
|
|
- )
|
|
|
-
|
|
|
- class Meta:
|
|
|
- model = VirtualChassis
|
|
|
- fields = [
|
|
|
- 'name', 'domain', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'tags',
|
|
|
- ]
|
|
|
-
|
|
|
- def clean(self):
|
|
|
- if self.cleaned_data['members'] and self.cleaned_data['initial_position'] is None:
|
|
|
- raise forms.ValidationError({
|
|
|
- 'initial_position': "A position must be specified for the first VC member."
|
|
|
- })
|
|
|
-
|
|
|
- def save(self, *args, **kwargs):
|
|
|
- instance = super().save(*args, **kwargs)
|
|
|
-
|
|
|
- # Assign VC members
|
|
|
- if instance.pk and self.cleaned_data['members']:
|
|
|
- initial_position = self.cleaned_data.get('initial_position', 1)
|
|
|
- for i, member in enumerate(self.cleaned_data['members'], start=initial_position):
|
|
|
- member.virtual_chassis = instance
|
|
|
- member.vc_position = i
|
|
|
- member.save()
|
|
|
-
|
|
|
- return instance
|
|
|
-
|
|
|
-
|
|
|
-#
|
|
|
-# Component templates
|
|
|
-#
|
|
|
-
|
|
|
-class ComponentTemplateCreateForm(ComponentForm):
|
|
|
- """
|
|
|
- Base form for the creation of device component templates (subclassed from ComponentTemplateModel).
|
|
|
- """
|
|
|
- manufacturer = DynamicModelChoiceField(
|
|
|
- queryset=Manufacturer.objects.all(),
|
|
|
- required=False,
|
|
|
- initial_params={
|
|
|
- 'device_types': 'device_type',
|
|
|
- 'module_types': 'module_type',
|
|
|
- }
|
|
|
- )
|
|
|
- device_type = DynamicModelChoiceField(
|
|
|
- queryset=DeviceType.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'manufacturer_id': '$manufacturer'
|
|
|
- }
|
|
|
- )
|
|
|
- description = forms.CharField(
|
|
|
- required=False
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class ModularComponentTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
- module_type = DynamicModelChoiceField(
|
|
|
- queryset=ModuleType.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'manufacturer_id': '$manufacturer'
|
|
|
- }
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class ConsolePortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortTypeChoices),
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class ConsoleServerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortTypeChoices),
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class PowerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerPortTypeChoices),
|
|
|
- required=False
|
|
|
- )
|
|
|
- maximum_draw = forms.IntegerField(
|
|
|
- min_value=1,
|
|
|
- required=False,
|
|
|
- help_text="Maximum power draw (watts)"
|
|
|
- )
|
|
|
- allocated_draw = forms.IntegerField(
|
|
|
- min_value=1,
|
|
|
- required=False,
|
|
|
- help_text="Allocated power draw (watts)"
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'maximum_draw',
|
|
|
- 'allocated_draw', 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class PowerOutletTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerOutletTypeChoices),
|
|
|
- required=False
|
|
|
- )
|
|
|
- power_port = DynamicModelChoiceField(
|
|
|
- queryset=PowerPortTemplate.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'devicetype_id': '$device_type',
|
|
|
- 'moduletype_id': '$module_type',
|
|
|
- }
|
|
|
- )
|
|
|
- feed_leg = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerOutletFeedLegChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'power_port', 'feed_leg',
|
|
|
- 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class InterfaceTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=InterfaceTypeChoices,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- mgmt_only = forms.BooleanField(
|
|
|
- required=False,
|
|
|
- label='Management only'
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'mgmt_only',
|
|
|
- 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class FrontPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=PortTypeChoices,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- color = ColorField(
|
|
|
- required=False
|
|
|
- )
|
|
|
+class FrontPortTemplateCreateForm(ComponentCreateForm):
|
|
|
rear_port_set = forms.MultipleChoiceField(
|
|
|
choices=[],
|
|
|
label='Rear ports',
|
|
|
help_text='Select one rear port assignment for each front port being created.',
|
|
|
)
|
|
|
field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'color', 'rear_port_set',
|
|
|
- 'description',
|
|
|
+ 'name_pattern', 'label_pattern', 'rear_port_set',
|
|
|
)
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
@@ -300,18 +77,6 @@ class FrontPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
)
|
|
|
self.fields['rear_port_set'].choices = choices
|
|
|
|
|
|
- def clean(self):
|
|
|
- super().clean()
|
|
|
-
|
|
|
- # Validate that the number of ports being created equals the number of selected (rear port, position) tuples
|
|
|
- front_port_count = len(self.cleaned_data['name_pattern'])
|
|
|
- rear_port_count = len(self.cleaned_data['rear_port_set'])
|
|
|
- if front_port_count != rear_port_count:
|
|
|
- raise forms.ValidationError({
|
|
|
- 'rear_port_set': 'The provided name pattern will create {} ports, however {} rear port assignments '
|
|
|
- 'were selected. These counts must match.'.format(front_port_count, rear_port_count)
|
|
|
- })
|
|
|
-
|
|
|
def get_iterative_data(self, iteration):
|
|
|
|
|
|
# Assign rear port and position from selected set
|
|
|
@@ -323,252 +88,14 @@ class FrontPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
}
|
|
|
|
|
|
|
|
|
-class RearPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=PortTypeChoices,
|
|
|
- widget=StaticSelect(),
|
|
|
- )
|
|
|
- color = ColorField(
|
|
|
- required=False
|
|
|
- )
|
|
|
- positions = forms.IntegerField(
|
|
|
- min_value=REARPORT_POSITIONS_MIN,
|
|
|
- max_value=REARPORT_POSITIONS_MAX,
|
|
|
- initial=1,
|
|
|
- help_text='The number of front ports which may be mapped to each rear port'
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'manufacturer', 'device_type', 'module_type', 'name_pattern', 'label_pattern', 'type', 'color', 'positions',
|
|
|
- 'description',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class ModuleBayTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
- # TODO: Support patterned position assignment
|
|
|
- field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'description')
|
|
|
-
|
|
|
-
|
|
|
-class DeviceBayTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
- field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'description')
|
|
|
-
|
|
|
-
|
|
|
-#
|
|
|
-# Device components
|
|
|
-#
|
|
|
-
|
|
|
-class ComponentCreateForm(CustomFieldsMixin, ComponentForm):
|
|
|
- """
|
|
|
- Base form for the creation of device components (models subclassed from ComponentModel).
|
|
|
- """
|
|
|
- device = DynamicModelChoiceField(
|
|
|
- queryset=Device.objects.all()
|
|
|
- )
|
|
|
- description = forms.CharField(
|
|
|
- max_length=200,
|
|
|
- required=False
|
|
|
- )
|
|
|
- tags = DynamicModelMultipleChoiceField(
|
|
|
- queryset=Tag.objects.all(),
|
|
|
- required=False
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class ConsolePortCreateForm(ComponentCreateForm):
|
|
|
- model = ConsolePort
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortTypeChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- speed = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortSpeedChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- field_order = ('device', 'name_pattern', 'label_pattern', 'type', 'speed', 'mark_connected', 'description', 'tags')
|
|
|
-
|
|
|
-
|
|
|
-class ConsoleServerPortCreateForm(ComponentCreateForm):
|
|
|
- model = ConsoleServerPort
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortTypeChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- speed = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(ConsolePortSpeedChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- field_order = ('device', 'name_pattern', 'label_pattern', 'type', 'speed', 'mark_connected', 'description', 'tags')
|
|
|
-
|
|
|
-
|
|
|
-class PowerPortCreateForm(ComponentCreateForm):
|
|
|
- model = PowerPort
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerPortTypeChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- maximum_draw = forms.IntegerField(
|
|
|
- min_value=1,
|
|
|
- required=False,
|
|
|
- help_text="Maximum draw in watts"
|
|
|
- )
|
|
|
- allocated_draw = forms.IntegerField(
|
|
|
- min_value=1,
|
|
|
- required=False,
|
|
|
- help_text="Allocated draw in watts"
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'device', 'name_pattern', 'label_pattern', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected',
|
|
|
- 'description', 'tags',
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-class PowerOutletCreateForm(ComponentCreateForm):
|
|
|
- model = PowerOutlet
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerOutletTypeChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- power_port = forms.ModelChoiceField(
|
|
|
- queryset=PowerPort.objects.all(),
|
|
|
- required=False
|
|
|
- )
|
|
|
- feed_leg = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(PowerOutletFeedLegChoices),
|
|
|
- required=False
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'device', 'name_pattern', 'label_pattern', 'type', 'power_port', 'feed_leg', 'mark_connected', 'description',
|
|
|
- 'tags',
|
|
|
- )
|
|
|
-
|
|
|
- def __init__(self, *args, **kwargs):
|
|
|
- super().__init__(*args, **kwargs)
|
|
|
-
|
|
|
- # Limit power_port queryset to PowerPorts which belong to the parent Device
|
|
|
- device = Device.objects.get(
|
|
|
- pk=self.initial.get('device') or self.data.get('device')
|
|
|
- )
|
|
|
- self.fields['power_port'].queryset = PowerPort.objects.filter(device=device)
|
|
|
-
|
|
|
-
|
|
|
-class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
- model = Interface
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=InterfaceTypeChoices,
|
|
|
- widget=StaticSelect(),
|
|
|
- )
|
|
|
- enabled = forms.BooleanField(
|
|
|
- required=False,
|
|
|
- initial=True
|
|
|
- )
|
|
|
- parent = DynamicModelChoiceField(
|
|
|
- queryset=Interface.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'device_id': '$device',
|
|
|
- }
|
|
|
- )
|
|
|
- bridge = DynamicModelChoiceField(
|
|
|
- queryset=Interface.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'device_id': '$device',
|
|
|
- }
|
|
|
- )
|
|
|
- lag = DynamicModelChoiceField(
|
|
|
- queryset=Interface.objects.all(),
|
|
|
- required=False,
|
|
|
- query_params={
|
|
|
- 'device_id': '$device',
|
|
|
- 'type': 'lag',
|
|
|
- },
|
|
|
- label='LAG'
|
|
|
- )
|
|
|
- mac_address = forms.CharField(
|
|
|
- required=False,
|
|
|
- label='MAC Address'
|
|
|
- )
|
|
|
- wwn = forms.CharField(
|
|
|
- required=False,
|
|
|
- label='WWN'
|
|
|
- )
|
|
|
- mgmt_only = forms.BooleanField(
|
|
|
- required=False,
|
|
|
- label='Management only',
|
|
|
- help_text='This interface is used only for out-of-band management'
|
|
|
- )
|
|
|
- mode = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(InterfaceModeChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect()
|
|
|
- )
|
|
|
- rf_role = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(WirelessRoleChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect(),
|
|
|
- label='Wireless role'
|
|
|
- )
|
|
|
- rf_channel = forms.ChoiceField(
|
|
|
- choices=add_blank_choice(WirelessChannelChoices),
|
|
|
- required=False,
|
|
|
- widget=StaticSelect(),
|
|
|
- label='Wireless channel'
|
|
|
- )
|
|
|
- rf_channel_frequency = forms.DecimalField(
|
|
|
- required=False,
|
|
|
- label='Channel frequency (MHz)'
|
|
|
- )
|
|
|
- rf_channel_width = forms.DecimalField(
|
|
|
- required=False,
|
|
|
- label='Channel width (MHz)'
|
|
|
- )
|
|
|
- untagged_vlan = DynamicModelChoiceField(
|
|
|
- queryset=VLAN.objects.all(),
|
|
|
- required=False,
|
|
|
- label='Untagged VLAN'
|
|
|
- )
|
|
|
- tagged_vlans = DynamicModelMultipleChoiceField(
|
|
|
- queryset=VLAN.objects.all(),
|
|
|
- required=False,
|
|
|
- label='Tagged VLANs'
|
|
|
- )
|
|
|
- field_order = (
|
|
|
- 'device', 'name_pattern', 'label_pattern', 'type', 'enabled', 'parent', 'bridge', 'lag', 'mtu', 'mac_address',
|
|
|
- 'wwn', 'description', 'mgmt_only', 'mark_connected', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
|
|
- 'rf_channel_width', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags'
|
|
|
- )
|
|
|
-
|
|
|
- def __init__(self, *args, **kwargs):
|
|
|
- super().__init__(*args, **kwargs)
|
|
|
-
|
|
|
- # Limit VLAN choices by device
|
|
|
- device_id = self.initial.get('device') or self.data.get('device')
|
|
|
- self.fields['untagged_vlan'].widget.add_query_param('available_on_device', device_id)
|
|
|
- self.fields['tagged_vlans'].widget.add_query_param('available_on_device', device_id)
|
|
|
-
|
|
|
-
|
|
|
class FrontPortCreateForm(ComponentCreateForm):
|
|
|
- model = FrontPort
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=PortTypeChoices,
|
|
|
- widget=StaticSelect(),
|
|
|
- )
|
|
|
- color = ColorField(
|
|
|
- required=False
|
|
|
- )
|
|
|
rear_port_set = forms.MultipleChoiceField(
|
|
|
choices=[],
|
|
|
label='Rear ports',
|
|
|
help_text='Select one rear port assignment for each front port being created.',
|
|
|
)
|
|
|
field_order = (
|
|
|
- 'device', 'name_pattern', 'label_pattern', 'type', 'color', 'rear_port_set', 'mark_connected', 'description',
|
|
|
- 'tags',
|
|
|
+ 'name_pattern', 'label_pattern', 'rear_port_set',
|
|
|
)
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
@@ -596,18 +123,6 @@ class FrontPortCreateForm(ComponentCreateForm):
|
|
|
)
|
|
|
self.fields['rear_port_set'].choices = choices
|
|
|
|
|
|
- def clean(self):
|
|
|
- super().clean()
|
|
|
-
|
|
|
- # Validate that the number of ports being created equals the number of selected (rear port, position) tuples
|
|
|
- front_port_count = len(self.cleaned_data['name_pattern'])
|
|
|
- rear_port_count = len(self.cleaned_data['rear_port_set'])
|
|
|
- if front_port_count != rear_port_count:
|
|
|
- raise forms.ValidationError({
|
|
|
- 'rear_port_set': 'The provided name pattern will create {} ports, however {} rear port assignments '
|
|
|
- 'were selected. These counts must match.'.format(front_port_count, rear_port_count)
|
|
|
- })
|
|
|
-
|
|
|
def get_iterative_data(self, iteration):
|
|
|
|
|
|
# Assign rear port and position from selected set
|
|
|
@@ -619,68 +134,76 @@ class FrontPortCreateForm(ComponentCreateForm):
|
|
|
}
|
|
|
|
|
|
|
|
|
-class RearPortCreateForm(ComponentCreateForm):
|
|
|
- model = RearPort
|
|
|
- type = forms.ChoiceField(
|
|
|
- choices=PortTypeChoices,
|
|
|
- widget=StaticSelect(),
|
|
|
- )
|
|
|
- color = ColorField(
|
|
|
- required=False
|
|
|
- )
|
|
|
- positions = forms.IntegerField(
|
|
|
- min_value=REARPORT_POSITIONS_MIN,
|
|
|
- max_value=REARPORT_POSITIONS_MAX,
|
|
|
- initial=1,
|
|
|
- help_text='The number of front ports which may be mapped to each rear port'
|
|
|
+class VirtualChassisCreateForm(CustomFieldModelForm):
|
|
|
+ region = DynamicModelChoiceField(
|
|
|
+ queryset=Region.objects.all(),
|
|
|
+ required=False,
|
|
|
+ initial_params={
|
|
|
+ 'sites': '$site'
|
|
|
+ }
|
|
|
)
|
|
|
- field_order = (
|
|
|
- 'device', 'name_pattern', 'label_pattern', 'type', 'color', 'positions', 'mark_connected', 'description',
|
|
|
- 'tags',
|
|
|
+ site_group = DynamicModelChoiceField(
|
|
|
+ queryset=SiteGroup.objects.all(),
|
|
|
+ required=False,
|
|
|
+ initial_params={
|
|
|
+ 'sites': '$site'
|
|
|
+ }
|
|
|
)
|
|
|
-
|
|
|
-
|
|
|
-class ModuleBayCreateForm(ComponentCreateForm):
|
|
|
- model = ModuleBay
|
|
|
- field_order = ('device', 'name_pattern', 'label_pattern', 'description', 'tags')
|
|
|
-
|
|
|
-
|
|
|
-class DeviceBayCreateForm(ComponentCreateForm):
|
|
|
- model = DeviceBay
|
|
|
- field_order = ('device', 'name_pattern', 'label_pattern', 'description', 'tags')
|
|
|
-
|
|
|
-
|
|
|
-class InventoryItemCreateForm(ComponentCreateForm):
|
|
|
- model = InventoryItem
|
|
|
- parent = DynamicModelChoiceField(
|
|
|
- queryset=InventoryItem.objects.all(),
|
|
|
+ site = DynamicModelChoiceField(
|
|
|
+ queryset=Site.objects.all(),
|
|
|
required=False,
|
|
|
query_params={
|
|
|
- 'device_id': '$device'
|
|
|
+ 'region_id': '$region',
|
|
|
+ 'group_id': '$site_group',
|
|
|
}
|
|
|
)
|
|
|
- role = DynamicModelChoiceField(
|
|
|
- queryset=InventoryItemRole.objects.all(),
|
|
|
- required=False
|
|
|
- )
|
|
|
- manufacturer = DynamicModelChoiceField(
|
|
|
- queryset=Manufacturer.objects.all(),
|
|
|
- required=False
|
|
|
- )
|
|
|
- part_id = forms.CharField(
|
|
|
- max_length=50,
|
|
|
+ rack = DynamicModelChoiceField(
|
|
|
+ queryset=Rack.objects.all(),
|
|
|
required=False,
|
|
|
- label='Part ID'
|
|
|
+ null_option='None',
|
|
|
+ query_params={
|
|
|
+ 'site_id': '$site'
|
|
|
+ }
|
|
|
)
|
|
|
- serial = forms.CharField(
|
|
|
- max_length=50,
|
|
|
+ members = DynamicModelMultipleChoiceField(
|
|
|
+ queryset=Device.objects.all(),
|
|
|
required=False,
|
|
|
+ query_params={
|
|
|
+ 'site_id': '$site',
|
|
|
+ 'rack_id': '$rack',
|
|
|
+ }
|
|
|
)
|
|
|
- asset_tag = forms.CharField(
|
|
|
- max_length=50,
|
|
|
+ initial_position = forms.IntegerField(
|
|
|
+ initial=1,
|
|
|
required=False,
|
|
|
+ help_text='Position of the first member device. Increases by one for each additional member.'
|
|
|
)
|
|
|
- field_order = (
|
|
|
- 'device', 'parent', 'name_pattern', 'label_pattern', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
|
|
|
- 'description', 'tags',
|
|
|
+ tags = DynamicModelMultipleChoiceField(
|
|
|
+ queryset=Tag.objects.all(),
|
|
|
+ required=False
|
|
|
)
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ model = VirtualChassis
|
|
|
+ fields = [
|
|
|
+ 'name', 'domain', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'tags',
|
|
|
+ ]
|
|
|
+
|
|
|
+ def clean(self):
|
|
|
+ if self.cleaned_data['members'] and self.cleaned_data['initial_position'] is None:
|
|
|
+ raise forms.ValidationError({
|
|
|
+ 'initial_position': "A position must be specified for the first VC member."
|
|
|
+ })
|
|
|
+
|
|
|
+ def save(self, *args, **kwargs):
|
|
|
+ instance = super().save(*args, **kwargs)
|
|
|
+
|
|
|
+ # Assign VC members
|
|
|
+ if instance.pk and self.cleaned_data['members']:
|
|
|
+ initial_position = self.cleaned_data.get('initial_position', 1)
|
|
|
+ for i, member in enumerate(self.cleaned_data['members'], start=initial_position):
|
|
|
+ member.virtual_chassis = instance
|
|
|
+ member.vc_position = i
|
|
|
+ member.save()
|
|
|
+
|
|
|
+ return instance
|