|
@@ -9,7 +9,7 @@ from utilities.forms import (
|
|
SlugField,
|
|
SlugField,
|
|
)
|
|
)
|
|
|
|
|
|
-from .models import Circuit, CircuitType, Provider
|
|
|
|
|
|
+from .models import Circuit, CircuitTermination, CircuitType, Provider
|
|
|
|
|
|
|
|
|
|
#
|
|
#
|
|
@@ -82,6 +82,64 @@ class CircuitTypeForm(forms.ModelForm, BootstrapMixin):
|
|
#
|
|
#
|
|
|
|
|
|
class CircuitForm(BootstrapMixin, CustomFieldForm):
|
|
class CircuitForm(BootstrapMixin, CustomFieldForm):
|
|
|
|
+ comments = CommentField()
|
|
|
|
+
|
|
|
|
+ class Meta:
|
|
|
|
+ model = Circuit
|
|
|
|
+ fields = ['cid', 'type', 'provider', 'tenant', 'install_date', 'commit_rate', 'comments']
|
|
|
|
+ help_texts = {
|
|
|
|
+ 'cid': "Unique circuit ID",
|
|
|
|
+ 'install_date': "Format: YYYY-MM-DD",
|
|
|
|
+ 'commit_rate': "Commited 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']
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class CircuitImportForm(BulkImportForm, BootstrapMixin):
|
|
|
|
+ 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)')
|
|
|
|
+ comments = CommentField(widget=SmallTextarea)
|
|
|
|
+
|
|
|
|
+ class Meta:
|
|
|
|
+ nullable_fields = ['tenant', 'commit_rate', 'comments']
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
+ model = Circuit
|
|
|
|
+ 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(forms.ModelForm, BootstrapMixin):
|
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'}))
|
|
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',
|
|
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), required=False, label='Rack',
|
|
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}',
|
|
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}',
|
|
@@ -95,28 +153,25 @@ class CircuitForm(BootstrapMixin, CustomFieldForm):
|
|
interface = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Interface',
|
|
interface = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Interface',
|
|
widget=APISelect(api_url='/api/dcim/devices/{{device}}/interfaces/?type=physical',
|
|
widget=APISelect(api_url='/api/dcim/devices/{{device}}/interfaces/?type=physical',
|
|
disabled_indicator='is_connected'))
|
|
disabled_indicator='is_connected'))
|
|
- comments = CommentField()
|
|
|
|
|
|
|
|
class Meta:
|
|
class Meta:
|
|
- model = Circuit
|
|
|
|
- fields = [
|
|
|
|
- 'cid', 'type', 'provider', 'tenant', 'site', 'rack', 'device', 'livesearch', 'interface', 'install_date',
|
|
|
|
- 'port_speed', 'upstream_speed', 'commit_rate', 'xconnect_id', 'pp_info', 'comments'
|
|
|
|
- ]
|
|
|
|
|
|
+ model = CircuitTermination
|
|
|
|
+ fields = ['term_side', 'site', 'rack', 'device', 'livesearch', 'interface', 'port_speed', 'upstream_speed',
|
|
|
|
+ 'xconnect_id', 'pp_info']
|
|
help_texts = {
|
|
help_texts = {
|
|
- 'cid': "Unique circuit ID",
|
|
|
|
- 'install_date': "Format: YYYY-MM-DD",
|
|
|
|
'port_speed': "Physical circuit speed",
|
|
'port_speed': "Physical circuit speed",
|
|
- 'commit_rate': "Commited rate",
|
|
|
|
'xconnect_id': "ID of the local cross-connect",
|
|
'xconnect_id': "ID of the local cross-connect",
|
|
'pp_info': "Patch panel ID and port number(s)"
|
|
'pp_info': "Patch panel ID and port number(s)"
|
|
}
|
|
}
|
|
|
|
+ widgets = {
|
|
|
|
+ 'term_side': forms.HiddenInput(),
|
|
|
|
+ }
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
- super(CircuitForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
+ super(CircuitTerminationForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
- # If this circuit has been assigned to an interface, initialize rack and device
|
|
|
|
|
|
+ # If an interface has been assigned, initialize rack and device
|
|
if self.instance.interface:
|
|
if self.instance.interface:
|
|
self.initial['rack'] = self.instance.interface.device.rack
|
|
self.initial['rack'] = self.instance.interface.device.rack
|
|
self.initial['device'] = self.instance.interface.device
|
|
self.initial['device'] = self.instance.interface.device
|
|
@@ -140,11 +195,13 @@ class CircuitForm(BootstrapMixin, CustomFieldForm):
|
|
# Limit interface choices
|
|
# Limit interface choices
|
|
if self.is_bound and self.data.get('device'):
|
|
if self.is_bound and self.data.get('device'):
|
|
interfaces = Interface.objects.filter(device=self.data['device'])\
|
|
interfaces = Interface.objects.filter(device=self.data['device'])\
|
|
- .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit', 'connected_as_a', 'connected_as_b')
|
|
|
|
|
|
+ .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit_termination', 'connected_as_a',
|
|
|
|
+ 'connected_as_b')
|
|
self.fields['interface'].widget.attrs['initial'] = self.data.get('interface')
|
|
self.fields['interface'].widget.attrs['initial'] = self.data.get('interface')
|
|
elif self.initial.get('device'):
|
|
elif self.initial.get('device'):
|
|
interfaces = Interface.objects.filter(device=self.initial['device'])\
|
|
interfaces = Interface.objects.filter(device=self.initial['device'])\
|
|
- .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit', 'connected_as_a', 'connected_as_b')
|
|
|
|
|
|
+ .exclude(form_factor=IFACE_FF_VIRTUAL).select_related('circuit_termination', 'connected_as_a',
|
|
|
|
+ 'connected_as_b')
|
|
self.fields['interface'].widget.attrs['initial'] = self.initial.get('interface')
|
|
self.fields['interface'].widget.attrs['initial'] = self.initial.get('interface')
|
|
else:
|
|
else:
|
|
interfaces = []
|
|
interfaces = []
|
|
@@ -154,47 +211,3 @@ class CircuitForm(BootstrapMixin, CustomFieldForm):
|
|
'disabled': iface.is_connected and iface.id != self.fields['interface'].widget.attrs.get('initial'),
|
|
'disabled': iface.is_connected and iface.id != self.fields['interface'].widget.attrs.get('initial'),
|
|
}) for iface in interfaces
|
|
}) for iface in interfaces
|
|
]
|
|
]
|
|
-
|
|
|
|
-
|
|
|
|
-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.'})
|
|
|
|
- site = forms.ModelChoiceField(Site.objects.all(), to_field_name='name',
|
|
|
|
- error_messages={'invalid_choice': 'Site not found.'})
|
|
|
|
-
|
|
|
|
- class Meta:
|
|
|
|
- model = Circuit
|
|
|
|
- fields = ['cid', 'provider', 'type', 'tenant', 'site', 'install_date', 'port_speed', 'upstream_speed',
|
|
|
|
- 'commit_rate', 'xconnect_id', 'pp_info']
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-class CircuitImportForm(BulkImportForm, BootstrapMixin):
|
|
|
|
- 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)
|
|
|
|
- port_speed = forms.IntegerField(required=False, label='Port speed (Kbps)')
|
|
|
|
- commit_rate = forms.IntegerField(required=False, label='Commit rate (Kbps)')
|
|
|
|
- comments = CommentField(widget=SmallTextarea)
|
|
|
|
-
|
|
|
|
- class Meta:
|
|
|
|
- nullable_fields = ['tenant', 'port_speed', 'commit_rate', 'comments']
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
- model = Circuit
|
|
|
|
- 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('circuits')), to_field_name='slug')
|
|
|