netbox-loadbalancer-plugin 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- netbox_loadbalancer/__init__.py +34 -0
- netbox_loadbalancer/api/__init__.py +0 -0
- netbox_loadbalancer/api/serializers.py +86 -0
- netbox_loadbalancer/api/urls.py +23 -0
- netbox_loadbalancer/api/views.py +72 -0
- netbox_loadbalancer/choices.py +185 -0
- netbox_loadbalancer/filtersets.py +127 -0
- netbox_loadbalancer/forms.py +352 -0
- netbox_loadbalancer/graphql/__init__.py +1 -0
- netbox_loadbalancer/graphql/filters.py +72 -0
- netbox_loadbalancer/graphql/schema.py +39 -0
- netbox_loadbalancer/graphql/types.py +70 -0
- netbox_loadbalancer/migrations/0001_initial.py +112 -0
- netbox_loadbalancer/migrations/0002_add_port_weight_validators.py +42 -0
- netbox_loadbalancer/migrations/0003_add_weight_min_validator.py +23 -0
- netbox_loadbalancer/migrations/__init__.py +0 -0
- netbox_loadbalancer/models.py +326 -0
- netbox_loadbalancer/navigation.py +42 -0
- netbox_loadbalancer/panels.py +82 -0
- netbox_loadbalancer/search.py +62 -0
- netbox_loadbalancer/tables.py +128 -0
- netbox_loadbalancer/templates/netbox_loadbalancer/loadbalancer.html +1 -0
- netbox_loadbalancer/templates/netbox_loadbalancer/pool.html +1 -0
- netbox_loadbalancer/templates/netbox_loadbalancer/poolmember.html +1 -0
- netbox_loadbalancer/templates/netbox_loadbalancer/virtualserver.html +1 -0
- netbox_loadbalancer/tests/__init__.py +0 -0
- netbox_loadbalancer/tests/test_api.py +135 -0
- netbox_loadbalancer/tests/test_filtersets.py +235 -0
- netbox_loadbalancer/tests/test_models.py +287 -0
- netbox_loadbalancer/tests/test_views.py +218 -0
- netbox_loadbalancer/urls.py +42 -0
- netbox_loadbalancer/views.py +320 -0
- netbox_loadbalancer_plugin-0.1.0.dist-info/METADATA +312 -0
- netbox_loadbalancer_plugin-0.1.0.dist-info/RECORD +37 -0
- netbox_loadbalancer_plugin-0.1.0.dist-info/WHEEL +5 -0
- netbox_loadbalancer_plugin-0.1.0.dist-info/licenses/LICENSE +191 -0
- netbox_loadbalancer_plugin-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""NetBox plugin for managing load balancers, virtual servers, pools, and pool members.
|
|
2
|
+
|
|
3
|
+
This is the plugin entry point. NetBox discovers plugins by looking for a module-level
|
|
4
|
+
``config`` variable that points to a PluginConfig subclass. The PluginConfig class
|
|
5
|
+
declares metadata (name, version, author) and settings (base_url, min_version) that
|
|
6
|
+
NetBox uses when loading the plugin.
|
|
7
|
+
|
|
8
|
+
When NetBox starts, it imports this module, reads the ``config`` variable, and uses it
|
|
9
|
+
to register the plugin's models, views, API endpoints, navigation menu, and search
|
|
10
|
+
indexes — all of which are defined in sibling modules within this package.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from netbox.plugins import PluginConfig
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NetBoxLoadBalancerConfig(PluginConfig):
|
|
17
|
+
"""Declares plugin metadata and compatibility requirements.
|
|
18
|
+
|
|
19
|
+
NetBox reads these attributes at startup to register the plugin. The ``name``
|
|
20
|
+
must match the Python package name (``netbox_loadbalancer``). The ``base_url``
|
|
21
|
+
determines the URL prefix for all plugin views (e.g. ``/plugins/loadbalancer/``).
|
|
22
|
+
The ``min_version`` prevents the plugin from loading on incompatible NetBox releases.
|
|
23
|
+
"""
|
|
24
|
+
name = 'netbox_loadbalancer'
|
|
25
|
+
verbose_name = 'Load Balancer'
|
|
26
|
+
description = 'Manage load balancers, virtual servers, pools, and pool members'
|
|
27
|
+
version = '0.1.0'
|
|
28
|
+
author = 'David Johnnes'
|
|
29
|
+
author_email = 'david.johnnes@gmail.com'
|
|
30
|
+
base_url = 'loadbalancer'
|
|
31
|
+
min_version = '4.0.0'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
config = NetBoxLoadBalancerConfig
|
|
File without changes
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""REST API serializers for the netbox_loadbalancer plugin.
|
|
2
|
+
|
|
3
|
+
Each serializer extends ``NetBoxModelSerializer``, which is a DRF ModelSerializer
|
|
4
|
+
pre-configured with NetBox's conventions for nested object representation, tag
|
|
5
|
+
handling, and custom field support.
|
|
6
|
+
|
|
7
|
+
Key concepts:
|
|
8
|
+
- ``Meta.fields``: the complete list of fields included in the full (detail) API
|
|
9
|
+
response. This includes computed fields like ``url`` and ``display`` (provided
|
|
10
|
+
by NetBoxModelSerializer), standard model fields, and audit fields (``created``,
|
|
11
|
+
``last_updated``).
|
|
12
|
+
- ``Meta.brief_fields``: the subset of fields returned when the ``?brief=true``
|
|
13
|
+
query parameter is used on the API. Brief mode returns a minimal representation
|
|
14
|
+
(typically just id, url, display, and name) and is used when the object appears
|
|
15
|
+
as a nested related object inside another serializer's response, to avoid deeply
|
|
16
|
+
nested JSON.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from netbox.api.serializers import NetBoxModelSerializer
|
|
20
|
+
|
|
21
|
+
from ..models import LoadBalancer, VirtualServer, Pool, PoolMember
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LoadBalancerSerializer(NetBoxModelSerializer):
|
|
25
|
+
"""Serializer for load balancer API responses.
|
|
26
|
+
|
|
27
|
+
Related objects (device, site, tenant, management_ip) are automatically serialized
|
|
28
|
+
as nested objects in full mode, or as brief references when this serializer is
|
|
29
|
+
used as a nested serializer inside another response.
|
|
30
|
+
"""
|
|
31
|
+
class Meta:
|
|
32
|
+
model = LoadBalancer
|
|
33
|
+
fields = (
|
|
34
|
+
'id', 'url', 'display', 'name', 'platform', 'status',
|
|
35
|
+
'device', 'site', 'tenant', 'management_ip', 'description',
|
|
36
|
+
'tags', 'custom_fields', 'created', 'last_updated',
|
|
37
|
+
)
|
|
38
|
+
brief_fields = ('id', 'url', 'display', 'name')
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class PoolSerializer(NetBoxModelSerializer):
|
|
42
|
+
"""Serializer for pool API responses.
|
|
43
|
+
|
|
44
|
+
The loadbalancer field is serialized as a nested object in full mode, showing
|
|
45
|
+
the parent load balancer's details inline within the pool response.
|
|
46
|
+
"""
|
|
47
|
+
class Meta:
|
|
48
|
+
model = Pool
|
|
49
|
+
fields = (
|
|
50
|
+
'id', 'url', 'display', 'name', 'loadbalancer', 'method',
|
|
51
|
+
'protocol', 'description',
|
|
52
|
+
'tags', 'custom_fields', 'created', 'last_updated',
|
|
53
|
+
)
|
|
54
|
+
brief_fields = ('id', 'url', 'display', 'name')
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class VirtualServerSerializer(NetBoxModelSerializer):
|
|
58
|
+
"""Serializer for virtual server API responses.
|
|
59
|
+
|
|
60
|
+
Includes nested representations for loadbalancer, ip_address, pool, and tenant.
|
|
61
|
+
The port and protocol fields are serialized as simple values.
|
|
62
|
+
"""
|
|
63
|
+
class Meta:
|
|
64
|
+
model = VirtualServer
|
|
65
|
+
fields = (
|
|
66
|
+
'id', 'url', 'display', 'name', 'loadbalancer', 'ip_address',
|
|
67
|
+
'port', 'protocol', 'status', 'pool', 'tenant', 'description',
|
|
68
|
+
'tags', 'custom_fields', 'created', 'last_updated',
|
|
69
|
+
)
|
|
70
|
+
brief_fields = ('id', 'url', 'display', 'name')
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PoolMemberSerializer(NetBoxModelSerializer):
|
|
74
|
+
"""Serializer for pool member API responses.
|
|
75
|
+
|
|
76
|
+
Includes nested representations for pool, ip_address, and device. Numeric fields
|
|
77
|
+
(port, weight, priority) are serialized as plain integers.
|
|
78
|
+
"""
|
|
79
|
+
class Meta:
|
|
80
|
+
model = PoolMember
|
|
81
|
+
fields = (
|
|
82
|
+
'id', 'url', 'display', 'name', 'pool', 'ip_address', 'device',
|
|
83
|
+
'port', 'weight', 'priority', 'status', 'description',
|
|
84
|
+
'tags', 'custom_fields', 'created', 'last_updated',
|
|
85
|
+
)
|
|
86
|
+
brief_fields = ('id', 'url', 'display', 'name')
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""API URL routing for the netbox_loadbalancer plugin.
|
|
2
|
+
|
|
3
|
+
Uses ``NetBoxRouter`` (a subclass of DRF's DefaultRouter) to automatically generate
|
|
4
|
+
REST API URL patterns for all four model viewsets. The router creates standard
|
|
5
|
+
endpoints like ``/api/plugins/loadbalancer/loadbalancers/`` and
|
|
6
|
+
``/api/plugins/loadbalancer/loadbalancers/<id>/``.
|
|
7
|
+
|
|
8
|
+
NetBox discovers this module automatically because the plugin package contains an
|
|
9
|
+
``api/`` sub-package with a ``urls.py`` module. The ``urlpatterns`` variable is
|
|
10
|
+
included under the plugin's API namespace by NetBox's plugin loading machinery.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from netbox.api.routers import NetBoxRouter
|
|
14
|
+
|
|
15
|
+
from . import views
|
|
16
|
+
|
|
17
|
+
router = NetBoxRouter()
|
|
18
|
+
router.register('loadbalancers', views.LoadBalancerViewSet)
|
|
19
|
+
router.register('pools', views.PoolViewSet)
|
|
20
|
+
router.register('virtual-servers', views.VirtualServerViewSet)
|
|
21
|
+
router.register('pool-members', views.PoolMemberViewSet)
|
|
22
|
+
|
|
23
|
+
urlpatterns = router.urls
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""REST API viewsets for the netbox_loadbalancer plugin.
|
|
2
|
+
|
|
3
|
+
Each viewset extends ``NetBoxModelViewSet``, which is a DRF (Django REST Framework)
|
|
4
|
+
ModelViewSet pre-configured with NetBox's authentication, permission checking,
|
|
5
|
+
pagination, and nested serializer support. A single viewset provides all standard
|
|
6
|
+
REST actions: list, retrieve, create, update, partial_update, and destroy.
|
|
7
|
+
|
|
8
|
+
The three class attributes on each viewset control its behaviour:
|
|
9
|
+
- ``queryset``: the base database query (can include annotations like Count).
|
|
10
|
+
- ``serializer_class``: the serializer used to convert model instances to/from JSON.
|
|
11
|
+
- ``filterset_class``: the FilterSet that enables URL query parameter filtering
|
|
12
|
+
(e.g. ``GET /api/plugins/loadbalancer/pools/?method=round-robin``).
|
|
13
|
+
|
|
14
|
+
These viewsets are registered with the ``NetBoxRouter`` in ``api/urls.py``, which
|
|
15
|
+
generates the standard REST URL patterns (list, detail, etc.) automatically.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from django.db.models import Count
|
|
19
|
+
from netbox.api.viewsets import NetBoxModelViewSet
|
|
20
|
+
|
|
21
|
+
from ..models import LoadBalancer, VirtualServer, Pool, PoolMember
|
|
22
|
+
from ..filtersets import (
|
|
23
|
+
LoadBalancerFilterSet, VirtualServerFilterSet, PoolFilterSet, PoolMemberFilterSet,
|
|
24
|
+
)
|
|
25
|
+
from .serializers import (
|
|
26
|
+
LoadBalancerSerializer, VirtualServerSerializer, PoolSerializer, PoolMemberSerializer,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LoadBalancerViewSet(NetBoxModelViewSet):
|
|
31
|
+
"""API endpoint for managing load balancers.
|
|
32
|
+
|
|
33
|
+
Supports ``GET /``, ``POST /``, ``GET /<id>/``, ``PUT /<id>/``, ``PATCH /<id>/``,
|
|
34
|
+
and ``DELETE /<id>/`` under the ``/api/plugins/loadbalancer/loadbalancers/`` path.
|
|
35
|
+
"""
|
|
36
|
+
queryset = LoadBalancer.objects.all()
|
|
37
|
+
serializer_class = LoadBalancerSerializer
|
|
38
|
+
filterset_class = LoadBalancerFilterSet
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class PoolViewSet(NetBoxModelViewSet):
|
|
42
|
+
"""API endpoint for managing pools.
|
|
43
|
+
|
|
44
|
+
The queryset includes ``.annotate(member_count=Count('members'))`` so that the
|
|
45
|
+
pool member count is available in the serialized response without requiring a
|
|
46
|
+
separate database query for each pool.
|
|
47
|
+
"""
|
|
48
|
+
queryset = Pool.objects.annotate(member_count=Count('members'))
|
|
49
|
+
serializer_class = PoolSerializer
|
|
50
|
+
filterset_class = PoolFilterSet
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class VirtualServerViewSet(NetBoxModelViewSet):
|
|
54
|
+
"""API endpoint for managing virtual servers.
|
|
55
|
+
|
|
56
|
+
Supports full CRUD and filtering by load balancer, status, protocol, pool, and
|
|
57
|
+
tenant via the ``VirtualServerFilterSet``.
|
|
58
|
+
"""
|
|
59
|
+
queryset = VirtualServer.objects.all()
|
|
60
|
+
serializer_class = VirtualServerSerializer
|
|
61
|
+
filterset_class = VirtualServerFilterSet
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class PoolMemberViewSet(NetBoxModelViewSet):
|
|
65
|
+
"""API endpoint for managing pool members.
|
|
66
|
+
|
|
67
|
+
Supports full CRUD and filtering by pool, status, device, IP address, port,
|
|
68
|
+
weight, and priority via the ``PoolMemberFilterSet``.
|
|
69
|
+
"""
|
|
70
|
+
queryset = PoolMember.objects.all()
|
|
71
|
+
serializer_class = PoolMemberSerializer
|
|
72
|
+
filterset_class = PoolMemberFilterSet
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Choice sets for the netbox_loadbalancer plugin.
|
|
2
|
+
|
|
3
|
+
Each class in this module extends NetBox's ``ChoiceSet`` base class to define the
|
|
4
|
+
valid options for a CharField on one of the plugin's models. A ChoiceSet works like
|
|
5
|
+
a Django choices tuple but adds colour-coded badges in the UI (the optional third
|
|
6
|
+
element in each CHOICES entry).
|
|
7
|
+
|
|
8
|
+
The ``key`` attribute (e.g. ``'LoadBalancer.platform'``) allows NetBox administrators
|
|
9
|
+
to override or extend the default choices at runtime through the FIELD_CHOICES
|
|
10
|
+
configuration setting, without modifying the plugin source code.
|
|
11
|
+
|
|
12
|
+
Convention: class constants (e.g. ``STATUS_ACTIVE = 'active'``) are used throughout
|
|
13
|
+
the codebase to reference choices by name instead of hardcoding string values.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from utilities.choices import ChoiceSet
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LoadBalancerPlatformChoices(ChoiceSet):
|
|
20
|
+
"""Platform types for load balancer appliances.
|
|
21
|
+
|
|
22
|
+
Identifies the vendor or technology stack running the load balancer. This is a
|
|
23
|
+
required field on the LoadBalancer model. Common platforms include hardware
|
|
24
|
+
appliances (F5 BIG-IP, Citrix ADC), software-based solutions (HAProxy, NGINX),
|
|
25
|
+
and cloud-native services (AWS ELB/ALB, Azure LB). Use 'Other' for platforms
|
|
26
|
+
not listed here.
|
|
27
|
+
"""
|
|
28
|
+
key = 'LoadBalancer.platform'
|
|
29
|
+
|
|
30
|
+
PLATFORM_F5 = 'f5'
|
|
31
|
+
PLATFORM_HAPROXY = 'haproxy'
|
|
32
|
+
PLATFORM_CITRIX = 'citrix'
|
|
33
|
+
PLATFORM_NGINX = 'nginx'
|
|
34
|
+
PLATFORM_AWS = 'aws'
|
|
35
|
+
PLATFORM_AZURE = 'azure'
|
|
36
|
+
PLATFORM_OTHER = 'other'
|
|
37
|
+
|
|
38
|
+
CHOICES = [
|
|
39
|
+
(PLATFORM_F5, 'F5 BIG-IP'),
|
|
40
|
+
(PLATFORM_HAPROXY, 'HAProxy'),
|
|
41
|
+
(PLATFORM_CITRIX, 'Citrix ADC'),
|
|
42
|
+
(PLATFORM_NGINX, 'NGINX'),
|
|
43
|
+
(PLATFORM_AWS, 'AWS ELB/ALB'),
|
|
44
|
+
(PLATFORM_AZURE, 'Azure LB'),
|
|
45
|
+
(PLATFORM_OTHER, 'Other'),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LoadBalancerStatusChoices(ChoiceSet):
|
|
50
|
+
"""Operational lifecycle status for load balancers.
|
|
51
|
+
|
|
52
|
+
Tracks where a load balancer is in its lifecycle: planned (not yet deployed),
|
|
53
|
+
active (in production), maintenance (temporarily offline for work), or
|
|
54
|
+
decommissioned (retired). Each status has an associated colour that is displayed
|
|
55
|
+
as a badge in the NetBox UI.
|
|
56
|
+
"""
|
|
57
|
+
key = 'LoadBalancer.status'
|
|
58
|
+
|
|
59
|
+
STATUS_ACTIVE = 'active'
|
|
60
|
+
STATUS_PLANNED = 'planned'
|
|
61
|
+
STATUS_MAINTENANCE = 'maintenance'
|
|
62
|
+
STATUS_DECOMMISSIONED = 'decommissioned'
|
|
63
|
+
|
|
64
|
+
CHOICES = [
|
|
65
|
+
(STATUS_ACTIVE, 'Active', 'green'),
|
|
66
|
+
(STATUS_PLANNED, 'Planned', 'cyan'),
|
|
67
|
+
(STATUS_MAINTENANCE, 'Maintenance', 'yellow'),
|
|
68
|
+
(STATUS_DECOMMISSIONED, 'Decommissioned', 'gray'),
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class VirtualServerStatusChoices(ChoiceSet):
|
|
73
|
+
"""Operational status for virtual servers.
|
|
74
|
+
|
|
75
|
+
Indicates whether a virtual server is actively accepting traffic (active),
|
|
76
|
+
not yet deployed (planned), or intentionally taken offline (disabled).
|
|
77
|
+
"""
|
|
78
|
+
key = 'VirtualServer.status'
|
|
79
|
+
|
|
80
|
+
STATUS_ACTIVE = 'active'
|
|
81
|
+
STATUS_PLANNED = 'planned'
|
|
82
|
+
STATUS_DISABLED = 'disabled'
|
|
83
|
+
|
|
84
|
+
CHOICES = [
|
|
85
|
+
(STATUS_ACTIVE, 'Active', 'green'),
|
|
86
|
+
(STATUS_PLANNED, 'Planned', 'cyan'),
|
|
87
|
+
(STATUS_DISABLED, 'Disabled', 'red'),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class VirtualServerProtocolChoices(ChoiceSet):
|
|
92
|
+
"""Network protocol that a virtual server listener accepts.
|
|
93
|
+
|
|
94
|
+
Determines what kind of traffic the virtual server handles. TCP and UDP are
|
|
95
|
+
layer-4 protocols, while HTTP and HTTPS are layer-7 (application-level).
|
|
96
|
+
The choice of protocol affects how the load balancer inspects and routes traffic.
|
|
97
|
+
"""
|
|
98
|
+
key = 'VirtualServer.protocol'
|
|
99
|
+
|
|
100
|
+
PROTOCOL_TCP = 'tcp'
|
|
101
|
+
PROTOCOL_UDP = 'udp'
|
|
102
|
+
PROTOCOL_HTTP = 'http'
|
|
103
|
+
PROTOCOL_HTTPS = 'https'
|
|
104
|
+
PROTOCOL_OTHER = 'other'
|
|
105
|
+
|
|
106
|
+
CHOICES = [
|
|
107
|
+
(PROTOCOL_TCP, 'TCP'),
|
|
108
|
+
(PROTOCOL_UDP, 'UDP'),
|
|
109
|
+
(PROTOCOL_HTTP, 'HTTP'),
|
|
110
|
+
(PROTOCOL_HTTPS, 'HTTPS'),
|
|
111
|
+
(PROTOCOL_OTHER, 'Other'),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class PoolMethodChoices(ChoiceSet):
|
|
116
|
+
"""Load balancing algorithm used to distribute traffic among pool members.
|
|
117
|
+
|
|
118
|
+
- Round Robin: requests are sent to each member in turn, cycling through the list.
|
|
119
|
+
- Least Connections: the member with the fewest active connections gets the next
|
|
120
|
+
request, which is useful when request processing times vary.
|
|
121
|
+
- IP Hash: the client's source IP determines which member receives the request,
|
|
122
|
+
providing session persistence (sticky sessions).
|
|
123
|
+
- Weighted: traffic is distributed proportionally based on each member's weight
|
|
124
|
+
value, allowing more powerful servers to handle more traffic.
|
|
125
|
+
"""
|
|
126
|
+
key = 'Pool.method'
|
|
127
|
+
|
|
128
|
+
METHOD_ROUND_ROBIN = 'round-robin'
|
|
129
|
+
METHOD_LEAST_CONNECTIONS = 'least-connections'
|
|
130
|
+
METHOD_IP_HASH = 'ip-hash'
|
|
131
|
+
METHOD_WEIGHTED = 'weighted'
|
|
132
|
+
METHOD_OTHER = 'other'
|
|
133
|
+
|
|
134
|
+
CHOICES = [
|
|
135
|
+
(METHOD_ROUND_ROBIN, 'Round Robin'),
|
|
136
|
+
(METHOD_LEAST_CONNECTIONS, 'Least Connections'),
|
|
137
|
+
(METHOD_IP_HASH, 'IP Hash'),
|
|
138
|
+
(METHOD_WEIGHTED, 'Weighted'),
|
|
139
|
+
(METHOD_OTHER, 'Other'),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PoolProtocolChoices(ChoiceSet):
|
|
144
|
+
"""Network protocol used for communication between the load balancer and pool members.
|
|
145
|
+
|
|
146
|
+
This may differ from the virtual server's protocol. For example, a virtual server
|
|
147
|
+
might accept HTTPS traffic from clients while the pool communicates with backend
|
|
148
|
+
members over plain HTTP (SSL offloading).
|
|
149
|
+
"""
|
|
150
|
+
key = 'Pool.protocol'
|
|
151
|
+
|
|
152
|
+
PROTOCOL_TCP = 'tcp'
|
|
153
|
+
PROTOCOL_UDP = 'udp'
|
|
154
|
+
PROTOCOL_HTTP = 'http'
|
|
155
|
+
PROTOCOL_HTTPS = 'https'
|
|
156
|
+
PROTOCOL_OTHER = 'other'
|
|
157
|
+
|
|
158
|
+
CHOICES = [
|
|
159
|
+
(PROTOCOL_TCP, 'TCP'),
|
|
160
|
+
(PROTOCOL_UDP, 'UDP'),
|
|
161
|
+
(PROTOCOL_HTTP, 'HTTP'),
|
|
162
|
+
(PROTOCOL_HTTPS, 'HTTPS'),
|
|
163
|
+
(PROTOCOL_OTHER, 'Other'),
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class PoolMemberStatusChoices(ChoiceSet):
|
|
168
|
+
"""Operational status for individual pool members.
|
|
169
|
+
|
|
170
|
+
- Active: the member is healthy and receiving new traffic.
|
|
171
|
+
- Drain: the member stops accepting new connections but finishes processing
|
|
172
|
+
existing ones. This is used for graceful removal during maintenance.
|
|
173
|
+
- Disabled: the member is completely offline and receives no traffic at all.
|
|
174
|
+
"""
|
|
175
|
+
key = 'PoolMember.status'
|
|
176
|
+
|
|
177
|
+
STATUS_ACTIVE = 'active'
|
|
178
|
+
STATUS_DRAIN = 'drain'
|
|
179
|
+
STATUS_DISABLED = 'disabled'
|
|
180
|
+
|
|
181
|
+
CHOICES = [
|
|
182
|
+
(STATUS_ACTIVE, 'Active', 'green'),
|
|
183
|
+
(STATUS_DRAIN, 'Drain', 'yellow'),
|
|
184
|
+
(STATUS_DISABLED, 'Disabled', 'red'),
|
|
185
|
+
]
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Filter sets for querying and filtering load balancer objects.
|
|
2
|
+
|
|
3
|
+
Each FilterSet class defines the fields that can be used to filter a model's queryset
|
|
4
|
+
in both the web UI list views and the REST API. They extend NetBox's
|
|
5
|
+
``NetBoxModelFilterSet``, which provides built-in support for tags, custom fields,
|
|
6
|
+
and the ``q`` search parameter.
|
|
7
|
+
|
|
8
|
+
Filter types used:
|
|
9
|
+
- ``MultipleChoiceFilter``: allows filtering by one or more choice values
|
|
10
|
+
(e.g. ``?status=active&status=planned``).
|
|
11
|
+
- ``ModelMultipleChoiceFilter``: allows filtering by one or more related object IDs
|
|
12
|
+
(e.g. ``?loadbalancer_id=1&loadbalancer_id=2``).
|
|
13
|
+
|
|
14
|
+
The ``search()`` method on each FilterSet handles the ``q`` parameter from the search
|
|
15
|
+
box on list views. It defines which model fields are searched when a user types a
|
|
16
|
+
free-text query.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import django_filters
|
|
20
|
+
from netbox.filtersets import NetBoxModelFilterSet
|
|
21
|
+
|
|
22
|
+
from .models import LoadBalancer, VirtualServer, Pool, PoolMember
|
|
23
|
+
from .choices import (
|
|
24
|
+
LoadBalancerPlatformChoices,
|
|
25
|
+
LoadBalancerStatusChoices,
|
|
26
|
+
VirtualServerStatusChoices,
|
|
27
|
+
VirtualServerProtocolChoices,
|
|
28
|
+
PoolMethodChoices,
|
|
29
|
+
PoolProtocolChoices,
|
|
30
|
+
PoolMemberStatusChoices,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LoadBalancerFilterSet(NetBoxModelFilterSet):
|
|
35
|
+
"""Filters load balancers by platform, status, device, site, and tenant.
|
|
36
|
+
|
|
37
|
+
The Meta.fields tuple lists all fields that can be filtered via URL query
|
|
38
|
+
parameters. Fields like ``device_id``, ``site_id``, and ``tenant_id`` are
|
|
39
|
+
automatically handled by NetBoxModelFilterSet because they are standard
|
|
40
|
+
ForeignKey fields on the model.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
platform = django_filters.MultipleChoiceFilter(choices=LoadBalancerPlatformChoices)
|
|
44
|
+
status = django_filters.MultipleChoiceFilter(choices=LoadBalancerStatusChoices)
|
|
45
|
+
|
|
46
|
+
class Meta:
|
|
47
|
+
model = LoadBalancer
|
|
48
|
+
fields = ('id', 'name', 'platform', 'status', 'device_id', 'site_id', 'tenant_id')
|
|
49
|
+
|
|
50
|
+
def search(self, queryset, name, value):
|
|
51
|
+
"""Handle the ``q`` search parameter from the list view search box.
|
|
52
|
+
|
|
53
|
+
Performs a case-insensitive substring match on the load balancer's name field.
|
|
54
|
+
For example, searching for "prod" would match "Production-LB-01".
|
|
55
|
+
"""
|
|
56
|
+
return queryset.filter(name__icontains=value)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class PoolFilterSet(NetBoxModelFilterSet):
|
|
60
|
+
"""Filters pools by load balancer, method, and protocol.
|
|
61
|
+
|
|
62
|
+
The ``loadbalancer_id`` filter uses ``ModelMultipleChoiceFilter`` which accepts
|
|
63
|
+
one or more load balancer IDs and returns only pools belonging to those load
|
|
64
|
+
balancers.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
loadbalancer_id = django_filters.ModelMultipleChoiceFilter(
|
|
68
|
+
queryset=LoadBalancer.objects.all(),
|
|
69
|
+
)
|
|
70
|
+
method = django_filters.MultipleChoiceFilter(choices=PoolMethodChoices)
|
|
71
|
+
protocol = django_filters.MultipleChoiceFilter(choices=PoolProtocolChoices)
|
|
72
|
+
|
|
73
|
+
class Meta:
|
|
74
|
+
model = Pool
|
|
75
|
+
fields = ('id', 'name', 'loadbalancer_id', 'method', 'protocol')
|
|
76
|
+
|
|
77
|
+
def search(self, queryset, name, value):
|
|
78
|
+
"""Handle the ``q`` search parameter by matching against the pool name."""
|
|
79
|
+
return queryset.filter(name__icontains=value)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class VirtualServerFilterSet(NetBoxModelFilterSet):
|
|
83
|
+
"""Filters virtual servers by load balancer, status, protocol, port, pool, and tenant.
|
|
84
|
+
|
|
85
|
+
This is the most feature-rich FilterSet in the plugin, reflecting the number of
|
|
86
|
+
filterable attributes on the VirtualServer model. The ``pool_id`` filter allows
|
|
87
|
+
finding all virtual servers that point to a specific pool.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
loadbalancer_id = django_filters.ModelMultipleChoiceFilter(
|
|
91
|
+
queryset=LoadBalancer.objects.all(),
|
|
92
|
+
)
|
|
93
|
+
status = django_filters.MultipleChoiceFilter(choices=VirtualServerStatusChoices)
|
|
94
|
+
protocol = django_filters.MultipleChoiceFilter(choices=VirtualServerProtocolChoices)
|
|
95
|
+
pool_id = django_filters.ModelMultipleChoiceFilter(
|
|
96
|
+
queryset=Pool.objects.all(),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
class Meta:
|
|
100
|
+
model = VirtualServer
|
|
101
|
+
fields = ('id', 'name', 'loadbalancer_id', 'status', 'protocol', 'port', 'pool_id', 'tenant_id')
|
|
102
|
+
|
|
103
|
+
def search(self, queryset, name, value):
|
|
104
|
+
"""Handle the ``q`` search parameter by matching against the virtual server name."""
|
|
105
|
+
return queryset.filter(name__icontains=value)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class PoolMemberFilterSet(NetBoxModelFilterSet):
|
|
109
|
+
"""Filters pool members by pool, status, device, IP address, port, weight, and priority.
|
|
110
|
+
|
|
111
|
+
This FilterSet exposes the widest range of filterable fields, allowing operators
|
|
112
|
+
to find members by their parent pool, operational status, associated device or
|
|
113
|
+
IP, specific port numbers, or weight/priority values.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
pool_id = django_filters.ModelMultipleChoiceFilter(
|
|
117
|
+
queryset=Pool.objects.all(),
|
|
118
|
+
)
|
|
119
|
+
status = django_filters.MultipleChoiceFilter(choices=PoolMemberStatusChoices)
|
|
120
|
+
|
|
121
|
+
class Meta:
|
|
122
|
+
model = PoolMember
|
|
123
|
+
fields = ('id', 'name', 'pool_id', 'ip_address_id', 'device_id', 'port', 'weight', 'priority', 'status')
|
|
124
|
+
|
|
125
|
+
def search(self, queryset, name, value):
|
|
126
|
+
"""Handle the ``q`` search parameter by matching against the pool member name."""
|
|
127
|
+
return queryset.filter(name__icontains=value)
|