|
|
|
@@ -1,7 +1,6 @@
|
|
|
|
|
from django import forms
|
|
|
|
|
from django.core.exceptions import MultipleObjectsReturned
|
|
|
|
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
|
|
|
from django.db.models import Count
|
|
|
|
|
from taggit.forms import TagField
|
|
|
|
|
|
|
|
|
|
from dcim.models import Site, Rack, Device, Interface
|
|
|
|
@@ -9,9 +8,9 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
|
|
|
|
from tenancy.forms import TenancyForm
|
|
|
|
|
from tenancy.models import Tenant
|
|
|
|
|
from utilities.forms import (
|
|
|
|
|
AnnotatedMultipleChoiceField, APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
|
|
|
|
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, ReturnURLForm,
|
|
|
|
|
SlugField, add_blank_choice,
|
|
|
|
|
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
|
|
|
|
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, SlugField,
|
|
|
|
|
StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
|
|
|
|
)
|
|
|
|
|
from virtualization.models import VirtualMachine
|
|
|
|
|
from .constants import (
|
|
|
|
@@ -77,7 +76,10 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
|
|
|
|
|
)
|
|
|
|
|
tenant = forms.ModelChoiceField(
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/tenancy/tenants/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
enforce_unique = forms.NullBooleanField(
|
|
|
|
|
required=False,
|
|
|
|
@@ -102,11 +104,14 @@ class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
label='Search'
|
|
|
|
|
)
|
|
|
|
|
tenant = FilterChoiceField(
|
|
|
|
|
queryset=Tenant.objects.annotate(
|
|
|
|
|
filter_count=Count('vrfs')
|
|
|
|
|
),
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/tenancy/tenants/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -139,12 +144,8 @@ class RIRFilterForm(BootstrapMixin, forms.Form):
|
|
|
|
|
is_private = forms.NullBooleanField(
|
|
|
|
|
required=False,
|
|
|
|
|
label='Private',
|
|
|
|
|
widget=forms.Select(
|
|
|
|
|
choices=[
|
|
|
|
|
('', '---------'),
|
|
|
|
|
('True', 'Yes'),
|
|
|
|
|
('False', 'No'),
|
|
|
|
|
]
|
|
|
|
|
widget=StaticSelect2(
|
|
|
|
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
@@ -168,6 +169,11 @@ class AggregateForm(BootstrapMixin, CustomFieldForm):
|
|
|
|
|
'rir': "Regional Internet Registry responsible for this prefix",
|
|
|
|
|
'date_added': "Format: YYYY-MM-DD",
|
|
|
|
|
}
|
|
|
|
|
widgets = {
|
|
|
|
|
'rir': APISelect(
|
|
|
|
|
api_url="/api/ipam/rirs/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AggregateCSVForm(forms.ModelForm):
|
|
|
|
@@ -193,7 +199,10 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|
|
|
|
rir = forms.ModelChoiceField(
|
|
|
|
|
queryset=RIR.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='RIR'
|
|
|
|
|
label='RIR',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/rirs/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
date_added = forms.DateField(
|
|
|
|
|
required=False
|
|
|
|
@@ -218,12 +227,17 @@ class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
family = forms.ChoiceField(
|
|
|
|
|
required=False,
|
|
|
|
|
choices=IP_FAMILY_CHOICES,
|
|
|
|
|
label='Address family'
|
|
|
|
|
label='Address family',
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
rir = FilterChoiceField(
|
|
|
|
|
queryset=RIR.objects.annotate(filter_count=Count('aggregates')),
|
|
|
|
|
queryset=RIR.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
label='RIR'
|
|
|
|
|
label='RIR',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/rirs/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -261,9 +275,13 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='Site',
|
|
|
|
|
widget=forms.Select(
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
filter_for={
|
|
|
|
|
'vlan_group': 'site_id',
|
|
|
|
|
'vlan': 'site_id',
|
|
|
|
|
},
|
|
|
|
|
attrs={
|
|
|
|
|
'filter-for': 'vlan_group',
|
|
|
|
|
'nullable': 'true',
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
@@ -276,9 +294,11 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
required=False,
|
|
|
|
|
label='VLAN group',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
|
|
|
|
api_url='/api/ipam/vlan-groups/',
|
|
|
|
|
filter_for={
|
|
|
|
|
'vlan': 'group_id'
|
|
|
|
|
},
|
|
|
|
|
attrs={
|
|
|
|
|
'filter-for': 'vlan',
|
|
|
|
|
'nullable': 'true',
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
@@ -292,7 +312,7 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
required=False,
|
|
|
|
|
label='VLAN',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}',
|
|
|
|
|
api_url='/api/ipam/vlans/',
|
|
|
|
|
display_field='display_name'
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
@@ -304,6 +324,15 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant',
|
|
|
|
|
'tags',
|
|
|
|
|
]
|
|
|
|
|
widgets = {
|
|
|
|
|
'vrf': APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
),
|
|
|
|
|
'status': StaticSelect2(),
|
|
|
|
|
'role': APISelect(
|
|
|
|
|
api_url="/api/ipam/roles/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
|
|
|
@@ -415,12 +444,18 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|
|
|
|
)
|
|
|
|
|
site = forms.ModelChoiceField(
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
vrf = forms.ModelChoiceField(
|
|
|
|
|
queryset=VRF.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='VRF'
|
|
|
|
|
label='VRF',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
prefix_length = forms.IntegerField(
|
|
|
|
|
min_value=1,
|
|
|
|
@@ -429,15 +464,22 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|
|
|
|
)
|
|
|
|
|
tenant = forms.ModelChoiceField(
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/tenancy/tenants/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
status = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(PREFIX_STATUS_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
role = forms.ModelChoiceField(
|
|
|
|
|
queryset=Role.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/roles/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
is_pool = forms.NullBooleanField(
|
|
|
|
|
required=False,
|
|
|
|
@@ -473,47 +515,60 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
family = forms.ChoiceField(
|
|
|
|
|
required=False,
|
|
|
|
|
choices=IP_FAMILY_CHOICES,
|
|
|
|
|
label='Address family'
|
|
|
|
|
label='Address family',
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
mask_length = forms.ChoiceField(
|
|
|
|
|
required=False,
|
|
|
|
|
choices=PREFIX_MASK_LENGTH_CHOICES,
|
|
|
|
|
label='Mask length'
|
|
|
|
|
label='Mask length',
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
vrf = FilterChoiceField(
|
|
|
|
|
queryset=VRF.objects.annotate(
|
|
|
|
|
filter_count=Count('prefixes')
|
|
|
|
|
),
|
|
|
|
|
queryset=VRF.objects.all(),
|
|
|
|
|
to_field_name='rd',
|
|
|
|
|
label='VRF',
|
|
|
|
|
null_label='-- Global --'
|
|
|
|
|
null_label='-- Global --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/vrfs/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
tenant = FilterChoiceField(
|
|
|
|
|
queryset=Tenant.objects.annotate(
|
|
|
|
|
filter_count=Count('prefixes')
|
|
|
|
|
),
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/tenancy/tenants/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
status = AnnotatedMultipleChoiceField(
|
|
|
|
|
)
|
|
|
|
|
status = forms.MultipleChoiceField(
|
|
|
|
|
choices=PREFIX_STATUS_CHOICES,
|
|
|
|
|
annotate=Prefix.objects.all(),
|
|
|
|
|
annotate_field='status',
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2Multiple()
|
|
|
|
|
)
|
|
|
|
|
site = FilterChoiceField(
|
|
|
|
|
queryset=Site.objects.annotate(
|
|
|
|
|
filter_count=Count('prefixes')
|
|
|
|
|
),
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
role = FilterChoiceField(
|
|
|
|
|
queryset=Role.objects.annotate(
|
|
|
|
|
filter_count=Count('prefixes')
|
|
|
|
|
),
|
|
|
|
|
queryset=Role.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/roles/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
expand = forms.BooleanField(
|
|
|
|
|
required=False,
|
|
|
|
@@ -534,9 +589,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='Site',
|
|
|
|
|
widget=forms.Select(
|
|
|
|
|
attrs={
|
|
|
|
|
'filter-for': 'nat_rack'
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
filter_for={
|
|
|
|
|
'nat_rack': 'site_id',
|
|
|
|
|
'nat_device': 'site_id'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
@@ -548,10 +605,12 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|
|
|
|
required=False,
|
|
|
|
|
label='Rack',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/dcim/racks/?site_id={{nat_site}}',
|
|
|
|
|
api_url='/api/dcim/racks/',
|
|
|
|
|
display_field='display_name',
|
|
|
|
|
filter_for={
|
|
|
|
|
'nat_device': 'rack_id'
|
|
|
|
|
},
|
|
|
|
|
attrs={
|
|
|
|
|
'filter-for': 'nat_device',
|
|
|
|
|
'nullable': 'true'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
@@ -565,9 +624,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|
|
|
|
required=False,
|
|
|
|
|
label='Device',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/dcim/devices/?site_id={{nat_site}}&rack_id={{nat_rack}}',
|
|
|
|
|
api_url='/api/dcim/devices/',
|
|
|
|
|
display_field='display_name',
|
|
|
|
|
attrs={'filter-for': 'nat_inside'}
|
|
|
|
|
filter_for={
|
|
|
|
|
'nat_inside': 'device_id'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
nat_inside = ChainedModelChoiceField(
|
|
|
|
@@ -578,20 +639,10 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|
|
|
|
required=False,
|
|
|
|
|
label='IP Address',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}',
|
|
|
|
|
api_url='/api/ipam/ip-addresses/',
|
|
|
|
|
display_field='address'
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
livesearch = forms.CharField(
|
|
|
|
|
required=False,
|
|
|
|
|
label='Search',
|
|
|
|
|
widget=Livesearch(
|
|
|
|
|
query_key='q',
|
|
|
|
|
query_url='ipam-api:ipaddress-list',
|
|
|
|
|
field_to_update='nat_inside',
|
|
|
|
|
obj_label='address'
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
primary_for_parent = forms.BooleanField(
|
|
|
|
|
required=False,
|
|
|
|
|
label='Make this the primary IP for the device/VM'
|
|
|
|
@@ -606,6 +657,13 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|
|
|
|
'address', 'vrf', 'status', 'role', 'description', 'interface', 'primary_for_parent', 'nat_site',
|
|
|
|
|
'nat_rack', 'nat_inside', 'tenant_group', 'tenant', 'tags',
|
|
|
|
|
]
|
|
|
|
|
widgets = {
|
|
|
|
|
'status': StaticSelect2(),
|
|
|
|
|
'role': StaticSelect2(),
|
|
|
|
|
'vrf': APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
|
|
|
@@ -685,6 +743,13 @@ class IPAddressBulkAddForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
fields = [
|
|
|
|
|
'address', 'vrf', 'status', 'role', 'description', 'tenant_group', 'tenant',
|
|
|
|
|
]
|
|
|
|
|
widgets = {
|
|
|
|
|
'status': StaticSelect2(),
|
|
|
|
|
'role': StaticSelect2(),
|
|
|
|
|
'vrf': APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
@@ -822,7 +887,10 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|
|
|
|
vrf = forms.ModelChoiceField(
|
|
|
|
|
queryset=VRF.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='VRF'
|
|
|
|
|
label='VRF',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
mask_length = forms.IntegerField(
|
|
|
|
|
min_value=1,
|
|
|
|
@@ -831,15 +899,20 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|
|
|
|
)
|
|
|
|
|
tenant = forms.ModelChoiceField(
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/tenancy/tenants/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
status = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(IPADDRESS_STATUS_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
role = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(IPADDRESS_ROLE_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
description = forms.CharField(
|
|
|
|
|
max_length=100, required=False
|
|
|
|
@@ -856,7 +929,10 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
|
|
|
|
|
queryset=VRF.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
label='VRF',
|
|
|
|
|
empty_label='Global'
|
|
|
|
|
empty_label='Global',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/vrfs/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
address = forms.CharField(
|
|
|
|
|
label='IP Address'
|
|
|
|
@@ -881,39 +957,45 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
family = forms.ChoiceField(
|
|
|
|
|
required=False,
|
|
|
|
|
choices=IP_FAMILY_CHOICES,
|
|
|
|
|
label='Address family'
|
|
|
|
|
label='Address family',
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
mask_length = forms.ChoiceField(
|
|
|
|
|
required=False,
|
|
|
|
|
choices=IPADDRESS_MASK_LENGTH_CHOICES,
|
|
|
|
|
label='Mask length'
|
|
|
|
|
label='Mask length',
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
vrf = FilterChoiceField(
|
|
|
|
|
queryset=VRF.objects.annotate(
|
|
|
|
|
filter_count=Count('ip_addresses')
|
|
|
|
|
),
|
|
|
|
|
queryset=VRF.objects.all(),
|
|
|
|
|
to_field_name='rd',
|
|
|
|
|
label='VRF',
|
|
|
|
|
null_label='-- Global --'
|
|
|
|
|
null_label='-- Global --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/vrfs/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
tenant = FilterChoiceField(
|
|
|
|
|
queryset=Tenant.objects.annotate(
|
|
|
|
|
filter_count=Count('ip_addresses')
|
|
|
|
|
),
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/tenancy/tenants/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
status = AnnotatedMultipleChoiceField(
|
|
|
|
|
)
|
|
|
|
|
status = forms.MultipleChoiceField(
|
|
|
|
|
choices=IPADDRESS_STATUS_CHOICES,
|
|
|
|
|
annotate=IPAddress.objects.all(),
|
|
|
|
|
annotate_field='status',
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2Multiple()
|
|
|
|
|
)
|
|
|
|
|
role = AnnotatedMultipleChoiceField(
|
|
|
|
|
role = forms.MultipleChoiceField(
|
|
|
|
|
choices=IPADDRESS_ROLE_CHOICES,
|
|
|
|
|
annotate=IPAddress.objects.all(),
|
|
|
|
|
annotate_field='role',
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2Multiple()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -929,6 +1011,11 @@ class VLANGroupForm(BootstrapMixin, forms.ModelForm):
|
|
|
|
|
fields = [
|
|
|
|
|
'site', 'name', 'slug',
|
|
|
|
|
]
|
|
|
|
|
widgets = {
|
|
|
|
|
'site': APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VLANGroupCSVForm(forms.ModelForm):
|
|
|
|
@@ -953,11 +1040,14 @@ class VLANGroupCSVForm(forms.ModelForm):
|
|
|
|
|
|
|
|
|
|
class VLANGroupFilterForm(BootstrapMixin, forms.Form):
|
|
|
|
|
site = FilterChoiceField(
|
|
|
|
|
queryset=Site.objects.annotate(
|
|
|
|
|
filter_count=Count('vlan_groups')
|
|
|
|
|
),
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- Global --'
|
|
|
|
|
null_label='-- Global --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -969,9 +1059,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
site = forms.ModelChoiceField(
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
required=False,
|
|
|
|
|
widget=forms.Select(
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
filter_for={
|
|
|
|
|
'group': 'site_id'
|
|
|
|
|
},
|
|
|
|
|
attrs={
|
|
|
|
|
'filter-for': 'group',
|
|
|
|
|
'nullable': 'true',
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
@@ -984,7 +1077,7 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
required=False,
|
|
|
|
|
label='Group',
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
|
|
|
|
api_url='/api/ipam/vlan-groups/',
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
tags = TagField(required=False)
|
|
|
|
@@ -1002,6 +1095,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|
|
|
|
'status': "Operational status of this VLAN",
|
|
|
|
|
'role': "The primary function of this VLAN",
|
|
|
|
|
}
|
|
|
|
|
widgets = {
|
|
|
|
|
'status': StaticSelect2(),
|
|
|
|
|
'role': APISelect(
|
|
|
|
|
api_url="/api/ipam/roles/"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VLANCSVForm(forms.ModelForm):
|
|
|
|
@@ -1077,23 +1176,36 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|
|
|
|
)
|
|
|
|
|
site = forms.ModelChoiceField(
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/dcim/sites/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
group = forms.ModelChoiceField(
|
|
|
|
|
queryset=VLANGroup.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/vlan-groups/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
tenant = forms.ModelChoiceField(
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/tenancy/tenants/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
status = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(VLAN_STATUS_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
role = forms.ModelChoiceField(
|
|
|
|
|
queryset=Role.objects.all(),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=APISelect(
|
|
|
|
|
api_url="/api/ipam/roles/"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
description = forms.CharField(
|
|
|
|
|
max_length=100,
|
|
|
|
@@ -1113,38 +1225,48 @@ class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
label='Search'
|
|
|
|
|
)
|
|
|
|
|
site = FilterChoiceField(
|
|
|
|
|
queryset=Site.objects.annotate(
|
|
|
|
|
filter_count=Count('vlans')
|
|
|
|
|
),
|
|
|
|
|
queryset=Site.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- Global --'
|
|
|
|
|
null_label='-- Global --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
group_id = FilterChoiceField(
|
|
|
|
|
queryset=VLANGroup.objects.annotate(
|
|
|
|
|
filter_count=Count('vlans')
|
|
|
|
|
),
|
|
|
|
|
queryset=VLANGroup.objects.all(),
|
|
|
|
|
label='VLAN group',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/vlan-groups/",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
tenant = FilterChoiceField(
|
|
|
|
|
queryset=Tenant.objects.annotate(
|
|
|
|
|
filter_count=Count('vlans')
|
|
|
|
|
),
|
|
|
|
|
queryset=Tenant.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/tenancy/tenants/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
status = AnnotatedMultipleChoiceField(
|
|
|
|
|
)
|
|
|
|
|
status = forms.MultipleChoiceField(
|
|
|
|
|
choices=VLAN_STATUS_CHOICES,
|
|
|
|
|
annotate=VLAN.objects.all(),
|
|
|
|
|
annotate_field='status',
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2Multiple()
|
|
|
|
|
)
|
|
|
|
|
role = FilterChoiceField(
|
|
|
|
|
queryset=Role.objects.annotate(
|
|
|
|
|
filter_count=Count('vlans')
|
|
|
|
|
),
|
|
|
|
|
queryset=Role.objects.all(),
|
|
|
|
|
to_field_name='slug',
|
|
|
|
|
null_label='-- None --'
|
|
|
|
|
null_label='-- None --',
|
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
|
api_url="/api/ipam/roles/",
|
|
|
|
|
value_field="slug",
|
|
|
|
|
null_option=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1166,6 +1288,10 @@ class ServiceForm(BootstrapMixin, CustomFieldForm):
|
|
|
|
|
'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be "
|
|
|
|
|
"reachable via all IPs assigned to the device.",
|
|
|
|
|
}
|
|
|
|
|
widgets = {
|
|
|
|
|
'protocol': StaticSelect2(),
|
|
|
|
|
'ipaddresses': StaticSelect2Multiple(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
@@ -1192,10 +1318,11 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|
|
|
|
)
|
|
|
|
|
protocol = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2Multiple()
|
|
|
|
|
)
|
|
|
|
|
port = forms.IntegerField(
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1206,7 +1333,8 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|
|
|
|
)
|
|
|
|
|
protocol = forms.ChoiceField(
|
|
|
|
|
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
|
|
|
|
required=False
|
|
|
|
|
required=False,
|
|
|
|
|
widget=StaticSelect2()
|
|
|
|
|
)
|
|
|
|
|
port = forms.IntegerField(
|
|
|
|
|
validators=[
|
|
|
|
@@ -1222,5 +1350,5 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
nullable_fields = [
|
|
|
|
|
'site', 'group', 'tenant', 'role', 'description',
|
|
|
|
|
'site', 'tenant', 'role', 'description',
|
|
|
|
|
]
|
|
|
|
|