Exemple #1
0
class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    vrf = DynamicModelChoiceField(queryset=VRF.objects.all(),
                                  required=False,
                                  label='VRF')
    site = DynamicModelChoiceField(queryset=Site.objects.all(),
                                   required=False,
                                   widget=APISelect(filter_for={
                                       'vlan_group': 'site_id',
                                       'vlan': 'site_id',
                                   },
                                                    attrs={
                                                        'nullable': 'true',
                                                    }))
    vlan_group = DynamicModelChoiceField(queryset=VLANGroup.objects.all(),
                                         required=False,
                                         label='VLAN group',
                                         widget=APISelect(
                                             filter_for={'vlan': 'group_id'},
                                             attrs={
                                                 'nullable': 'true',
                                             }))
    vlan = DynamicModelChoiceField(
        queryset=VLAN.objects.all(),
        required=False,
        label='VLAN',
        widget=APISelect(display_field='display_name'))
    role = DynamicModelChoiceField(queryset=Role.objects.all(), required=False)
    tags = TagField(required=False)

    class Meta:
        model = Prefix
        fields = [
            'prefix',
            'vrf',
            'site',
            'vlan',
            'status',
            'role',
            'is_pool',
            'description',
            'tenant_group',
            'tenant',
            'tags',
        ]
        widgets = {
            'status': StaticSelect2(),
        }

    def __init__(self, *args, **kwargs):

        # Initialize helper selectors
        instance = kwargs.get('instance')
        initial = kwargs.get('initial', {}).copy()
        if instance and instance.vlan is not None:
            initial['vlan_group'] = instance.vlan.group
        kwargs['initial'] = initial

        super().__init__(*args, **kwargs)

        self.fields['vrf'].empty_label = 'Global'
Exemple #2
0
class ProviderForm(BootstrapMixin, CustomFieldModelForm):
    slug = SlugField()
    comments = CommentField()
    tags = TagField(required=False)

    class Meta:
        model = Provider
        fields = [
            'name',
            'slug',
            'asn',
            'account',
            'portal_url',
            'noc_contact',
            'admin_contact',
            'comments',
            'tags',
        ]
        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",
        }
