Skip to content

Commit

Permalink
Merge pull request #105 from k01ek/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
k01ek authored Sep 16, 2022
2 parents c1d422e + a9a8d86 commit 3132f73
Show file tree
Hide file tree
Showing 35 changed files with 162 additions and 861 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PYTHON_VER?=3.8
NETBOX_VER?=v3.2.4
NETBOX_VER?=v3.2.9

NAME=netbox-bgp

Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

## Features
This plugin provide following Models:
* AS Numbers (will be removed in 0.8.0)
* BGP Communities
* BGP Sessions
* Routing Policy
Expand All @@ -17,7 +16,7 @@ This plugin provide following Models:
| NetBox 2.11 | 0.3.9 |
| NetBox 3.0 | 0.4.3 |
| NetBox 3.1 | 0.5.0 |
| NetBox 3.2 | 0.6.0 |
| NetBox 3.2 | >= 0.6.0 |

## Installation

Expand All @@ -32,29 +31,30 @@ PLUGINS = ['netbox_bgp']
```
Restart NetBox and add `netbox-bgp` to your local_requirements.txt

See [NetBox Documentation](https://docs.netbox.dev/en/stable/plugins/#installing-plugins) for details

## Configuration

The following options are available:
* `device_ext_page`: String (default right) Device related BGP sessions table position. The following values are available:
left, right, full_width. Set empty value for disable.
* `asdot`: Boolean (defaul False) asdot notation for 4-byte AS
left, right, full_width. Set empty value for disable.

## Screenshots

BGP Session
![BGP Session](docs/img/bgp_sess.png)
![BGP Session](docs/img/session.png)

BGP Sessions
![BGP Session Table](docs/img/bgp_sess_list.png)

ASN
![ASN](docs/img/asn.png)

ASNs
![ASN Table](docs/img/asn_list.png)
![BGP Session Table](docs/img/sessions.png)

Community
![Community](docs/img/commun.png)

Peer Group
![Peer Group](docs/img/peer_group.png)

Routing Policy
![Routing Policy](docs/img/routepolicy.png)

Prefix List
![Prefix List](docs/img/preflist.png)
2 changes: 1 addition & 1 deletion develop/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG python_ver=3.7
ARG python_ver=3.8
FROM python:${python_ver}

ARG netbox_ver=master
Expand Down
Binary file removed docs/img/asn.png
Binary file not shown.
Binary file removed docs/img/asn_list.png
Binary file not shown.
Binary file removed docs/img/bgp_sess.png
Binary file not shown.
Binary file removed docs/img/bgp_sess_list.png
Binary file not shown.
Binary file modified docs/img/commun.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/preflist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/routepolicy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/session.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/sessions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion netbox_bgp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class BGPConfig(PluginConfig):
max_version = '3.2.99'
default_settings = {
'device_ext_page': 'right',
'asdot': False
}


Expand Down
7 changes: 1 addition & 6 deletions netbox_bgp/admin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
from django.contrib import admin
from .models import ASN, Community, BGPSession, BGPPeerGroup, RoutingPolicy


@admin.register(ASN)
class ASNAdmin(admin.ModelAdmin):
fields = ('number', 'status', 'description')
from .models import Community, BGPSession, BGPPeerGroup, RoutingPolicy


@admin.register(Community)
Expand Down
48 changes: 8 additions & 40 deletions netbox_bgp/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
from rest_framework.serializers import Serializer, HyperlinkedIdentityField, ValidationError
from rest_framework.serializers import HyperlinkedIdentityField, ValidationError
from rest_framework.relations import PrimaryKeyRelatedField

from netbox.api import ChoiceField, WritableNestedSerializer, ValidatedModelSerializer
from netbox.api import ChoiceField, WritableNestedSerializer
from netbox.api.serializers import NetBoxModelSerializer
from dcim.api.nested_serializers import NestedSiteSerializer, NestedDeviceSerializer
from tenancy.api.nested_serializers import NestedTenantSerializer
from extras.api.nested_serializers import NestedTagSerializer
from ipam.api.nested_serializers import NestedIPAddressSerializer
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedASNSerializer


from netbox_bgp.models import (
ASN, ASNStatusChoices, BGPSession, SessionStatusChoices, RoutingPolicy, BGPPeerGroup,
Community, RoutingPolicyRule, PrefixList, PrefixListRule
BGPSession, RoutingPolicy, BGPPeerGroup,
Community, RoutingPolicyRule, PrefixList, PrefixListRule,
)

from netbox_bgp.choices import CommunityStatusChoices, SessionStatusChoices


class SerializedPKRelatedField(PrimaryKeyRelatedField):
def __init__(self, serializer, **kwargs):
Expand All @@ -25,39 +26,6 @@ def to_representation(self, value):
return self.serializer(value, context={'request': self.context['request']}).data


class ASNSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=ASNStatusChoices, required=False)
site = NestedSiteSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)

def validate(self, attrs):
try:
number = attrs['number']
tenant = attrs.get('tenant')
except KeyError:
# this is patch
return attrs
if ASN.objects.filter(number=number, tenant=tenant).exists():
raise ValidationError(
{'error': 'Asn with this Number and Tenant already exists.'}
)
return attrs

class Meta:
ref_name = 'BGP_ASN'
model = ASN
fields = ['number', 'id', 'display', 'status', 'description', 'custom_fields', 'site', 'tenant', 'tags']


class NestedASNSerializer(WritableNestedSerializer):
url = HyperlinkedIdentityField(view_name='plugins:netbox_bgp:asn')

class Meta:
ref_name = 'BGP_ASN_Nested'
model = ASN
fields = ['id', 'url', 'number', 'description']


class RoutingPolicySerializer(NetBoxModelSerializer):
class Meta:
model = RoutingPolicy
Expand Down Expand Up @@ -172,7 +140,7 @@ class Meta:


class CommunitySerializer(NetBoxModelSerializer):
status = ChoiceField(choices=ASNStatusChoices, required=False)
status = ChoiceField(choices=CommunityStatusChoices, required=False)
tenant = NestedTenantSerializer(required=False, allow_null=True)

class Meta:
Expand Down
5 changes: 2 additions & 3 deletions netbox_bgp/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from rest_framework import routers

from .views import (
ASNViewSet, BGPSessionViewSet, RoutingPolicyViewSet, BGPPeerGroupViewSet,
CommunityViewSet, PrefixListViewSet
BGPSessionViewSet, RoutingPolicyViewSet, BGPPeerGroupViewSet, CommunityViewSet,
PrefixListViewSet
)

router = routers.DefaultRouter()
router.register('asn', ASNViewSet)
router.register('session', BGPSessionViewSet, 'session')
router.register('bgpsession', BGPSessionViewSet, 'bgpsession')
router.register('routing-policy', RoutingPolicyViewSet)
Expand Down
12 changes: 3 additions & 9 deletions netbox_bgp/api/views.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
from rest_framework.viewsets import ModelViewSet

from .serializers import (
ASNSerializer, BGPSessionSerializer, RoutingPolicySerializer, BGPPeerGroupSerializer,
BGPSessionSerializer, RoutingPolicySerializer, BGPPeerGroupSerializer,
CommunitySerializer, PrefixListSerializer
)
from netbox_bgp.models import ASN, BGPSession, RoutingPolicy, BGPPeerGroup, Community, PrefixList
from netbox_bgp.models import BGPSession, RoutingPolicy, BGPPeerGroup, Community, PrefixList
from netbox_bgp.filters import (
ASNFilterSet, BGPSessionFilterSet, RoutingPolicyFilterSet, BGPPeerGroupFilterSet,
BGPSessionFilterSet, RoutingPolicyFilterSet, BGPPeerGroupFilterSet,
CommunityFilterSet, PrefixListFilterSet
)


class ASNViewSet(ModelViewSet):
queryset = ASN.objects.all()
serializer_class = ASNSerializer
filterset_class = ASNFilterSet


class BGPSessionViewSet(ModelViewSet):
queryset = BGPSession.objects.all()
serializer_class = BGPSessionSerializer
Expand Down
18 changes: 15 additions & 3 deletions netbox_bgp/choices.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from utilities.choices import ChoiceSet


class ASNStatusChoices(ChoiceSet):
class CommunityStatusChoices(ChoiceSet):

STATUS_ACTIVE = 'active'
STATUS_RESERVED = 'reserved'
Expand All @@ -11,7 +11,7 @@ class ASNStatusChoices(ChoiceSet):
(STATUS_ACTIVE, 'Active', 'blue'),
(STATUS_RESERVED, 'Reserved', 'cyan'),
(STATUS_DEPRECATED, 'Deprecated', 'red'),
)
)


class SessionStatusChoices(ChoiceSet):
Expand Down Expand Up @@ -58,7 +58,19 @@ class AFISAFIChoices(ChoiceSet):
AFISAFI_VPNV6_FLOWSPEC = 'vpnv6-flowspec'

CHOICES = (

(AFISAFI_IPV4_UNICAST, 'IPv4 Unicast'),
(AFISAFI_IPV4_MULTICAST, 'IPv4 Multicast'),
(AFISAFI_IPV4_FLOWSPEC, 'IPv4 Flowspec'),
(AFISAFI_IPV6_UNICAST, 'IPv6 Unicast'),
(AFISAFI_IPV6_MULTICAST, 'IPv6 Multicast'),
(AFISAFI_L2VPN_VPLS, 'L2VPN VPLS'),
(AFISAFI_L2VPN_EVPN, 'L2VPN EVPN'),
(AFISAFI_VPNV4_UNICAST, 'VPNv4 Unicast'),
(AFISAFI_VPNV4_MULTICAST, 'VPNv4 Multicast'),
(AFISAFI_VPNV4_FLOWSPEC, 'VPNv4 Flowspec'),
(AFISAFI_VPNV6_UNICAST, 'VPNv6 Unicast'),
(AFISAFI_VPNV6_MULTICAST, 'VPNv6 Multicast'),
(AFISAFI_VPNV6_FLOWSPEC, 'VPNv6 Flowspec')
)


Expand Down
31 changes: 4 additions & 27 deletions netbox_bgp/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,11 @@
from netaddr.core import AddrFormatError
from extras.filters import TagFilter

from .models import ASN, Community, BGPSession, RoutingPolicy, BGPPeerGroup, PrefixList
from ipam.models import IPAddress
from .models import Community, BGPSession, RoutingPolicy, BGPPeerGroup, PrefixList
from ipam.models import IPAddress, ASN
from dcim.models import Device


class ASNFilterSet(django_filters.FilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
tag = TagFilter()

class Meta:
model = ASN
fields = ['number', 'description', 'status', 'tenant', 'site']

def search(self, queryset, name, value):
"""Perform the filtered search."""
if not value.strip():
return queryset
qs_filter = (
Q(id__icontains=value)
| Q(number__icontains=value)
| Q(description__icontains=value)
)
return queryset.filter(qs_filter)


class CommunityFilterSet(django_filters.FilterSet):
q = django_filters.CharFilter(
method='search',
Expand Down Expand Up @@ -65,7 +42,7 @@ class BGPSessionFilterSet(django_filters.FilterSet):
remote_as = django_filters.ModelMultipleChoiceFilter(
field_name='remote_as__number',
queryset=ASN.objects.all(),
to_field_name='number',
to_field_name='asn',
label='Remote AS (Number)',
)
remote_as_id = django_filters.ModelMultipleChoiceFilter(
Expand All @@ -77,7 +54,7 @@ class BGPSessionFilterSet(django_filters.FilterSet):
local_as = django_filters.ModelMultipleChoiceFilter(
field_name='local_as__number',
queryset=ASN.objects.all(),
to_field_name='number',
to_field_name='asn',
label='Local AS (Number)',
)
local_as_id = django_filters.ModelMultipleChoiceFilter(
Expand Down
Loading

0 comments on commit 3132f73

Please sign in to comment.