Skip to content

Commit

Permalink
Merge pull request #38 from fdomain/bgp-ui
Browse files Browse the repository at this point in the history
Improvements on BGP UI views
  • Loading branch information
fdomain authored Aug 5, 2024
2 parents 3b3a997 + 8acb351 commit 665cca6
Show file tree
Hide file tree
Showing 15 changed files with 492 additions and 76 deletions.
19 changes: 16 additions & 3 deletions netbox_cmdb/netbox_cmdb/api/bgp/serializers.py
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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:
Expand All @@ -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 = {}
Expand Down
23 changes: 20 additions & 3 deletions netbox_cmdb/netbox_cmdb/api/bgp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,34 @@
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,
BGPASNSerializer,
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):
Expand Down Expand Up @@ -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
Expand Down
11 changes: 7 additions & 4 deletions netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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:
Expand Down
10 changes: 2 additions & 8 deletions netbox_cmdb/netbox_cmdb/api/route_policy/views.py
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions netbox_cmdb/netbox_cmdb/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
41 changes: 40 additions & 1 deletion netbox_cmdb/netbox_cmdb/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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."""

Expand Down
85 changes: 80 additions & 5 deletions netbox_cmdb/netbox_cmdb/forms.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -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:
Expand Down
1 change: 0 additions & 1 deletion netbox_cmdb/netbox_cmdb/models/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
8 changes: 6 additions & 2 deletions netbox_cmdb/netbox_cmdb/models/route_policy.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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"]
Expand Down
12 changes: 12 additions & 0 deletions netbox_cmdb/netbox_cmdb/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 665cca6

Please sign in to comment.