diff --git a/netbox_cmdb/netbox_cmdb/api/bgp/serializers.py b/netbox_cmdb/netbox_cmdb/api/bgp/serializers.py index 428bf43..4693417 100644 --- a/netbox_cmdb/netbox_cmdb/api/bgp/serializers.py +++ b/netbox_cmdb/netbox_cmdb/api/bgp/serializers.py @@ -1,13 +1,17 @@ from django.core.exceptions import ValidationError from django.db.models import Q from ipam.api.nested_serializers import NestedIPAddressSerializer -from netbox.api.serializers import WritableNestedSerializer from rest_framework import serializers -from rest_framework.serializers import IntegerField, ModelSerializer +from rest_framework.serializers import ( + IntegerField, + ModelSerializer, + SerializerMethodField, +) from tenancy.api.nested_serializers import NestedTenantSerializer -from netbox_cmdb.choices import AssetMonitoringStateChoices +from netbox.api.serializers import WritableNestedSerializer from netbox_cmdb.api.common_serializers import CommonDeviceSerializer +from netbox_cmdb.choices import AssetMonitoringStateChoices from netbox_cmdb.constants import BGP_MAX_ASN, BGP_MIN_ASN from netbox_cmdb.models.bgp import ( ASN, @@ -126,10 +130,15 @@ class DeviceBGPSessionSerializer(ModelSerializer): route_policy_in = RoutePolicySerializer(required=False, many=False, allow_null=True) route_policy_out = RoutePolicySerializer(required=False, many=False, allow_null=True) + display = SerializerMethodField(read_only=True) + class Meta: model = DeviceBGPSession fields = "__all__" + def get_display(self, obj): + return str(obj) + class CircuitSerializer(ModelSerializer): class Meta: @@ -141,6 +150,10 @@ class BGPSessionSerializer(ModelSerializer): peer_a = DeviceBGPSessionSerializer(many=False) peer_b = DeviceBGPSessionSerializer(many=False) tenant = NestedTenantSerializer(required=False, many=False) + display = SerializerMethodField(read_only=True) + + def get_display(self, obj): + return str(obj) def create(self, validated_data): peers_data = {} diff --git a/netbox_cmdb/netbox_cmdb/api/bgp/views.py b/netbox_cmdb/netbox_cmdb/api/bgp/views.py index 026aede..06617a1 100644 --- a/netbox_cmdb/netbox_cmdb/api/bgp/views.py +++ b/netbox_cmdb/netbox_cmdb/api/bgp/views.py @@ -2,12 +2,12 @@ from django.db import transaction from django_pglocks import advisory_lock from drf_yasg.utils import swagger_auto_schema -from netbox.api.viewsets.mixins import ObjectValidationMixin from rest_framework import status from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.views import APIView +from netbox.api.viewsets.mixins import ObjectValidationMixin from netbox_cmdb import filtersets from netbox_cmdb.api.bgp.serializers import ( AvailableAsnSerializer, @@ -15,10 +15,21 @@ BGPGlobalSerializer, BGPPeerGroupSerializer, BGPSessionSerializer, + DeviceBGPSessionSerializer, ) from netbox_cmdb.api.viewsets import CustomNetBoxModelViewSet -from netbox_cmdb.filtersets import ASNFilterSet, BGPSessionFilterSet -from netbox_cmdb.models.bgp import ASN, BGPGlobal, BGPPeerGroup, BGPSession +from netbox_cmdb.filtersets import ( + ASNFilterSet, + BGPSessionFilterSet, + DeviceBGPSessionFilterSet, +) +from netbox_cmdb.models.bgp import ( + ASN, + BGPGlobal, + BGPPeerGroup, + BGPSession, + DeviceBGPSession, +) class ASNViewSet(CustomNetBoxModelViewSet): @@ -96,6 +107,12 @@ class BGPSessionsViewSet(CustomNetBoxModelViewSet): filterset_class = BGPSessionFilterSet +class DeviceBGPSessionsViewSet(CustomNetBoxModelViewSet): + queryset = DeviceBGPSession.objects.all() + serializer_class = DeviceBGPSessionSerializer + filterset_class = DeviceBGPSessionFilterSet + + class BGPPeerGroupViewSet(CustomNetBoxModelViewSet): queryset = BGPPeerGroup.objects.all() serializer_class = BGPPeerGroupSerializer diff --git a/netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py b/netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py index 51e5119..68d02b9 100644 --- a/netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py +++ b/netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py @@ -1,10 +1,10 @@ """Route Policy serializers.""" from django.core.exceptions import ValidationError -from netbox.api.serializers import WritableNestedSerializer from rest_framework import serializers -from rest_framework.serializers import ModelSerializer +from rest_framework.serializers import ModelSerializer, SerializerMethodField +from netbox.api.serializers import WritableNestedSerializer from netbox_cmdb.api.bgp.serializers import AsnSerializer from netbox_cmdb.api.common_serializers import CommonDeviceSerializer from netbox_cmdb.models.bgp_community_list import BGPCommunityList @@ -68,12 +68,15 @@ class Meta: class WritableRoutePolicySerializer(ModelSerializer): device = CommonDeviceSerializer() - terms = RoutePolicyTermSerializer(many=True, source="route_policy_term") + display = SerializerMethodField(read_only=True) class Meta: model = RoutePolicy - fields = ["id", "name", "device", "description", "terms"] + fields = ["id", "name", "device", "description", "terms", "display"] + + def get_display(self, obj): + return obj.name def _validate_terms(self, terms_data): if len(terms_data) < 1: diff --git a/netbox_cmdb/netbox_cmdb/api/route_policy/views.py b/netbox_cmdb/netbox_cmdb/api/route_policy/views.py index ad83aea..bc976d8 100644 --- a/netbox_cmdb/netbox_cmdb/api/route_policy/views.py +++ b/netbox_cmdb/netbox_cmdb/api/route_policy/views.py @@ -1,18 +1,12 @@ """Route Policy views.""" -from netbox_cmdb import filtersets - from netbox_cmdb.api.route_policy.serializers import WritableRoutePolicySerializer from netbox_cmdb.api.viewsets import CustomNetBoxModelViewSet +from netbox_cmdb.filtersets import RoutePolicyFilterSet from netbox_cmdb.models.route_policy import RoutePolicy class RoutePolicyViewSet(CustomNetBoxModelViewSet): queryset = RoutePolicy.objects.all() serializer_class = WritableRoutePolicySerializer - filterset_fields = [ - "id", - "name", - "device__id", - "device__name", - ] + filtersets.device_location_filterset + filterset_class = RoutePolicyFilterSet diff --git a/netbox_cmdb/netbox_cmdb/api/urls.py b/netbox_cmdb/netbox_cmdb/api/urls.py index 0a7edbb..30512b1 100644 --- a/netbox_cmdb/netbox_cmdb/api/urls.py +++ b/netbox_cmdb/netbox_cmdb/api/urls.py @@ -7,6 +7,7 @@ BGPGlobalViewSet, BGPPeerGroupViewSet, BGPSessionsViewSet, + DeviceBGPSessionsViewSet, ) from netbox_cmdb.api.bgp_community_list.views import BGPCommunityListViewSet from netbox_cmdb.api.prefix_list.views import PrefixListViewSet @@ -18,6 +19,7 @@ router.register("asns", ASNViewSet) router.register("bgp-global", BGPGlobalViewSet) router.register("bgp-sessions", BGPSessionsViewSet) +router.register("device-bgp-sessions", DeviceBGPSessionsViewSet) router.register("bgp-community-lists", BGPCommunityListViewSet) router.register("peer-groups", BGPPeerGroupViewSet) router.register("prefix-lists", PrefixListViewSet) diff --git a/netbox_cmdb/netbox_cmdb/filtersets.py b/netbox_cmdb/netbox_cmdb/filtersets.py index d5edcc5..3405afa 100644 --- a/netbox_cmdb/netbox_cmdb/filtersets.py +++ b/netbox_cmdb/netbox_cmdb/filtersets.py @@ -5,7 +5,8 @@ from utilities.filters import MultiValueCharFilter from netbox.filtersets import ChangeLoggedModelFilterSet -from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession +from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession +from netbox_cmdb.models.route_policy import RoutePolicy device_location_filterset = [ "device__location__name", @@ -162,6 +163,44 @@ def search(self, queryset, name, value): ).distinct() +class DeviceBGPSessionFilterSet(ChangeLoggedModelFilterSet): + """Device BGP Session filterset.""" + + q = django_filters.CharFilter( + method="search", + label="Search", + ) + + class Meta: + model = DeviceBGPSession + fields = ["id", "device__name", "local_address", "local_asn"] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(device__name__icontains=value) | Q(description__icontains=value) + ).distinct() + + +class RoutePolicyFilterSet(ChangeLoggedModelFilterSet): + """Route Policy filterset.""" + + q = django_filters.CharFilter( + method="search", + label="Search", + ) + + class Meta: + model = RoutePolicy + fields = ["id", "device__id", "device__name", "name"] + device_location_filterset + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter(name__icontains=value) + + class BGPPeerGroupFilterSet(ChangeLoggedModelFilterSet): """BGP Session filterset.""" diff --git a/netbox_cmdb/netbox_cmdb/forms.py b/netbox_cmdb/netbox_cmdb/forms.py index ee5dbe9..78b1c65 100644 --- a/netbox_cmdb/netbox_cmdb/forms.py +++ b/netbox_cmdb/netbox_cmdb/forms.py @@ -1,19 +1,22 @@ """Forms.""" +from typing import Any, Sequence + from dcim.models import Device from dcim.models.devices import DeviceType from dcim.models.sites import SiteGroup from django import forms from django.utils.translation import gettext as _ from extras.models import Tag -from netbox_cmdb.models.snmp import SNMP, SNMPCommunity -from netbox_cmdb.constants import MAX_COMMUNITY_PER_DEVICE from utilities.forms import DynamicModelMultipleChoiceField from utilities.forms.fields import DynamicModelChoiceField, MultipleChoiceField from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm -from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices, SNMPCommunityType -from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession +from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices +from netbox_cmdb.constants import MAX_COMMUNITY_PER_DEVICE +from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession +from netbox_cmdb.models.route_policy import RoutePolicy +from netbox_cmdb.models.snmp import SNMP, SNMPCommunity class ASNForm(NetBoxModelForm): @@ -25,9 +28,56 @@ class Meta: class BGPSessionForm(NetBoxModelForm): + peer_a = DynamicModelChoiceField( + queryset=DeviceBGPSession.objects.all(), + label=_("Peer A"), + required=True, + ) + peer_b = DynamicModelChoiceField( + queryset=DeviceBGPSession.objects.all(), + label=_("Peer B"), + required=True, + ) + class Meta: model = BGPSession - fields = ["peer_a", "peer_b", "state", "monitoring_state"] + fields = ["peer_a", "peer_b", "state", "monitoring_state", "tenant"] + + +class DeviceBGPSessionForm(NetBoxModelForm): + def __init__(self, *args, **kwargs): + instance = kwargs.get("instance") + initial = kwargs.get("initial", {}) + if instance is not None and instance.device: + initial["device"] = str(instance.device) + kwargs["initial"] = initial + super().__init__(*args, **kwargs) + + device = forms.CharField(disabled=True) + route_policy_in = DynamicModelChoiceField( + queryset=RoutePolicy.objects.all(), + label=_("Route Policy in"), + query_params={ + "device__id": "$device", + }, + to_field_name="name", + fetch_trigger="open", + required=False, + ) + route_policy_out = DynamicModelChoiceField( + queryset=RoutePolicy.objects.all(), + label=_("Route Policy out"), + query_params={ + "device__id": "$device", + }, + to_field_name="name", + fetch_trigger="open", + required=False, + ) + + class Meta: + model = DeviceBGPSession + fields = ["device", "route_policy_in", "route_policy_out"] class BGPSessionFilterSetForm(NetBoxModelFilterSetForm): @@ -67,6 +117,31 @@ class Meta: ] +class RoutePolicyForm(NetBoxModelForm): + device = DynamicModelChoiceField(queryset=Device.objects.all()) + + class Meta: + model = RoutePolicy + fields = [ + "name", + "device", + "description", + ] + + +class RoutePolicyFilterSetForm(NetBoxModelFilterSetForm): + device__id = DynamicModelMultipleChoiceField( + queryset=Device.objects.all(), + label=_("Device"), + required=False, + ) + name = forms.CharField( + required=False, + ) + + model = RoutePolicy + + class InlineTermForm(forms.models.BaseInlineFormSet): """InlineTermForm is a form that require at least one item to be valid. It is useful for following models: diff --git a/netbox_cmdb/netbox_cmdb/models/bgp.py b/netbox_cmdb/netbox_cmdb/models/bgp.py index e2e4b30..7ed54fd 100644 --- a/netbox_cmdb/netbox_cmdb/models/bgp.py +++ b/netbox_cmdb/netbox_cmdb/models/bgp.py @@ -10,7 +10,6 @@ from netbox.models import ChangeLoggedModel from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices from netbox_cmdb.constants import BGP_MAX_ASN, BGP_MIN_ASN -from netbox_cmdb.models.circuit import Circuit class BGPGlobal(ChangeLoggedModel): diff --git a/netbox_cmdb/netbox_cmdb/models/route_policy.py b/netbox_cmdb/netbox_cmdb/models/route_policy.py index 7f4548c..cff8789 100644 --- a/netbox_cmdb/netbox_cmdb/models/route_policy.py +++ b/netbox_cmdb/netbox_cmdb/models/route_policy.py @@ -1,8 +1,9 @@ from django.core.exceptions import ValidationError from django.db import models -from netbox.models import ChangeLoggedModel +from django.urls import reverse from utilities.querysets import RestrictedQuerySet +from netbox.models import ChangeLoggedModel from netbox_cmdb.choices import DecisionChoice from netbox_cmdb.fields import CustomIPAddressField @@ -26,11 +27,14 @@ class RoutePolicy(ChangeLoggedModel): objects = RestrictedQuerySet.as_manager() def __str__(self): - return f"{self.device}--{self.name}" + return str(self.name) def __repr__(self): return str(self.name) + def get_absolute_url(self): + return reverse("plugins:netbox_cmdb:routepolicy", args=[self.pk]) + class Meta: verbose_name_plural = "Route Policies" unique_together = ["device", "name"] diff --git a/netbox_cmdb/netbox_cmdb/navigation.py b/netbox_cmdb/netbox_cmdb/navigation.py index 246e69a..55bb2a5 100644 --- a/netbox_cmdb/netbox_cmdb/navigation.py +++ b/netbox_cmdb/netbox_cmdb/navigation.py @@ -40,6 +40,18 @@ ), ), ), + PluginMenuItem( + link="plugins:netbox_cmdb:routepolicy_list", + link_text="Route Policies", + buttons=( + PluginMenuButton( + link="plugins:netbox_cmdb:routepolicy_add", + title="Route Policies", + icon_class="mdi mdi-plus-thick", + color=ButtonColorChoices.GREEN, + ), + ), + ), PluginMenuItem( link="plugins:netbox_cmdb:snmp_list", link_text="SNMP", diff --git a/netbox_cmdb/netbox_cmdb/tables.py b/netbox_cmdb/netbox_cmdb/tables.py index b4a5dec..9bea1b0 100644 --- a/netbox_cmdb/netbox_cmdb/tables.py +++ b/netbox_cmdb/netbox_cmdb/tables.py @@ -3,7 +3,8 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns -from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession +from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession +from netbox_cmdb.models.route_policy import RoutePolicy from netbox_cmdb.models.snmp import SNMP, SNMPCommunity @@ -42,27 +43,64 @@ class Meta(NetBoxTable.Meta): ) +class DeviceBGPSessionTable(NetBoxTable): + id = tables.Column() + device = tables.Column(verbose_name="Device") + description = tables.Column(verbose_name="Description") + local_address = tables.Column(verbose_name="Local address") + local_asn = tables.Column(verbose_name="Local ASN") + route_policy_in = tables.Column(verbose_name="Route Policy in") + route_policy_out = tables.Column(verbose_name="Route Policy out") + maximum_prefixes = tables.Column(verbose_name="Maximum prefixes") + + class Meta(NetBoxTable.Meta): + model = DeviceBGPSession + fields = ( + "id", + "device", + "description", + "local_address", + "local_asn", + "route_policy_in", + "route_policy_out", + "maximum_prefixes", + ) + + class BGPPeerGroupTable(NetBoxTable): - device = tables.LinkColumn() - name = tables.LinkColumn() - asn = tables.Column() - route_policy_in = tables.Column() - route_policy_out = tables.Column() + name = tables.Column(linkify=True) + device = tables.Column(linkify=True) + local_asn = tables.Column(linkify=True) + remote_asn = tables.Column(linkify=True) + route_policy_in = tables.Column(linkify=True) + route_policy_out = tables.Column(linkify=True) maximum_prefixes = tables.Column() + refcount = tables.Column() class Meta(NetBoxTable.Meta): model = BGPPeerGroup fields = ( - "pk", "name", + "device", "local_asn", "remote_asn", "route_policy_in", "route_policy_out", "maximum_prefixes", + "refcount", ) +class RoutePolicyTable(NetBoxTable): + device = tables.Column(linkify=True) + name = tables.Column(linkify=True) + refcount = tables.Column() + + class Meta(NetBoxTable.Meta): + model = RoutePolicy + fields = ("name", "device", "refcount") + + class SNMPTable(NetBoxTable): device = tables.LinkColumn() diff --git a/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/bgpsession.html b/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/bgpsession.html index b0f57aa..d5f65f2 100644 --- a/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/bgpsession.html +++ b/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/bgpsession.html @@ -8,39 +8,39 @@
Peer A
- - - - - - - - -
Device + Device {{ object.peer_a.device|linkify}}
Description + Description {{ object.peer_a.description }}
Local address + Local address {{ object.peer_a.local_address|linkify}}
Local ASN + Local ASN {{ object.peer_a.local_asn|linkify}}
Route Policy in + Route Policy in {{ object.peer_a.route_policy_in|placeholder}}
Route Policy out + Route Policy out {{ object.peer_a.route_policy_out|placeholder}}
Maximum prefixes + Maximum prefixes {{ object.peer_a.maximum_prefixes }}
Enforce First AS + Enforce First AS {% checkmark object.peer_a.enforce_first_as %}
Enabled + Enabled {% checkmark object.peer_a.enabled %}
@@ -87,10 +87,6 @@
BGP Session
Circuit {{ object.circuit|placeholder }} - - Tenant - {{ object.tenant|placeholder|linkify }} -
@@ -101,39 +97,39 @@
Peer B
- - - - - - - - -
Device + Device {{ object.peer_b.device|linkify}}
Description + Description {{ object.peer_b.description }}
Local address + Local address {{ object.peer_b.local_address|linkify}}
Local ASN + Local ASN {{ object.peer_b.local_asn|linkify}}
Route Policy in + Route Policy in {{ object.peer_b.route_policy_in|placeholder}}
Route Policy out + Route Policy out {{ object.peer_b.route_policy_out|placeholder}}
Maximum prefixes + Maximum prefixes {{ object.peer_b.maximum_prefixes }}
Enforce First AS + Enforce First AS {% checkmark object.peer_b.enforce_first_as %}
Enabled + Enabled {% checkmark object.peer_b.enabled %}
@@ -169,7 +165,7 @@
Peer-Group A
+ + +
PG Name - {{ object.peer_a.peer_group.name}}{{ object.peer_a.peer_group | linkify:"name" }}
Description @@ -185,11 +181,11 @@
Peer-Group A
Route Policy in - {{ object.peer_a.peer_group.route_policy_in.name|placeholder}}{{ object.peer_a.peer_group.route_policy_in|placeholder|linkify:"name"}}
Route Policy out - {{ object.peer_a.peer_group.route_policy_out.name|placeholder}}{{ object.peer_a.peer_group.route_policy_out|placeholder|linkify:"name"}}
Maximum prefixes @@ -210,7 +206,7 @@
Peer-Group B
+ + +
PG Name - {{ object.peer_b.peer_group.name}}{{ object.peer_b.peer_group | linkify:"name" }}
Description @@ -226,11 +222,11 @@
Peer-Group B
Route Policy in - {{ object.peer_b.peer_group.route_policy_in.name|placeholder}}{{ object.peer_b.peer_group.route_policy_in|placeholder|linkify:"name"}}
Route Policy out - {{ object.peer_b.peer_group.route_policy_out.name|placeholder}}{{ object.peer_b.peer_group.route_policy_out|placeholder|linkify:"name"}}
Maximum prefixes diff --git a/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/routepolicy.html b/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/routepolicy.html new file mode 100644 index 0000000..4dd3dda --- /dev/null +++ b/netbox_cmdb/netbox_cmdb/templates/netbox_cmdb/routepolicy.html @@ -0,0 +1,96 @@ +{% extends 'generic/object.html' %} {% block content %} +
+
+
+
Route Policy
+
+ + + + + + + + + + + + + +
Name{{ object.name }}
Device{{ object.device|linkify }}
Description{{ object.description }}
+
+
+
+
+
+
Terms
+
+ + + + + + + + + + + {% for term in object.route_policy_term.all %} + + + + + + + {% endfor %} + +
SeqDecisionConditionsActions
{{ term.sequence }}{{ term.decision }} + {% if term.from_bgp_community %} + from_bgp_community {{ term.from_bgp_community }}
+ {% endif %} + {% if term.from_bgp_community_list %} + from_bgp_community_list {{ term.from_bgp_community_list.name }}
+ {% endif %} + {% if term.from_prefix_list %} + from_prefix_list {{ term.from_prefix_list.name }}
+ {% endif %} + {% if term.from_source_protocol %} + from_source_protocol {{ term.from_source_protocol }}
+ {% endif %} + {% if term.from_route_type %} + from_route_type {{ term.from_route_type }}
+ {% endif %} + {% if term.from_local_pref %} + from_local_pref {{ term.from_local_pref }}
+ {% endif %} +
+ {% if term.set_local_pref %} + set_local_pref {{ term.set_local_pref }}
+ {% endif %} + {% if term.set_community %} + set_community {{ term.set_community }}
+ {% endif %} + {% if term.set_origin %} + set_origin {{ term.set_origin }}
+ {% endif %} + {% if term.set_metric %} + set_metric {{ term.set_metric }}
+ {% endif %} + {% if term.set_large_community %} + set_large_community {{ term.set_large_community }}
+ {% endif %} + {% if term.set_as_path_prepend_asn %} + set_as_path_prepend_asn {{ term.set_as_path_prepend_asn }}
+ {% endif %} + {% if term.set_as_path_prepend_repeat %} + set_as_path_prepend_repeat {{ term.set_as_path_prepend_repeat }}
+ {% endif %} + {% if term.set_next_hop %} + set_next_hop {{ term.set_next_hop }}
+ {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/netbox_cmdb/netbox_cmdb/urls.py b/netbox_cmdb/netbox_cmdb/urls.py index f774d62..fced042 100644 --- a/netbox_cmdb/netbox_cmdb/urls.py +++ b/netbox_cmdb/netbox_cmdb/urls.py @@ -5,6 +5,7 @@ from netbox_cmdb.models.bgp import * from netbox_cmdb.models.snmp import SNMP, SNMPCommunity +from netbox_cmdb.models.route_policy import RoutePolicy from netbox_cmdb.views import ( ASNDeleteView, ASNEditView, @@ -25,6 +26,14 @@ SNMPDeleteView, SNMPEditView, SNMPListView, + DeviceBGPSessionEditView, + DeviceBGPSessionListView, + DeviceBGPSessionView, + DeviecBGPSessionDeleteView, + RoutePolicyDeleteView, + RoutePolicyEditView, + RoutePolicyListView, + RoutePolicyView, ) urlpatterns = [ @@ -73,6 +82,26 @@ name="bgpsession_journal", kwargs={"model": BGPSession}, ), + # Device BGP session + path("device-bgp-session/", DeviceBGPSessionListView.as_view(), name="devicebgpsession_list"), + path("device-bgp-session/add", DeviceBGPSessionEditView.as_view(), name="devicebgpsession_add"), + path("device-bgp-session//", DeviceBGPSessionView.as_view(), name="devicebgpsession"), + path( + "device-bgp-session//edit", + DeviceBGPSessionEditView.as_view(), + name="devicebgpsession_edit", + ), + path( + "device-bgp-session//delete", + DeviecBGPSessionDeleteView.as_view(), + name="devicebgpsession_delete", + ), + path( + "device-bgp-session//changelog/", + ObjectChangeLogView.as_view(), + name="devicebgpsession_changelog", + kwargs={"model": DeviceBGPSession}, + ), # Peer Group path("peer-group/", BGPPeerGroupListView.as_view(), name="bgppeergroup_list"), path("peer-group/add/", BGPPeerGroupEditView.as_view(), name="bgppeergroup_add"), @@ -99,6 +128,32 @@ name="bgppeergroup_journal", kwargs={"model": BGPPeerGroup}, ), + # Route Policy + path("route-policy/", RoutePolicyListView.as_view(), name="routepolicy_list"), + path("route-policy/add/", RoutePolicyEditView.as_view(), name="routepolicy_add"), + path("route-policy//", RoutePolicyView.as_view(), name="routepolicy"), + path( + "route-policy//edit/", + RoutePolicyEditView.as_view(), + name="routepolicy_edit", + ), + path( + "route-policy//delete/", + RoutePolicyDeleteView.as_view(), + name="routepolicy_delete", + ), + path( + "route-policy//changelog/", + ObjectChangeLogView.as_view(), + name="routepolicy_changelog", + kwargs={"model": RoutePolicy}, + ), + path( + "route-policy//journal/", + ObjectJournalView.as_view(), + name="routepolicy_journal", + kwargs={"model": RoutePolicy}, + ), # SNMP path("snmp/", SNMPListView.as_view(), name="snmp_list"), path("snmp/add/", SNMPEditView.as_view(), name="snmp_add"), diff --git a/netbox_cmdb/netbox_cmdb/views.py b/netbox_cmdb/netbox_cmdb/views.py index 4a4521f..5a6de8b 100644 --- a/netbox_cmdb/netbox_cmdb/views.py +++ b/netbox_cmdb/netbox_cmdb/views.py @@ -1,5 +1,7 @@ """Views.""" +from utilities.utils import count_related + from netbox.views.generic import ( ObjectDeleteView, ObjectEditView, @@ -11,6 +13,8 @@ ASNFilterSet, BGPPeerGroupFilterSet, BGPSessionFilterSet, + DeviceBGPSessionFilterSet, + RoutePolicyFilterSet, SNMPFilterSet, ) from netbox_cmdb.forms import ( @@ -18,15 +22,27 @@ BGPPeerGroupForm, BGPSessionFilterSetForm, BGPSessionForm, + DeviceBGPSessionForm, + RoutePolicyFilterSetForm, + RoutePolicyForm, SNMPCommunityGroupForm, SNMPGroupForm, ) -from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession +from netbox_cmdb.models.bgp import ( + ASN, + AfiSafi, + BGPPeerGroup, + BGPSession, + DeviceBGPSession, +) +from netbox_cmdb.models.route_policy import RoutePolicy from netbox_cmdb.models.snmp import SNMP, SNMPCommunity from netbox_cmdb.tables import ( ASNTable, BGPPeerGroupTable, BGPSessionTable, + DeviceBGPSessionTable, + RoutePolicyTable, SNMPCommunityTable, SNMPTable, ) @@ -86,23 +102,37 @@ class BGPSessionView(ObjectView): ).all() template_name = "netbox_cmdb/bgpsession.html" - def get_extra_context(self, request, instance): - # Get AFI/SAFIS - peer_a_afi_safis = [] - peer_b_afi_safis = [] - if instance.peer_a.afi_safis is not None: - peer_a_afi_safis = instance.peer_a.afi_safis.all() - if instance.peer_b.afi_safis is not None: - peer_b_afi_safis = instance.peer_b.afi_safis.all() - return { - "peer_a_afi_safis": peer_a_afi_safis, - "peer_b_afi_safis": peer_b_afi_safis, - } + +## DeviceBGPSession views +class DeviceBGPSessionListView(ObjectListView): + queryset = DeviceBGPSession.objects.all() + filterset = DeviceBGPSessionFilterSet + table = DeviceBGPSessionTable + + +class DeviceBGPSessionView(ObjectView): + queryset = DeviceBGPSession.objects.all() + + +class DeviceBGPSessionEditView(ObjectEditView): + queryset = DeviceBGPSession.objects.all() + form = DeviceBGPSessionForm + filterset = DeviceBGPSessionFilterSet + + +class DeviecBGPSessionDeleteView(ObjectDeleteView): + queryset = DeviceBGPSession.objects.all() + + +class DeviecBGPSessionBulkDeleteView(BulkDeleteView): + queryset = DeviceBGPSession.objects.all() + filterset = DeviceBGPSessionFilterSet + table = DeviceBGPSessionTable ## Peer groups views class BGPPeerGroupListView(ObjectListView): - queryset = BGPPeerGroup.objects.all() + queryset = BGPPeerGroup.objects.annotate(refcount=count_related(DeviceBGPSession, "peer_group")) filterset = BGPPeerGroupFilterSet table = BGPPeerGroupTable template_name = "netbox_cmdb/bgppeergroup_list.html" @@ -122,6 +152,49 @@ class BGPPeerGroupView(ObjectView): template_name = "netbox_cmdb/bgppeergroup.html" +## Route policy views + + +class RoutePolicyListView(ObjectListView): + queryset = RoutePolicy.objects.annotate( + refcount=sum( + [ + count_related(AfiSafi, "route_policy_in"), + count_related(AfiSafi, "route_policy_out"), + count_related(DeviceBGPSession, "route_policy_in"), + count_related(DeviceBGPSession, "route_policy_out"), + count_related(BGPPeerGroup, "route_policy_in"), + count_related(BGPPeerGroup, "route_policy_out"), + ] + ) + ) + filterset_form = RoutePolicyFilterSetForm + filterset = RoutePolicyFilterSet + table = RoutePolicyTable + + +class RoutePolicyView(ObjectView): + queryset = RoutePolicy.objects.prefetch_related("route_policy_term").all() + template_name = "netbox_cmdb/routepolicy.html" + + +class RoutePolicyEditView(ObjectEditView): + model = RoutePolicy + queryset = RoutePolicy.objects.prefetch_related("route_policy_term").all() + form = RoutePolicyForm + filterset = RoutePolicyFilterSet + + +class RoutePolicyDeleteView(ObjectDeleteView): + queryset = RoutePolicy.objects.all() + + +class RoutePolicyBulkDeleteView(BulkDeleteView): + queryset = RoutePolicy.objects.all() + filterset = RoutePolicyFilterSet + table = RoutePolicyTable + + ## Snmp groups views class SNMPListView(ObjectListView): queryset = SNMP.objects.all()