2017-05-24 11:33:11 -04:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
from django import forms
|
2016-09-20 11:08:25 -04:00
|
|
|
from django.db.models import Count
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2017-02-27 16:52:13 -05:00
|
|
|
from dcim.models import Site, Device, Interface, Rack, VIRTUAL_IFACE_TYPES
|
2016-08-23 12:05:28 -04:00
|
|
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
2017-05-11 17:35:20 -04:00
|
|
|
from tenancy.forms import TenancyForm
|
2016-07-26 15:48:48 -04:00
|
|
|
from tenancy.models import Tenant
|
2016-05-18 15:17:58 -04:00
|
|
|
from utilities.forms import (
|
2017-06-02 13:40:52 -04:00
|
|
|
APISelect, BootstrapMixin, ChainedFieldsMixin, ChainedModelChoiceField, CommentField, FilterChoiceField,
|
|
|
|
SmallTextarea, SlugField,
|
2016-05-18 15:17:58 -04:00
|
|
|
)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-12-14 13:47:22 -05:00
|
|
|
from .models import Circuit, CircuitTermination, CircuitType, Provider
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Providers
|
|
|
|
#
|
|
|
|
|
2016-08-15 15:24:23 -04:00
|
|
|
class ProviderForm(BootstrapMixin, CustomFieldForm):
|
2016-05-20 15:32:17 -04:00
|
|
|
slug = SlugField()
|
2016-03-01 11:23:03 -05:00
|
|
|
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",
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-02 13:40:52 -04:00
|
|
|
class ProviderCSVForm(forms.ModelForm):
|
|
|
|
slug = SlugField()
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Provider
|
2017-06-02 13:40:52 -04:00
|
|
|
fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'comments']
|
|
|
|
help_texts = {
|
|
|
|
'name': 'Provider name',
|
2017-06-06 17:27:26 -04:00
|
|
|
'asn': '32-bit autonomous system number',
|
|
|
|
'portal_url': 'Portal URL',
|
|
|
|
'comments': 'Free-form comments',
|
2017-06-02 13:40:52 -04:00
|
|
|
}
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
2016-08-22 13:11:57 -04:00
|
|
|
class ProviderBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
2016-03-01 11:23:03 -05:00
|
|
|
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')
|
2016-11-29 17:29:56 -05:00
|
|
|
comments = CommentField(widget=SmallTextarea)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-09-30 16:17:41 -04:00
|
|
|
class Meta:
|
|
|
|
nullable_fields = ['asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
|
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-08-23 12:05:28 -04:00
|
|
|
class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
model = Provider
|
2017-01-24 12:05:39 -05:00
|
|
|
q = forms.CharField(required=False, label='Search')
|
2016-09-20 11:08:25 -04:00
|
|
|
site = FilterChoiceField(queryset=Site.objects.all(), to_field_name='slug')
|
2017-03-01 13:09:19 -05:00
|
|
|
asn = forms.IntegerField(required=False, label='ASN')
|
2016-07-14 13:53:30 -04:00
|
|
|
|
|
|
|
|
2016-05-13 12:44:03 -04:00
|
|
|
#
|
|
|
|
# Circuit types
|
|
|
|
#
|
|
|
|
|
2016-12-21 14:15:18 -05:00
|
|
|
class CircuitTypeForm(BootstrapMixin, forms.ModelForm):
|
2016-05-20 15:32:17 -04:00
|
|
|
slug = SlugField()
|
2016-05-13 12:44:03 -04:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = CircuitType
|
|
|
|
fields = ['name', 'slug']
|
|
|
|
|
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
# Circuits
|
|
|
|
#
|
|
|
|
|
2017-05-11 17:35:20 -04:00
|
|
|
class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
2016-12-14 13:47:22 -05:00
|
|
|
comments = CommentField()
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Circuit
|
2017-05-11 17:35:20 -04:00
|
|
|
fields = [
|
|
|
|
'cid', 'type', 'provider', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
|
|
|
|
'comments',
|
|
|
|
]
|
2016-12-14 13:47:22 -05:00
|
|
|
help_texts = {
|
|
|
|
'cid': "Unique circuit ID",
|
|
|
|
'install_date': "Format: YYYY-MM-DD",
|
2017-01-03 14:25:51 -05:00
|
|
|
'commit_rate': "Committed rate",
|
2016-12-14 13:47:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-02 13:40:52 -04:00
|
|
|
class CircuitCSVForm(forms.ModelForm):
|
|
|
|
provider = forms.ModelChoiceField(
|
|
|
|
queryset=Provider.objects.all(),
|
|
|
|
to_field_name='name',
|
|
|
|
help_text='Name of parent provider',
|
|
|
|
error_messages={
|
|
|
|
'invalid_choice': 'Provider not found.'
|
|
|
|
}
|
|
|
|
)
|
|
|
|
type = forms.ModelChoiceField(
|
|
|
|
queryset=CircuitType.objects.all(),
|
|
|
|
to_field_name='name',
|
2017-06-07 15:30:28 -04:00
|
|
|
help_text='Type of circuit',
|
2017-06-02 13:40:52 -04:00
|
|
|
error_messages={
|
|
|
|
'invalid_choice': 'Invalid circuit type.'
|
|
|
|
}
|
|
|
|
)
|
|
|
|
tenant = forms.ModelChoiceField(
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
required=False,
|
|
|
|
to_field_name='name',
|
2017-06-06 17:27:26 -04:00
|
|
|
help_text='Name of assigned tenant',
|
2017-06-02 13:40:52 -04:00
|
|
|
error_messages={
|
|
|
|
'invalid_choice': 'Tenant not found.'
|
|
|
|
}
|
|
|
|
)
|
2016-12-14 13:47:22 -05:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Circuit
|
2017-06-02 13:40:52 -04:00
|
|
|
fields = ['cid', 'provider', 'type', 'tenant', 'install_date', 'commit_rate', 'description', 'comments']
|
2016-12-14 13:47:22 -05:00
|
|
|
|
|
|
|
|
|
|
|
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)')
|
2017-01-17 15:18:03 -05:00
|
|
|
description = forms.CharField(max_length=100, required=False)
|
2016-12-14 13:47:22 -05:00
|
|
|
comments = CommentField(widget=SmallTextarea)
|
|
|
|
|
|
|
|
class Meta:
|
2017-01-17 15:18:03 -05:00
|
|
|
nullable_fields = ['tenant', 'commit_rate', 'description', 'comments']
|
2016-12-14 13:47:22 -05:00
|
|
|
|
|
|
|
|
|
|
|
class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
model = Circuit
|
2017-01-24 12:05:39 -05:00
|
|
|
q = forms.CharField(required=False, label='Search')
|
2017-03-01 13:09:19 -05:00
|
|
|
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'
|
|
|
|
)
|
2016-12-14 13:47:22 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Circuit terminations
|
|
|
|
#
|
|
|
|
|
2017-05-11 16:24:57 -04:00
|
|
|
class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm):
|
2017-02-17 14:48:00 -05:00
|
|
|
site = forms.ModelChoiceField(
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
widget=forms.Select(
|
|
|
|
attrs={'filter-for': 'rack'}
|
|
|
|
)
|
|
|
|
)
|
2017-05-11 16:24:57 -04:00
|
|
|
rack = ChainedModelChoiceField(
|
2017-02-17 14:48:00 -05:00
|
|
|
queryset=Rack.objects.all(),
|
2017-05-25 14:33:50 -04:00
|
|
|
chains=(
|
|
|
|
('site', 'site'),
|
|
|
|
),
|
2017-02-17 14:48:00 -05:00
|
|
|
required=False,
|
|
|
|
label='Rack',
|
|
|
|
widget=APISelect(
|
|
|
|
api_url='/api/dcim/racks/?site_id={{site}}',
|
|
|
|
attrs={'filter-for': 'device', 'nullable': 'true'}
|
|
|
|
)
|
|
|
|
)
|
2017-05-11 16:24:57 -04:00
|
|
|
device = ChainedModelChoiceField(
|
2017-02-17 14:48:00 -05:00
|
|
|
queryset=Device.objects.all(),
|
2017-05-25 14:33:50 -04:00
|
|
|
chains=(
|
|
|
|
('site', 'site'),
|
|
|
|
('rack', 'rack'),
|
|
|
|
),
|
2017-02-17 14:48:00 -05:00
|
|
|
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'}
|
|
|
|
)
|
|
|
|
)
|
2017-05-11 16:24:57 -04:00
|
|
|
interface = ChainedModelChoiceField(
|
|
|
|
queryset=Interface.objects.exclude(form_factor__in=VIRTUAL_IFACE_TYPES).select_related(
|
|
|
|
'circuit_termination', 'connected_as_a', 'connected_as_b'
|
|
|
|
),
|
2017-05-25 14:33:50 -04:00
|
|
|
chains=(
|
|
|
|
('device', 'device'),
|
|
|
|
),
|
2017-02-17 14:48:00 -05:00
|
|
|
required=False,
|
|
|
|
label='Interface',
|
|
|
|
widget=APISelect(
|
2017-03-24 18:42:23 -05:00
|
|
|
api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical',
|
2017-06-14 10:57:43 -04:00
|
|
|
disabled_indicator='connection'
|
2017-02-17 14:48:00 -05:00
|
|
|
)
|
2016-03-01 11:23:03 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
class Meta:
|
2016-12-14 13:47:22 -05:00
|
|
|
model = CircuitTermination
|
2017-05-25 14:33:50 -04:00
|
|
|
fields = [
|
|
|
|
'term_side', 'site', 'rack', 'device', 'interface', 'port_speed', 'upstream_speed', 'xconnect_id',
|
|
|
|
'pp_info',
|
|
|
|
]
|
2016-03-01 11:23:03 -05:00
|
|
|
help_texts = {
|
|
|
|
'port_speed': "Physical circuit speed",
|
|
|
|
'xconnect_id': "ID of the local cross-connect",
|
|
|
|
'pp_info': "Patch panel ID and port number(s)"
|
|
|
|
}
|
2016-12-14 13:47:22 -05:00
|
|
|
widgets = {
|
|
|
|
'term_side': forms.HiddenInput(),
|
|
|
|
}
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2017-05-11 17:52:23 -04:00
|
|
|
def __init__(self, *args, **kwargs):
|
2017-05-11 16:24:57 -04:00
|
|
|
|
|
|
|
# Initialize helper selectors
|
2017-05-11 17:52:23 -04:00
|
|
|
instance = kwargs.get('instance')
|
2017-05-11 16:24:57 -04:00
|
|
|
if instance and instance.interface is not None:
|
2017-05-11 17:52:23 -04:00
|
|
|
initial = kwargs.get('initial', {})
|
2017-05-11 16:24:57 -04:00
|
|
|
initial['rack'] = instance.interface.device.rack
|
|
|
|
initial['device'] = instance.interface.device
|
2017-05-11 17:52:23 -04:00
|
|
|
kwargs['initial'] = initial
|
2017-05-11 16:24:57 -04:00
|
|
|
|
2017-05-11 17:52:23 -04:00
|
|
|
super(CircuitTerminationForm, self).__init__(*args, **kwargs)
|
2017-05-11 16:24:57 -04:00
|
|
|
|
|
|
|
# Mark connected interfaces as disabled
|
2016-03-01 11:23:03 -05:00
|
|
|
self.fields['interface'].choices = [
|
2017-05-11 16:24:57 -04:00
|
|
|
(iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in self.fields['interface'].queryset
|
2016-03-01 11:23:03 -05:00
|
|
|
]
|