Skip to content

Commit 665cca6

Browse files
authored
Merge pull request #38 from fdomain/bgp-ui
Improvements on BGP UI views
2 parents 3b3a997 + 8acb351 commit 665cca6

File tree

15 files changed

+492
-76
lines changed

15 files changed

+492
-76
lines changed

netbox_cmdb/netbox_cmdb/api/bgp/serializers.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
from django.core.exceptions import ValidationError
22
from django.db.models import Q
33
from ipam.api.nested_serializers import NestedIPAddressSerializer
4-
from netbox.api.serializers import WritableNestedSerializer
54
from rest_framework import serializers
6-
from rest_framework.serializers import IntegerField, ModelSerializer
5+
from rest_framework.serializers import (
6+
IntegerField,
7+
ModelSerializer,
8+
SerializerMethodField,
9+
)
710
from tenancy.api.nested_serializers import NestedTenantSerializer
8-
from netbox_cmdb.choices import AssetMonitoringStateChoices
911

12+
from netbox.api.serializers import WritableNestedSerializer
1013
from netbox_cmdb.api.common_serializers import CommonDeviceSerializer
14+
from netbox_cmdb.choices import AssetMonitoringStateChoices
1115
from netbox_cmdb.constants import BGP_MAX_ASN, BGP_MIN_ASN
1216
from netbox_cmdb.models.bgp import (
1317
ASN,
@@ -126,10 +130,15 @@ class DeviceBGPSessionSerializer(ModelSerializer):
126130
route_policy_in = RoutePolicySerializer(required=False, many=False, allow_null=True)
127131
route_policy_out = RoutePolicySerializer(required=False, many=False, allow_null=True)
128132

133+
display = SerializerMethodField(read_only=True)
134+
129135
class Meta:
130136
model = DeviceBGPSession
131137
fields = "__all__"
132138

139+
def get_display(self, obj):
140+
return str(obj)
141+
133142

134143
class CircuitSerializer(ModelSerializer):
135144
class Meta:
@@ -141,6 +150,10 @@ class BGPSessionSerializer(ModelSerializer):
141150
peer_a = DeviceBGPSessionSerializer(many=False)
142151
peer_b = DeviceBGPSessionSerializer(many=False)
143152
tenant = NestedTenantSerializer(required=False, many=False)
153+
display = SerializerMethodField(read_only=True)
154+
155+
def get_display(self, obj):
156+
return str(obj)
144157

145158
def create(self, validated_data):
146159
peers_data = {}

netbox_cmdb/netbox_cmdb/api/bgp/views.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,34 @@
22
from django.db import transaction
33
from django_pglocks import advisory_lock
44
from drf_yasg.utils import swagger_auto_schema
5-
from netbox.api.viewsets.mixins import ObjectValidationMixin
65
from rest_framework import status
76
from rest_framework.exceptions import ValidationError
87
from rest_framework.response import Response
98
from rest_framework.views import APIView
109

10+
from netbox.api.viewsets.mixins import ObjectValidationMixin
1111
from netbox_cmdb import filtersets
1212
from netbox_cmdb.api.bgp.serializers import (
1313
AvailableAsnSerializer,
1414
BGPASNSerializer,
1515
BGPGlobalSerializer,
1616
BGPPeerGroupSerializer,
1717
BGPSessionSerializer,
18+
DeviceBGPSessionSerializer,
1819
)
1920
from netbox_cmdb.api.viewsets import CustomNetBoxModelViewSet
20-
from netbox_cmdb.filtersets import ASNFilterSet, BGPSessionFilterSet
21-
from netbox_cmdb.models.bgp import ASN, BGPGlobal, BGPPeerGroup, BGPSession
21+
from netbox_cmdb.filtersets import (
22+
ASNFilterSet,
23+
BGPSessionFilterSet,
24+
DeviceBGPSessionFilterSet,
25+
)
26+
from netbox_cmdb.models.bgp import (
27+
ASN,
28+
BGPGlobal,
29+
BGPPeerGroup,
30+
BGPSession,
31+
DeviceBGPSession,
32+
)
2233

2334

2435
class ASNViewSet(CustomNetBoxModelViewSet):
@@ -96,6 +107,12 @@ class BGPSessionsViewSet(CustomNetBoxModelViewSet):
96107
filterset_class = BGPSessionFilterSet
97108

98109

110+
class DeviceBGPSessionsViewSet(CustomNetBoxModelViewSet):
111+
queryset = DeviceBGPSession.objects.all()
112+
serializer_class = DeviceBGPSessionSerializer
113+
filterset_class = DeviceBGPSessionFilterSet
114+
115+
99116
class BGPPeerGroupViewSet(CustomNetBoxModelViewSet):
100117
queryset = BGPPeerGroup.objects.all()
101118
serializer_class = BGPPeerGroupSerializer

netbox_cmdb/netbox_cmdb/api/route_policy/serializers.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""Route Policy serializers."""
22

33
from django.core.exceptions import ValidationError
4-
from netbox.api.serializers import WritableNestedSerializer
54
from rest_framework import serializers
6-
from rest_framework.serializers import ModelSerializer
5+
from rest_framework.serializers import ModelSerializer, SerializerMethodField
76

7+
from netbox.api.serializers import WritableNestedSerializer
88
from netbox_cmdb.api.bgp.serializers import AsnSerializer
99
from netbox_cmdb.api.common_serializers import CommonDeviceSerializer
1010
from netbox_cmdb.models.bgp_community_list import BGPCommunityList
@@ -68,12 +68,15 @@ class Meta:
6868

6969
class WritableRoutePolicySerializer(ModelSerializer):
7070
device = CommonDeviceSerializer()
71-
7271
terms = RoutePolicyTermSerializer(many=True, source="route_policy_term")
72+
display = SerializerMethodField(read_only=True)
7373

7474
class Meta:
7575
model = RoutePolicy
76-
fields = ["id", "name", "device", "description", "terms"]
76+
fields = ["id", "name", "device", "description", "terms", "display"]
77+
78+
def get_display(self, obj):
79+
return obj.name
7780

7881
def _validate_terms(self, terms_data):
7982
if len(terms_data) < 1:
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
"""Route Policy views."""
22

3-
from netbox_cmdb import filtersets
4-
53
from netbox_cmdb.api.route_policy.serializers import WritableRoutePolicySerializer
64
from netbox_cmdb.api.viewsets import CustomNetBoxModelViewSet
5+
from netbox_cmdb.filtersets import RoutePolicyFilterSet
76
from netbox_cmdb.models.route_policy import RoutePolicy
87

98

109
class RoutePolicyViewSet(CustomNetBoxModelViewSet):
1110
queryset = RoutePolicy.objects.all()
1211
serializer_class = WritableRoutePolicySerializer
13-
filterset_fields = [
14-
"id",
15-
"name",
16-
"device__id",
17-
"device__name",
18-
] + filtersets.device_location_filterset
12+
filterset_class = RoutePolicyFilterSet

netbox_cmdb/netbox_cmdb/api/urls.py

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
BGPGlobalViewSet,
88
BGPPeerGroupViewSet,
99
BGPSessionsViewSet,
10+
DeviceBGPSessionsViewSet,
1011
)
1112
from netbox_cmdb.api.bgp_community_list.views import BGPCommunityListViewSet
1213
from netbox_cmdb.api.prefix_list.views import PrefixListViewSet
@@ -18,6 +19,7 @@
1819
router.register("asns", ASNViewSet)
1920
router.register("bgp-global", BGPGlobalViewSet)
2021
router.register("bgp-sessions", BGPSessionsViewSet)
22+
router.register("device-bgp-sessions", DeviceBGPSessionsViewSet)
2123
router.register("bgp-community-lists", BGPCommunityListViewSet)
2224
router.register("peer-groups", BGPPeerGroupViewSet)
2325
router.register("prefix-lists", PrefixListViewSet)

netbox_cmdb/netbox_cmdb/filtersets.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from utilities.filters import MultiValueCharFilter
66

77
from netbox.filtersets import ChangeLoggedModelFilterSet
8-
from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession
8+
from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession
9+
from netbox_cmdb.models.route_policy import RoutePolicy
910

1011
device_location_filterset = [
1112
"device__location__name",
@@ -162,6 +163,44 @@ def search(self, queryset, name, value):
162163
).distinct()
163164

164165

166+
class DeviceBGPSessionFilterSet(ChangeLoggedModelFilterSet):
167+
"""Device BGP Session filterset."""
168+
169+
q = django_filters.CharFilter(
170+
method="search",
171+
label="Search",
172+
)
173+
174+
class Meta:
175+
model = DeviceBGPSession
176+
fields = ["id", "device__name", "local_address", "local_asn"]
177+
178+
def search(self, queryset, name, value):
179+
if not value.strip():
180+
return queryset
181+
return queryset.filter(
182+
Q(device__name__icontains=value) | Q(description__icontains=value)
183+
).distinct()
184+
185+
186+
class RoutePolicyFilterSet(ChangeLoggedModelFilterSet):
187+
"""Route Policy filterset."""
188+
189+
q = django_filters.CharFilter(
190+
method="search",
191+
label="Search",
192+
)
193+
194+
class Meta:
195+
model = RoutePolicy
196+
fields = ["id", "device__id", "device__name", "name"] + device_location_filterset
197+
198+
def search(self, queryset, name, value):
199+
if not value.strip():
200+
return queryset
201+
return queryset.filter(name__icontains=value)
202+
203+
165204
class BGPPeerGroupFilterSet(ChangeLoggedModelFilterSet):
166205
"""BGP Session filterset."""
167206

netbox_cmdb/netbox_cmdb/forms.py

+80-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
"""Forms."""
22

3+
from typing import Any, Sequence
4+
35
from dcim.models import Device
46
from dcim.models.devices import DeviceType
57
from dcim.models.sites import SiteGroup
68
from django import forms
79
from django.utils.translation import gettext as _
810
from extras.models import Tag
9-
from netbox_cmdb.models.snmp import SNMP, SNMPCommunity
10-
from netbox_cmdb.constants import MAX_COMMUNITY_PER_DEVICE
1111
from utilities.forms import DynamicModelMultipleChoiceField
1212
from utilities.forms.fields import DynamicModelChoiceField, MultipleChoiceField
1313

1414
from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm
15-
from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices, SNMPCommunityType
16-
from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession
15+
from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices
16+
from netbox_cmdb.constants import MAX_COMMUNITY_PER_DEVICE
17+
from netbox_cmdb.models.bgp import ASN, BGPPeerGroup, BGPSession, DeviceBGPSession
18+
from netbox_cmdb.models.route_policy import RoutePolicy
19+
from netbox_cmdb.models.snmp import SNMP, SNMPCommunity
1720

1821

1922
class ASNForm(NetBoxModelForm):
@@ -25,9 +28,56 @@ class Meta:
2528

2629

2730
class BGPSessionForm(NetBoxModelForm):
31+
peer_a = DynamicModelChoiceField(
32+
queryset=DeviceBGPSession.objects.all(),
33+
label=_("Peer A"),
34+
required=True,
35+
)
36+
peer_b = DynamicModelChoiceField(
37+
queryset=DeviceBGPSession.objects.all(),
38+
label=_("Peer B"),
39+
required=True,
40+
)
41+
2842
class Meta:
2943
model = BGPSession
30-
fields = ["peer_a", "peer_b", "state", "monitoring_state"]
44+
fields = ["peer_a", "peer_b", "state", "monitoring_state", "tenant"]
45+
46+
47+
class DeviceBGPSessionForm(NetBoxModelForm):
48+
def __init__(self, *args, **kwargs):
49+
instance = kwargs.get("instance")
50+
initial = kwargs.get("initial", {})
51+
if instance is not None and instance.device:
52+
initial["device"] = str(instance.device)
53+
kwargs["initial"] = initial
54+
super().__init__(*args, **kwargs)
55+
56+
device = forms.CharField(disabled=True)
57+
route_policy_in = DynamicModelChoiceField(
58+
queryset=RoutePolicy.objects.all(),
59+
label=_("Route Policy in"),
60+
query_params={
61+
"device__id": "$device",
62+
},
63+
to_field_name="name",
64+
fetch_trigger="open",
65+
required=False,
66+
)
67+
route_policy_out = DynamicModelChoiceField(
68+
queryset=RoutePolicy.objects.all(),
69+
label=_("Route Policy out"),
70+
query_params={
71+
"device__id": "$device",
72+
},
73+
to_field_name="name",
74+
fetch_trigger="open",
75+
required=False,
76+
)
77+
78+
class Meta:
79+
model = DeviceBGPSession
80+
fields = ["device", "route_policy_in", "route_policy_out"]
3181

3282

3383
class BGPSessionFilterSetForm(NetBoxModelFilterSetForm):
@@ -67,6 +117,31 @@ class Meta:
67117
]
68118

69119

120+
class RoutePolicyForm(NetBoxModelForm):
121+
device = DynamicModelChoiceField(queryset=Device.objects.all())
122+
123+
class Meta:
124+
model = RoutePolicy
125+
fields = [
126+
"name",
127+
"device",
128+
"description",
129+
]
130+
131+
132+
class RoutePolicyFilterSetForm(NetBoxModelFilterSetForm):
133+
device__id = DynamicModelMultipleChoiceField(
134+
queryset=Device.objects.all(),
135+
label=_("Device"),
136+
required=False,
137+
)
138+
name = forms.CharField(
139+
required=False,
140+
)
141+
142+
model = RoutePolicy
143+
144+
70145
class InlineTermForm(forms.models.BaseInlineFormSet):
71146
"""InlineTermForm is a form that require at least one item to be valid.
72147
It is useful for following models:

netbox_cmdb/netbox_cmdb/models/bgp.py

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from netbox.models import ChangeLoggedModel
1111
from netbox_cmdb.choices import AssetMonitoringStateChoices, AssetStateChoices
1212
from netbox_cmdb.constants import BGP_MAX_ASN, BGP_MIN_ASN
13-
from netbox_cmdb.models.circuit import Circuit
1413

1514

1615
class BGPGlobal(ChangeLoggedModel):

netbox_cmdb/netbox_cmdb/models/route_policy.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from django.core.exceptions import ValidationError
22
from django.db import models
3-
from netbox.models import ChangeLoggedModel
3+
from django.urls import reverse
44
from utilities.querysets import RestrictedQuerySet
55

6+
from netbox.models import ChangeLoggedModel
67
from netbox_cmdb.choices import DecisionChoice
78
from netbox_cmdb.fields import CustomIPAddressField
89

@@ -26,11 +27,14 @@ class RoutePolicy(ChangeLoggedModel):
2627
objects = RestrictedQuerySet.as_manager()
2728

2829
def __str__(self):
29-
return f"{self.device}--{self.name}"
30+
return str(self.name)
3031

3132
def __repr__(self):
3233
return str(self.name)
3334

35+
def get_absolute_url(self):
36+
return reverse("plugins:netbox_cmdb:routepolicy", args=[self.pk])
37+
3438
class Meta:
3539
verbose_name_plural = "Route Policies"
3640
unique_together = ["device", "name"]

netbox_cmdb/netbox_cmdb/navigation.py

+12
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@
4040
),
4141
),
4242
),
43+
PluginMenuItem(
44+
link="plugins:netbox_cmdb:routepolicy_list",
45+
link_text="Route Policies",
46+
buttons=(
47+
PluginMenuButton(
48+
link="plugins:netbox_cmdb:routepolicy_add",
49+
title="Route Policies",
50+
icon_class="mdi mdi-plus-thick",
51+
color=ButtonColorChoices.GREEN,
52+
),
53+
),
54+
),
4355
PluginMenuItem(
4456
link="plugins:netbox_cmdb:snmp_list",
4557
link_text="SNMP",

0 commit comments

Comments
 (0)