123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- from django import forms
- from django.db.models import Count
- from dcim.models import Site, Device, Interface, Rack, VIRTUAL_IFACE_TYPES
- from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
- from tenancy.models import Tenant
- from utilities.forms import (
- APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, FilterChoiceField, Livesearch, SmallTextarea,
- SlugField,
- )
- from .models import Circuit, CircuitTermination, CircuitType, Provider
- #
- # Providers
- #
- class ProviderForm(BootstrapMixin, CustomFieldForm):
- slug = SlugField()
- comments = CommentField()
- class Meta:
- model = Provider
- fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
- widgets = {
- 'noc_contact': SmallTextarea(attrs={'rows': 5}),
- 'admin_contact': SmallTextarea(attrs={'rows': 5}),
- }
- help_texts = {
- 'name': "Full name of the provider",
- 'asn': "BGP autonomous system number (if applicable)",
- 'portal_url': "URL of the provider's customer support portal",
- 'noc_contact': "NOC email address and phone number",
- 'admin_contact': "Administrative contact email address and phone number",
- }
- class ProviderFromCSVForm(forms.ModelForm):
- class Meta:
- model = Provider
- fields = ['name', 'slug', 'asn', 'account', 'portal_url']
- class ProviderImportForm(BootstrapMixin, BulkImportForm):
- csv = CSVDataField(csv_form=ProviderFromCSVForm)
- class ProviderBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
- pk = forms.ModelMultipleChoiceField(queryset=Provider.objects.all(), widget=forms.MultipleHiddenInput)
- asn = forms.IntegerField(required=False, label='ASN')
- account = forms.CharField(max_length=30, required=False, label='Account number')
- portal_url = forms.URLField(required=False, label='Portal')
- noc_contact = forms.CharField(required=False, widget=SmallTextarea, label='NOC contact')
- admin_contact = forms.CharField(required=False, widget=SmallTextarea, label='Admin contact')
- comments = CommentField(widget=SmallTextarea)
- class Meta:
- nullable_fields = ['asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
- class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
- model = Provider
- q = forms.CharField(required=False, label='Search')
- site = FilterChoiceField(queryset=Site.objects.all(), to_field_name='slug')
- asn = forms.IntegerField(required=False, label='ASN')
- #
- # Circuit types
- #
- class CircuitTypeForm(BootstrapMixin, forms.ModelForm):
- slug = SlugField()
- class Meta:
- model = CircuitType
- fields = ['name', 'slug']
- #
- # Circuits
- #
- class CircuitForm(BootstrapMixin, CustomFieldForm):
- comments = CommentField()
- class Meta:
- model = Circuit
- fields = ['cid', 'type', 'provider', 'tenant', 'install_date', 'commit_rate', 'description', 'comments']
- help_texts = {
- 'cid': "Unique circuit ID",
- 'install_date': "Format: YYYY-MM-DD",
- 'commit_rate': "Committed rate",
- }
- class CircuitFromCSVForm(forms.ModelForm):
- provider = forms.ModelChoiceField(Provider.objects.all(), to_field_name='name',
- error_messages={'invalid_choice': 'Provider not found.'})
- type = forms.ModelChoiceField(CircuitType.objects.all(), to_field_name='name',
- error_messages={'invalid_choice': 'Invalid circuit type.'})
- tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
- error_messages={'invalid_choice': 'Tenant not found.'})
- class Meta:
- model = Circuit
- fields = ['cid', 'provider', 'type', 'tenant', 'install_date', 'commit_rate', 'description']
- class CircuitImportForm(BootstrapMixin, BulkImportForm):
- csv = CSVDataField(csv_form=CircuitFromCSVForm)
- class CircuitBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
- pk = forms.ModelMultipleChoiceField(queryset=Circuit.objects.all(), widget=forms.MultipleHiddenInput)
- type = forms.ModelChoiceField(queryset=CircuitType.objects.all(), required=False)
- provider = forms.ModelChoiceField(queryset=Provider.objects.all(), required=False)
- tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
- commit_rate = forms.IntegerField(required=False, label='Commit rate (Kbps)')
- description = forms.CharField(max_length=100, required=False)
- comments = CommentField(widget=SmallTextarea)
- class Meta:
- nullable_fields = ['tenant', 'commit_rate', 'description', 'comments']
- class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
- model = Circuit
- q = forms.CharField(required=False, label='Search')
- type = FilterChoiceField(
- queryset=CircuitType.objects.annotate(filter_count=Count('circuits')),
- to_field_name='slug'
- )
- provider = FilterChoiceField(
- queryset=Provider.objects.annotate(filter_count=Count('circuits')),
- to_field_name='slug'
- )
- tenant = FilterChoiceField(
- queryset=Tenant.objects.annotate(filter_count=Count('circuits')),
- to_field_name='slug',
- null_option=(0, 'None')
- )
- site = FilterChoiceField(
- queryset=Site.objects.annotate(filter_count=Count('circuit_terminations')),
- to_field_name='slug'
- )
- #
- # Circuit terminations
- #
- class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
- site = forms.ModelChoiceField(
- queryset=Site.objects.all(),
- widget=forms.Select(
- attrs={'filter-for': 'rack'}
- )
- )
- rack = forms.ModelChoiceField(
- queryset=Rack.objects.all(),
- required=False,
- label='Rack',
- widget=APISelect(
- api_url='/api/dcim/racks/?site_id={{site}}',
- attrs={'filter-for': 'device', 'nullable': 'true'}
- )
- )
- device = forms.ModelChoiceField(
- queryset=Device.objects.all(),
- required=False,
- label='Device',
- widget=APISelect(
- api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}',
- display_field='display_name',
- attrs={'filter-for': 'interface'}
- )
- )
- livesearch = forms.CharField(
- required=False,
- label='Device',
- widget=Livesearch(
- query_key='q',
- query_url='dcim-api:device-list',
- field_to_update='device'
- )
- )
- interface = forms.ModelChoiceField(
- queryset=Interface.objects.all(),
- required=False,
- label='Interface',
- widget=APISelect(
- api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical',
- disabled_indicator='is_connected'
- )
- )
- class Meta:
- model = CircuitTermination
- fields = ['term_side', 'site', 'rack', 'device', 'livesearch', 'interface', 'port_speed', 'upstream_speed',
- 'xconnect_id', 'pp_info']
- help_texts = {
- 'port_speed': "Physical circuit speed",
- 'xconnect_id': "ID of the local cross-connect",
- 'pp_info': "Patch panel ID and port number(s)"
- }
- widgets = {
- 'term_side': forms.HiddenInput(),
- }
- def __init__(self, *args, **kwargs):
- super(CircuitTerminationForm, self).__init__(*args, **kwargs)
- # If an interface has been assigned, initialize rack and device
- if self.instance.interface:
- self.initial['rack'] = self.instance.interface.device.rack
- self.initial['device'] = self.instance.interface.device
- # Limit rack choices
- if self.is_bound:
- self.fields['rack'].queryset = Rack.objects.filter(site__pk=self.data['site'])
- elif self.initial.get('site'):
- self.fields['rack'].queryset = Rack.objects.filter(site=self.initial['site'])
- else:
- self.fields['rack'].choices = []
- # Limit device choices
- if self.is_bound and self.data.get('rack'):
- self.fields['device'].queryset = Device.objects.filter(rack=self.data['rack'])
- elif self.initial.get('rack'):
- self.fields['device'].queryset = Device.objects.filter(rack=self.initial['rack'])
- else:
- self.fields['device'].choices = []
- # Limit interface choices
- if self.is_bound and self.data.get('device'):
- interfaces = Interface.objects.filter(device=self.data['device']).exclude(
- form_factor__in=VIRTUAL_IFACE_TYPES
- ).select_related(
- 'circuit_termination', 'connected_as_a', 'connected_as_b'
- )
- self.fields['interface'].widget.attrs['initial'] = self.data.get('interface')
- elif self.initial.get('device'):
- interfaces = Interface.objects.filter(device=self.initial['device']).exclude(
- form_factor__in=VIRTUAL_IFACE_TYPES
- ).select_related(
- 'circuit_termination', 'connected_as_a', 'connected_as_b'
- )
- self.fields['interface'].widget.attrs['initial'] = self.initial.get('interface')
- else:
- interfaces = []
- self.fields['interface'].choices = [
- (iface.id, {
- 'label': iface.name,
- 'disabled': iface.is_connected and iface.id != self.fields['interface'].widget.attrs.get('initial'),
- }) for iface in interfaces
- ]
|