Exemple #3
0
class IPAddressBulkAddForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    vrf = DynamicModelChoiceField(queryset=VRF.objects.all(),
                                  required=False,
                                  label='VRF')
    tags = TagField(required=False)

    class Meta:
        model = IPAddress
        fields = [
            'address',
            'vrf',
            'status',
            'role',
            'dns_name',
            'description',
            'tenant_group',
            'tenant',
            'tags',
        ]
        widgets = {
            'status': StaticSelect2(),
            'role': StaticSelect2(),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['vrf'].empty_label = 'Global'
Exemple #4
0
class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    provider = DynamicModelChoiceField(queryset=Provider.objects.all())
    type = DynamicModelChoiceField(queryset=CircuitType.objects.all())
    comments = CommentField()
    tags = TagField(required=False)

    class Meta:
        model = Circuit
        fields = [
            'cid',
            'type',
            'provider',
            'status',
            'install_date',
            'commit_rate',
            'description',
            'tenant_group',
            'tenant',
            'comments',
            'tags',
        ]
        help_texts = {
            'cid': "Unique circuit ID",
            'commit_rate': "Committed rate",
        }
        widgets = {
            'status': StaticSelect2(),
            'install_date': DatePicker(),
        }
Exemple #5
0
class SecretForm(BootstrapMixin, CustomFieldModelForm):
    device = DynamicModelChoiceField(
        queryset=Device.objects.all()
    )
    plaintext = forms.CharField(
        max_length=SECRET_PLAINTEXT_MAX_LENGTH,
        required=False,
        label='Plaintext',
        widget=forms.PasswordInput(
            attrs={
                'class': 'requires-session-key',
            }
        )
    )
    plaintext2 = forms.CharField(
        max_length=SECRET_PLAINTEXT_MAX_LENGTH,
        required=False,
        label='Plaintext (verify)',
        widget=forms.PasswordInput()
    )
    role = DynamicModelChoiceField(
        queryset=SecretRole.objects.all()
    )
    tags = TagField(
        required=False
    )

    class Meta:
        model = Secret
        fields = [
            'device', 'role', 'name', 'plaintext', 'plaintext2', 'tags',
        ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # A plaintext value is required when creating a new Secret
        if not self.instance.pk:
            self.fields['plaintext'].required = True

    def clean(self):

        # Verify that the provided plaintext values match
        if self.cleaned_data['plaintext'] != self.cleaned_data['plaintext2']:
            raise forms.ValidationError({
                'plaintext2': "The two given plaintext values do not match. Please check your input."
            })

        # Validate uniqueness
        if Secret.objects.filter(
            device=self.cleaned_data['device'],
            role=self.cleaned_data['role'],
            name=self.cleaned_data['name']
        ).exists():
            raise forms.ValidationError(
                "Each secret assigned to a device must have a unique combination of role and name"
            )
Exemple #6
0
class InterfaceCreateForm(BootstrapMixin, forms.Form):
    virtual_machine = forms.ModelChoiceField(
        queryset=VirtualMachine.objects.all(), widget=forms.HiddenInput())
    name_pattern = ExpandableNameField(label='Name')
    type = forms.ChoiceField(choices=VMInterfaceTypeChoices,
                             initial=VMInterfaceTypeChoices.TYPE_VIRTUAL,
                             widget=forms.HiddenInput())
    enabled = forms.BooleanField(required=False, initial=True)
    mtu = forms.IntegerField(required=False,
                             min_value=INTERFACE_MTU_MIN,
                             max_value=INTERFACE_MTU_MAX,
                             label='MTU')
    mac_address = forms.CharField(required=False, label='MAC Address')
    description = forms.CharField(max_length=100, required=False)
    mode = forms.ChoiceField(
        choices=add_blank_choice(InterfaceModeChoices),
        required=False,
        widget=StaticSelect2(),
    )
    untagged_vlan = DynamicModelChoiceField(queryset=VLAN.objects.all(),
                                            required=False,
                                            widget=APISelect(
                                                display_field='display_name',
                                                full=True,
                                                additional_query_params={
                                                    'site_id': 'null',
                                                },
                                            ))
    tagged_vlans = DynamicModelMultipleChoiceField(
        queryset=VLAN.objects.all(),
        required=False,
        widget=APISelectMultiple(
            display_field='display_name',
            full=True,
            additional_query_params={
                'site_id': 'null',
            },
        ))
    tags = TagField(required=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        virtual_machine = VirtualMachine.objects.get(
            pk=self.initial.get('virtual_machine')
            or self.data.get('virtual_machine'))

        site = getattr(virtual_machine.cluster, 'site', None)
        if site is not None:
            # Add current site to VLANs query params
            self.fields['untagged_vlan'].widget.add_additional_query_param(
                'site_id', site.pk)
            self.fields['tagged_vlans'].widget.add_additional_query_param(
                'site_id', site.pk)
Exemple #7
0
class TenantForm(BootstrapMixin, CustomFieldModelForm):
    slug = SlugField()
    group = DynamicModelChoiceField(queryset=TenantGroup.objects.all(),
                                    required=False)
    comments = CommentField()
    tags = TagField(required=False)

    class Meta:
        model = Tenant
        fields = (
            'name',
            'slug',
            'group',
            'description',
            'comments',
            'tags',
        )
Exemple #8
0
class ClusterForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    type = DynamicModelChoiceField(queryset=ClusterType.objects.all())
    group = DynamicModelChoiceField(queryset=ClusterGroup.objects.all(),
                                    required=False)
    site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False)
    comments = CommentField()
    tags = TagField(required=False)

    class Meta:
        model = Cluster
        fields = (
            'name',
            'type',
            'group',
            'tenant',
            'site',
            'comments',
            'tags',
        )
Exemple #9
0
class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    tags = TagField(required=False)

    class Meta:
        model = VRF
        fields = [
            'name',
            'rd',
            'enforce_unique',
            'description',
            'tenant_group',
            'tenant',
            'tags',
        ]
        labels = {
            'rd': "RD",
        }
        help_texts = {
            'rd': "Route distinguisher in any format",
        }
Exemple #10
0
class AggregateForm(BootstrapMixin, CustomFieldModelForm):
    rir = DynamicModelChoiceField(queryset=RIR.objects.all())
    tags = TagField(required=False)

    class Meta:
        model = Aggregate
        fields = [
            'prefix',
            'rir',
            'date_added',
            'description',
            'tags',
        ]
        help_texts = {
            'prefix': "IPv4 or IPv6 network",
            'rir': "Regional Internet Registry responsible for this prefix",
        }
        widgets = {
            'date_added': DatePicker(),
        }
Exemple #11
0
class ServiceForm(BootstrapMixin, CustomFieldModelForm):
    port = forms.IntegerField(min_value=SERVICE_PORT_MIN,
                              max_value=SERVICE_PORT_MAX)
    tags = TagField(required=False)

    class Meta:
        model = Service
        fields = [
            'name',
            'protocol',
            'port',
            'ipaddresses',
            'description',
            'tags',
        ]
        help_texts = {
            '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)

        # Limit IP address choices to those assigned to interfaces of the parent device/VM
        if self.instance.device:
            vc_interface_ids = [
                i['id']
                for i in self.instance.device.vc_interfaces.values('id')
            ]
            self.fields['ipaddresses'].queryset = IPAddress.objects.filter(
                interface_id__in=vc_interface_ids)
        elif self.instance.virtual_machine:
            self.fields['ipaddresses'].queryset = IPAddress.objects.filter(
                interface__virtual_machine=self.instance.virtual_machine)
        else:
            self.fields['ipaddresses'].choices = []
Exemple #12
0
class VLANForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    site = DynamicModelChoiceField(queryset=Site.objects.all(),
                                   required=False,
                                   widget=APISelect(
                                       filter_for={'group': 'site_id'},
                                       attrs={
                                           'nullable': 'true',
                                       }))
    group = DynamicModelChoiceField(queryset=VLANGroup.objects.all(),
                                    required=False)
    role = DynamicModelChoiceField(queryset=Role.objects.all(), required=False)
    tags = TagField(required=False)

    class Meta:
        model = VLAN
        fields = [
            'site',
            'group',
            'vid',
            'name',
            'status',
            'role',
            'description',
            'tenant_group',
            'tenant',
            'tags',
        ]
        help_texts = {
            'site': "Leave blank if this VLAN spans multiple sites",
            'group': "VLAN group (optional)",
            'vid': "Configured VLAN ID",
            'name': "Configured VLAN name",
            'status': "Operational status of this VLAN",
            'role': "The primary function of this VLAN",
        }
        widgets = {
            'status': StaticSelect2(),
        }
Exemple #13
0
class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm,
                    CustomFieldModelForm):
    interface = forms.ModelChoiceField(queryset=Interface.objects.all(),
                                       required=False)
    vrf = DynamicModelChoiceField(queryset=VRF.objects.all(),
                                  required=False,
                                  label='VRF')
    nat_site = DynamicModelChoiceField(
        queryset=Site.objects.all(),
        required=False,
        label='Site',
        widget=APISelect(filter_for={
            'nat_rack': 'site_id',
            'nat_device': 'site_id'
        }))
    nat_rack = DynamicModelChoiceField(
        queryset=Rack.objects.all(),
        required=False,
        label='Rack',
        widget=APISelect(display_field='display_name',
                         filter_for={'nat_device': 'rack_id'},
                         attrs={'nullable': 'true'}))
    nat_device = DynamicModelChoiceField(
        queryset=Device.objects.all(),
        required=False,
        label='Device',
        widget=APISelect(display_field='display_name',
                         filter_for={'nat_inside': 'device_id'}))
    nat_vrf = DynamicModelChoiceField(
        queryset=VRF.objects.all(),
        required=False,
        label='VRF',
        widget=APISelect(filter_for={'nat_inside': 'vrf_id'}))
    nat_inside = DynamicModelChoiceField(
        queryset=IPAddress.objects.all(),
        required=False,
        label='IP Address',
        widget=APISelect(display_field='address'))
    primary_for_parent = forms.BooleanField(
        required=False, label='Make this the primary IP for the device/VM')
    tags = TagField(required=False)

    class Meta:
        model = IPAddress
        fields = [
            'address',
            'vrf',
            'status',
            'role',
            'dns_name',
            'description',
            'interface',
            'primary_for_parent',
            'nat_site',
            'nat_rack',
            'nat_inside',
            'tenant_group',
            'tenant',
            'tags',
        ]
        widgets = {
            'status': StaticSelect2(),
            'role': StaticSelect2(),
        }

    def __init__(self, *args, **kwargs):

        # Initialize helper selectors
        instance = kwargs.get('instance')
        initial = kwargs.get('initial', {}).copy()
        if instance and instance.nat_inside and instance.nat_inside.device is not None:
            initial['nat_site'] = instance.nat_inside.device.site
            initial['nat_rack'] = instance.nat_inside.device.rack
            initial['nat_device'] = instance.nat_inside.device
        kwargs['initial'] = initial

        super().__init__(*args, **kwargs)

        self.fields['vrf'].empty_label = 'Global'

        # Limit interface selections to those belonging to the parent device/VM
        if self.instance and self.instance.interface:
            self.fields['interface'].queryset = Interface.objects.filter(
                device=self.instance.interface.device,
                virtual_machine=self.instance.interface.virtual_machine
            ).prefetch_related(
                'device__primary_ip4',
                'device__primary_ip6',
                'virtual_machine__primary_ip4',
                'virtual_machine__primary_ip6',
            )  # We prefetch the primary address fields to ensure cache invalidation does not balk on the save()
        else:
            self.fields['interface'].choices = []

        # Initialize primary_for_parent if IP address is already assigned
        if self.instance.pk and self.instance.interface is not None:
            parent = self.instance.interface.parent
            if (self.instance.address.version == 4
                    and parent.primary_ip4_id == self.instance.pk
                    or self.instance.address.version == 6
                    and parent.primary_ip6_id == self.instance.pk):
                self.initial['primary_for_parent'] = True

    def clean(self):
        super().clean()

        # Primary IP assignment is only available if an interface has been assigned.
        if self.cleaned_data.get('primary_for_parent'
                                 ) and not self.cleaned_data.get('interface'):
            self.add_error(
                'primary_for_parent',
                "Only IP addresses assigned to an interface can be designated as primary IPs."
            )

    def save(self, *args, **kwargs):

        ipaddress = super().save(*args, **kwargs)

        # Assign/clear this IPAddress as the primary for the associated Device/VirtualMachine.
        if self.cleaned_data['primary_for_parent']:
            parent = self.cleaned_data['interface'].parent
            if ipaddress.address.version == 4:
                parent.primary_ip4 = ipaddress
            else:
                parent.primary_ip6 = ipaddress
            parent.save()
        elif self.cleaned_data['interface']:
            parent = self.cleaned_data['interface'].parent
            if ipaddress.address.version == 4 and parent.primary_ip4 == ipaddress:
                parent.primary_ip4 = None
                parent.save()
            elif ipaddress.address.version == 6 and parent.primary_ip6 == ipaddress:
                parent.primary_ip6 = None
                parent.save()

        return ipaddress
Exemple #14
0
class InterfaceForm(BootstrapMixin, forms.ModelForm):
    untagged_vlan = DynamicModelChoiceField(queryset=VLAN.objects.all(),
                                            required=False,
                                            widget=APISelect(
                                                display_field='display_name',
                                                full=True,
                                                additional_query_params={
                                                    'site_id': 'null',
                                                },
                                            ))
    tagged_vlans = DynamicModelMultipleChoiceField(
        queryset=VLAN.objects.all(),
        required=False,
        widget=APISelectMultiple(
            display_field='display_name',
            full=True,
            additional_query_params={
                'site_id': 'null',
            },
        ))
    tags = TagField(required=False)

    class Meta:
        model = Interface
        fields = [
            'virtual_machine',
            'name',
            'type',
            'enabled',
            'mac_address',
            'mtu',
            'description',
            'mode',
            'tags',
            'untagged_vlan',
            'tagged_vlans',
        ]
        widgets = {
            'virtual_machine': forms.HiddenInput(),
            'type': forms.HiddenInput(),
            'mode': StaticSelect2()
        }
        labels = {
            'mode': '802.1Q Mode',
        }
        help_texts = {
            'mode': INTERFACE_MODE_HELP_TEXT,
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Add current site to VLANs query params
        site = getattr(self.instance.parent, 'site', None)
        if site is not None:
            # Add current site to VLANs query params
            self.fields['untagged_vlan'].widget.add_additional_query_param(
                'site_id', site.pk)
            self.fields['tagged_vlans'].widget.add_additional_query_param(
                'site_id', site.pk)

    def clean(self):
        super().clean()

        # Validate VLAN assignments
        tagged_vlans = self.cleaned_data['tagged_vlans']

        # Untagged interfaces cannot be assigned tagged VLANs
        if self.cleaned_data[
                'mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans:
            raise forms.ValidationError({
                'mode':
                "An access interface cannot have tagged VLANs assigned."
            })

        # Remove all tagged VLAN assignments from "tagged all" interfaces
        elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
            self.cleaned_data['tagged_vlans'] = []
Exemple #15
0
class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
    cluster_group = DynamicModelChoiceField(
        queryset=ClusterGroup.objects.all(),
        required=False,
        widget=APISelect(filter_for={
            "cluster": "group_id",
        },
                         attrs={
                             'nullable': 'true',
                         }))
    cluster = DynamicModelChoiceField(queryset=Cluster.objects.all())
    role = DynamicModelChoiceField(
        queryset=DeviceRole.objects.all(),
        required=False,
        widget=APISelect(additional_query_params={"vm_role": "True"}))
    platform = DynamicModelChoiceField(queryset=Platform.objects.all(),
                                       required=False)
    tags = TagField(required=False)
    local_context_data = JSONField(required=False, label='')

    class Meta:
        model = VirtualMachine
        fields = [
            'name',
            'status',
            'cluster_group',
            'cluster',
            'role',
            'tenant_group',
            'tenant',
            'platform',
            'primary_ip4',
            'primary_ip6',
            'vcpus',
            'memory',
            'disk',
            'comments',
            'tags',
            'local_context_data',
        ]
        help_texts = {
            'local_context_data':
            "Local config context data overwrites all sources contexts in the final rendered "
            "config context",
        }
        widgets = {
            "status": StaticSelect2(),
            'primary_ip4': StaticSelect2(),
            'primary_ip6': StaticSelect2(),
        }

    def __init__(self, *args, **kwargs):

        # Initialize helper selector
        instance = kwargs.get('instance')
        if instance.pk and instance.cluster is not None:
            initial = kwargs.get('initial', {}).copy()
            initial['cluster_group'] = instance.cluster.group
            kwargs['initial'] = initial

        super().__init__(*args, **kwargs)

        if self.instance.pk:

            # Compile list of choices for primary IPv4 and IPv6 addresses
            for family in [4, 6]:
                ip_choices = [(None, '---------')]
                # Collect interface IPs
                interface_ips = IPAddress.objects.prefetch_related(
                    'interface').filter(
                        address__family=family,
                        interface__virtual_machine=self.instance)
                if interface_ips:
                    ip_choices.append(('Interface IPs', [
                        (ip.id, '{} ({})'.format(ip.address, ip.interface))
                        for ip in interface_ips
                    ]))
                # Collect NAT IPs
                nat_ips = IPAddress.objects.prefetch_related(
                    'nat_inside').filter(
                        address__family=family,
                        nat_inside__interface__virtual_machine=self.instance)
                if nat_ips:
                    ip_choices.append(('NAT IPs', [
                        (ip.id, '{} ({})'.format(ip.address,
                                                 ip.nat_inside.address))
                        for ip in nat_ips
                    ]))
                self.fields['primary_ip{}'.format(family)].choices = ip_choices

        else:

            # An object that doesn't exist yet can't have any IPs assigned to it
            self.fields['primary_ip4'].choices = []
            self.fields['primary_ip4'].widget.attrs['readonly'] = True
            self.fields['primary_ip6'].choices = []
            self.fields['primary_ip6'].widget.attrs['readonly'] = True