Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements on BGP UI views #38

Merged
merged 4 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading