Skip to content

Commit 58023a4

Browse files
authored
Merge pull request #49 from k01ek/develop
0.3.7
2 parents b36a8f3 + f8fc49c commit 58023a4

File tree

6 files changed

+93
-9
lines changed

6 files changed

+93
-9
lines changed

netbox_bgp/api/serializers.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from rest_framework.serializers import Serializer, HyperlinkedIdentityField
1+
from rest_framework.serializers import Serializer, HyperlinkedIdentityField, ValidationError
22
from rest_framework.relations import PrimaryKeyRelatedField
33

44
from netbox.api import ChoiceField, WritableNestedSerializer, ValidatedModelSerializer
@@ -63,6 +63,13 @@ class ASNSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
6363
site = NestedSiteSerializer(required=False, allow_null=True)
6464
tenant = NestedTenantSerializer(required=False, allow_null=True)
6565

66+
def validate(self, attrs):
67+
if ASN.objects.filter(number=attrs['number'], tenant=attrs.get('tenant')).exists():
68+
raise ValidationError(
69+
{'error': 'Asn with this Number and Tenant already exists.'}
70+
)
71+
return attrs
72+
6673
class Meta:
6774
model = ASN
6875
fields = ['number', 'id', 'status', 'description', 'custom_fields', 'site', 'tenant', 'tags']

netbox_bgp/filters.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import django_filters
2+
import netaddr
23
from django.db.models import Q
3-
4+
from netaddr.core import AddrFormatError
45
# With netbox v2.11.3 TagFilter was moved to extras
56
try:
67
from utilities.filters import TagFilter
@@ -122,7 +123,6 @@ class BGPSessionFilterSet(django_filters.FilterSet):
122123
to_field_name='address',
123124
label='Remote Address',
124125
)
125-
126126
device_id = django_filters.ModelMultipleChoiceFilter(
127127
field_name='device__id',
128128
queryset=Device.objects.all(),
@@ -135,6 +135,14 @@ class BGPSessionFilterSet(django_filters.FilterSet):
135135
to_field_name='name',
136136
label='Device (name)',
137137
)
138+
by_remote_address = django_filters.CharFilter(
139+
method='search_by_remote_ip',
140+
label='Remote Address',
141+
)
142+
by_local_address = django_filters.CharFilter(
143+
method='search_by_local_ip',
144+
label='Local Address',
145+
)
138146

139147
class Meta:
140148
model = BGPSession
@@ -152,6 +160,24 @@ def search(self, queryset, name, value):
152160
)
153161
return queryset.filter(qs_filter)
154162

163+
def search_by_remote_ip(self, queryset, name, value):
164+
if not value.strip():
165+
return queryset
166+
try:
167+
query = str(netaddr.IPNetwork(value).cidr)
168+
return queryset.filter(remote_address__address=query)
169+
except (AddrFormatError, ValueError):
170+
return queryset.none()
171+
172+
def search_by_local_ip(self, queryset, name, value):
173+
if not value.strip():
174+
return queryset
175+
try:
176+
query = str(netaddr.IPNetwork(value).cidr)
177+
return queryset.filter(local_address__address=query)
178+
except (AddrFormatError, ValueError):
179+
return queryset.none()
180+
155181

156182
class RoutingPolicyFilterSet(django_filters.FilterSet):
157183
q = django_filters.CharFilter(

netbox_bgp/forms.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django import forms
22
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
3+
from django.utils.translation import gettext as _
34

45
from extras.models import Tag
56
from tenancy.models import Tenant
@@ -294,9 +295,18 @@ class BGPSessionFilterForm(BootstrapMixin, CustomFieldModelForm):
294295
api_url='/api/plugins/bgp/asn/',
295296
)
296297
)
297-
tenant = DynamicModelChoiceField(
298-
queryset=Tenant.objects.all(),
299-
required=False
298+
by_local_address = forms.CharField(
299+
required=False,
300+
label='Local Address'
301+
)
302+
by_remote_address = forms.CharField(
303+
required=False,
304+
label='Remote Address'
305+
)
306+
device_id = DynamicModelMultipleChoiceField(
307+
queryset=Device.objects.all(),
308+
required=False,
309+
label=_('Device')
300310
)
301311
status = forms.MultipleChoiceField(
302312
choices=SessionStatusChoices,
@@ -324,12 +334,16 @@ class BGPSessionFilterForm(BootstrapMixin, CustomFieldModelForm):
324334
api_url='/api/plugins/bgp/routing-policy/'
325335
)
326336
)
337+
tenant = DynamicModelChoiceField(
338+
queryset=Tenant.objects.all(),
339+
required=False
340+
)
327341

328342
tag = TagFilterField(BGPSession)
329343

330344
class Meta:
331345
model = BGPSession
332-
fields = ['q', 'status', 'tenant', 'remote_as', 'local_as']
346+
fields = ['q', 'status', 'device_id', 'remote_as', 'local_as']
333347

334348

335349
class RoutingPolicyFilterForm(BootstrapMixin, CustomFieldModelForm):

netbox_bgp/tables.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
{% endif %}
1515
"""
1616

17+
POLICIES = """
18+
{% for rp in value.all %}
19+
<a href="{{ rp.get_absolute_url }}">{{ rp }}</a>{% if not forloop.last %}<br />{% endif %}
20+
{% empty %}
21+
&mdash;
22+
{% endfor %}
23+
"""
24+
1725

1826
class ASNTable(BaseTable):
1927
pk = ToggleColumn()
@@ -95,7 +103,24 @@ class Meta(BaseTable.Meta):
95103
class BGPPeerGroupTable(BaseTable):
96104
pk = ToggleColumn()
97105
name = tables.LinkColumn()
106+
import_policies = tables.TemplateColumn(
107+
template_code=POLICIES,
108+
orderable=False
109+
)
110+
export_policies = tables.TemplateColumn(
111+
template_code=POLICIES,
112+
orderable=False
113+
)
114+
tags = TagColumn(
115+
url_name='plugins:netbox_bgp:peer_group_list'
116+
)
98117

99118
class Meta(BaseTable.Meta):
100119
model = BGPPeerGroup
101-
fields = ('pk', 'name', 'description')
120+
fields = (
121+
'pk', 'name', 'description', 'tags',
122+
'import_policies', 'export_policies'
123+
)
124+
default_columns = (
125+
'pk', 'name', 'description'
126+
)

netbox_bgp/tests/test_api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from users.models import Token
99

10+
from tenancy.models import Tenant
1011
from netbox_bgp.models import ASN, Community
1112

1213

@@ -24,6 +25,7 @@ def setUp(self):
2425
self.base_url_lookup = 'plugins-api:netbox_bgp-api:asn'
2526
self.asn1 = ASN.objects.create(number=65000, description='test_asn1')
2627
self.asn2 = ASN.objects.create(number=65001, description='test_asn2')
28+
self.tenant = Tenant.objects.create(name='tenant')
2729

2830
def test_list_asn(self):
2931
url = reverse(f'{self.base_url_lookup}-list')
@@ -72,6 +74,16 @@ def test_delete_task(self):
7274
with self.assertRaises(ASN.DoesNotExist):
7375
ASN.objects.get(pk=self.asn1.pk)
7476

77+
def test_uniqueconstraint_asn(self):
78+
url = reverse(f'{self.base_url_lookup}-list')
79+
data = {'number': 65001, 'description': 'test_asn3'}
80+
response = self.client.post(url, data, format='json')
81+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
82+
83+
data = {'number': 65001, 'description': 'test_asn3', 'tenant': self.tenant.pk}
84+
response = self.client.post(url, data, format='json')
85+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
86+
7587

7688
class CommunityTestCase(BaseTestCase):
7789
def setUp(self):

netbox_bgp/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.3.6"
1+
__version__ = "0.3.7"

0 commit comments

Comments
 (0)