class RouterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): pk = DynamicModelMultipleChoiceField(queryset=Router.objects.all(), widget=forms.MultipleHiddenInput) local_autonomous_system = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) platform = DynamicModelChoiceField(required=False, queryset=Platform.objects.all()) encrypt_passwords = forms.NullBooleanField(required=False, widget=CustomNullBooleanSelect) poll_bgp_sessions_state = forms.NullBooleanField( required=False, widget=CustomNullBooleanSelect, label="Poll BGP sessions state") configuration_template = DynamicModelChoiceField( required=False, queryset=Configuration.objects.all()) device_state = forms.ChoiceField( required=False, choices=add_blank_choice(DeviceState.choices), widget=StaticSelect, ) comments = CommentField(widget=SmallTextarea) class Meta: nullable_fields = ["comments"]
class ConnectionBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): pk = DynamicModelMultipleChoiceField(queryset=Connection.objects.all(), widget=forms.MultipleHiddenInput) state = forms.ChoiceField( required=False, choices=add_blank_choice(ConnectionState.choices), widget=StaticSelect, ) internet_exchange_point = DynamicModelChoiceField( required=False, queryset=InternetExchange.objects.all(), help_text="IXP to which this connection connects", ) router = DynamicModelChoiceField( required=False, queryset=Router.objects.all(), help_text="Router on which this connection is setup", ) config_context = JSONField(required=False, label="Config context", widget=SmallTextarea) class Meta: model = Connection fields = ("state", "internet_exchange_point", "router", "config_context") nullable_fields = ("router", )
class InternetExchangePeeringSessionForm(BootstrapMixin, forms.ModelForm): autonomous_system = DynamicModelChoiceField( queryset=AutonomousSystem.objects.defer("prefixes")) internet_exchange = DynamicModelChoiceField( required=False, queryset=InternetExchange.objects.all(), label="IXP") ixp_connection = DynamicModelChoiceField( queryset=Connection.objects.all(), query_params={"internet_exchange_point_id": "$internet_exchange"}, label="IXP connection", ) password = PasswordField(required=False, render_value=True) import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "export-policy"}, ) comments = CommentField() tags = TagField(required=False) class Meta: model = InternetExchangePeeringSession fields = ( "service_reference", "autonomous_system", "ixp_connection", "ip_address", "password", "multihop_ttl", "is_route_server", "enabled", "import_routing_policies", "export_routing_policies", "comments", "tags", ) help_texts = { "ip_address": "IPv6 or IPv4 address", "is_route_server": "Define if this session is with a route server", } def clean(self): cleaned_data = super().clean() # Make sure that routing policies are compatible (address family) for policy in (cleaned_data["import_routing_policies"] | cleaned_data["export_routing_policies"]): if (policy.address_family != IPFamily.ALL and policy.address_family != cleaned_data["ip_address"].version): raise ValidationError( f"Routing policy '{policy.name}' cannot be used for this session, address families mismatch." )
class RouterFilterForm(BootstrapMixin, forms.Form): model = Router q = forms.CharField(required=False, label="Search") local_autonomous_system_id = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) platform_id = DynamicModelMultipleChoiceField( required=False, queryset=Platform.objects.all(), to_field_name="pk", null_option="None", label="Platform", ) device_state = forms.MultipleChoiceField( required=False, choices=add_blank_choice(DeviceState.choices), widget=StaticSelect, ) encrypt_passwords = forms.NullBooleanField(required=False, widget=CustomNullBooleanSelect) configuration_template_id = DynamicModelMultipleChoiceField( required=False, queryset=Configuration.objects.all(), to_field_name="pk", null_option="None", label="Configuration", ) tag = TagFilterField(model)
class InternetExchangeForm(BootstrapMixin, forms.ModelForm): slug = SlugField( max_length=255, help_text= "Friendly unique shorthand used for URL and config. Warning: may result in change of operational state on a router if being used in the configuration.", ) local_autonomous_system = DynamicModelChoiceField( queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "export-policy"}, ) communities = DynamicModelMultipleChoiceField( required=False, queryset=Community.objects.all()) ixapi_endpoint = DynamicModelChoiceField(required=False, label="IX-API endpoint", queryset=IXAPI.objects.all()) comments = CommentField() tags = TagField(required=False) class Meta: model = InternetExchange fields = ( "name", "slug", "local_autonomous_system", "communities", "import_routing_policies", "export_routing_policies", "ixapi_endpoint", "comments", "tags", ) help_texts = {"name": "Full name of the Internet Exchange point"}
class DirectPeeringSessionFilterForm(BootstrapMixin, forms.Form): model = DirectPeeringSession q = forms.CharField(required=False, label="Search") local_autonomous_system_id = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, to_field_name="pk", label="Local AS", ) autonomous_system_id = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), to_field_name="pk", label="Autonomous system", ) bgp_group_id = DynamicModelMultipleChoiceField( required=False, queryset=BGPGroup.objects.all(), to_field_name="pk", null_option="None", label="BGP group", ) address_family = forms.ChoiceField(required=False, choices=IPFamily.choices, widget=StaticSelect) enabled = forms.NullBooleanField(required=False, widget=CustomNullBooleanSelect) relationship_id = DynamicModelMultipleChoiceField( required=False, queryset=Relationship.objects.all(), to_field_name="pk", null_option="None", label="Relationship", ) router_id = DynamicModelMultipleChoiceField( required=False, queryset=Router.objects.all(), to_field_name="pk", null_option="None", label="Router", ) tag = TagFilterField(model)
class AutonomousSystemEmailForm(BootstrapMixin, forms.Form): email = DynamicModelChoiceField(required=False, queryset=Email.objects.all()) recipient = forms.MultipleChoiceField(widget=StaticSelectMultiple, label="E-mail recipient") cc = forms.MultipleChoiceField(widget=StaticSelectMultiple, label="E-mail CC", required=False) subject = forms.CharField(label="E-mail subject") body = TextareaField(label="E-mail body")
class DirectPeeringSessionBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): pk = DynamicModelMultipleChoiceField( queryset=DirectPeeringSession.objects.all(), widget=forms.MultipleHiddenInput) local_autonomous_system = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) enabled = forms.NullBooleanField(required=False, label="Enable", widget=CustomNullBooleanSelect) relationship = DynamicModelChoiceField(required=False, queryset=Relationship.objects.all()) bgp_group = DynamicModelChoiceField(required=False, queryset=BGPGroup.objects.all(), label="BGP group") import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "export-policy"}, ) router = DynamicModelChoiceField(required=False, queryset=Router.objects.all()) comments = CommentField() class Meta: nullable_fields = [ "import_routing_policies", "export_routing_policies", "router", "comments", ]
class ConnectionForm(BootstrapMixin, forms.ModelForm): state = forms.ChoiceField(choices=ConnectionState.choices, widget=StaticSelect) internet_exchange_point = DynamicModelChoiceField( required=False, queryset=InternetExchange.objects.all(), label="IXP", help_text="IXP to which this connection connects", ) router = DynamicModelChoiceField( required=False, queryset=Router.objects.all(), help_text="Router on which this connection is setup", ) config_context = JSONField(required=False, label="Config context", widget=SmallTextarea) comments = CommentField() tags = TagField(required=False) class Meta: model = Connection fields = ( "state", "vlan", "ipv6_address", "ipv4_address", "internet_exchange_point", "router", "interface", "description", "config_context", "comments", "tags", ) labels = { "vlan": "VLAN", "ipv6_address": "IPv6 address", "ipv4_address": "IPv4 address", }
class InternetExchangeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): pk = DynamicModelMultipleChoiceField( queryset=InternetExchange.objects.all(), widget=forms.MultipleHiddenInput) local_autonomous_system = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "export-policy"}, ) communities = DynamicModelMultipleChoiceField( required=False, queryset=Community.objects.all()) ixapi_endpoint = DynamicModelChoiceField(required=False, label="IX-API endpoint", queryset=IXAPI.objects.all()) comments = CommentField(widget=SmallTextarea) class Meta: nullable_fields = [ "import_routing_policies", "export_routing_policies", "communities", "ixapi_endpoint", "comments", ]
class InternetExchangeFilterForm(BootstrapMixin, forms.Form): model = InternetExchange q = forms.CharField(required=False, label="Search") local_autonomous_system_id = DynamicModelChoiceField( required=False, queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), to_field_name="pk", null_option="None", query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), to_field_name="pk", null_option="None", query_params={"type": "export-policy"}, ) tag = TagFilterField(model)
class RouterForm(BootstrapMixin, forms.ModelForm): netbox_device_id = forms.IntegerField(label="NetBox device", initial=0) platform = DynamicModelChoiceField(required=False, queryset=Platform.objects.all()) configuration_template = DynamicModelChoiceField( required=False, queryset=Configuration.objects.all(), label="Configuration", help_text="Template used to generate device configuration", ) local_autonomous_system = DynamicModelChoiceField( queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) config_context = JSONField(required=False, label="Config context", widget=SmallTextarea) napalm_username = forms.CharField(required=False, label="Username") napalm_password = PasswordField(required=False, render_value=True, label="Password") napalm_timeout = forms.IntegerField( required=False, label="Timeout", help_text="The maximum time to wait for a connection in seconds", ) napalm_args = JSONField( required=False, label="Optional arguments", help_text= "See NAPALM's <a href='http://napalm.readthedocs.io/en/latest/support/#optional-arguments'>documentation</a> for a complete list of optional arguments", widget=SmallTextarea, ) device_state = forms.ChoiceField( required=False, choices=add_blank_choice(DeviceState.choices), widget=StaticSelect, ) comments = CommentField() tags = TagField(required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if settings.NETBOX_API: choices = [] for device in NetBox().get_devices(): try: choices.append((device.id, device.display)) except AttributeError: # Fallback to hold API attribute choices.append((device.id, device.display_name)) self.fields["netbox_device_id"] = forms.ChoiceField( label="NetBox device", choices=[(0, "---------")] + choices, widget=StaticSelect, ) self.fields["netbox_device_id"].widget.attrs["class"] = " ".join([ self.fields["netbox_device_id"].widget.attrs.get("class", ""), "form-control", ]).strip() else: self.fields["netbox_device_id"].widget = forms.HiddenInput() class Meta: model = Router fields = ( "netbox_device_id", "use_netbox", "name", "hostname", "platform", "encrypt_passwords", "poll_bgp_sessions_state", "device_state", "configuration_template", "local_autonomous_system", "config_context", "napalm_username", "napalm_password", "napalm_timeout", "napalm_args", "comments", "tags", ) help_texts = { "hostname": "Router hostname (must be resolvable) or IP address" }
class DirectPeeringSessionForm(BootstrapMixin, forms.ModelForm): local_autonomous_system = DynamicModelChoiceField( queryset=AutonomousSystem.objects.defer("prefixes"), query_params={"affiliated": True}, label="Local AS", ) autonomous_system = DynamicModelChoiceField( queryset=AutonomousSystem.objects.defer("prefixes")) bgp_group = DynamicModelChoiceField(required=False, queryset=BGPGroup.objects.all(), label="BGP Group") relationship = DynamicModelChoiceField(queryset=Relationship.objects.all()) router = DynamicModelChoiceField( required=False, queryset=Router.objects.all(), help_text="Router on which this session is configured", ) import_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "import-policy"}, ) export_routing_policies = DynamicModelMultipleChoiceField( required=False, queryset=RoutingPolicy.objects.all(), query_params={"type": "export-policy"}, ) password = PasswordField(required=False, render_value=True) comments = CommentField() tags = TagField(required=False) class Meta: model = DirectPeeringSession fields = ( "service_reference", "local_autonomous_system", "local_ip_address", "autonomous_system", "bgp_group", "relationship", "ip_address", "password", "multihop_ttl", "enabled", "router", "import_routing_policies", "export_routing_policies", "comments", "tags", ) labels = { "local_ip_address": "Local IP Address", "ip_address": "IP Address" } help_texts = { "local_ip_address": "IPv6 or IPv4 address", "ip_address": "IPv6 or IPv4 address", "enabled": "Should this session be enabled?", } def clean(self): cleaned_data = super().clean() ip_src = cleaned_data["local_ip_address"] ip_dst = cleaned_data["ip_address"] # Make sure that both local qnd remote IP addresses belong in the same subnet if (cleaned_data["multihop_ttl"] == 1 and ip_src and (ip_src.network != ip_dst.network)): raise ValidationError( f"{ip_src} and {ip_dst} don't belong to the same subnet.") # Make sure that routing policies are compatible (address family) for policy in cleaned_data["import_routing_policies"].union( cleaned_data["export_routing_policies"]): if (policy.address_family != IPFamily.ALL and policy.address_family != ip_dst.version): raise ValidationError( f"Routing policy '{policy.name}' cannot be used for this session, address families mismatch." )