lint fixes

This commit is contained in:
ryanmerolle 2022-07-29 16:15:27 +00:00
parent df1e3d34f9
commit 41a3f29217
28 changed files with 1455 additions and 737 deletions

View File

@ -6,7 +6,7 @@
PLUGINS = [
"netbox_access_lists",
]
]
PLUGINS_CONFIG = {
"netbox_access_lists": {},

View File

@ -9,4 +9,5 @@ pycodestyle
pydocstyle
pylint
pylint-django
wily
yapf

View File

@ -17,7 +17,7 @@ repos:
args:
- '--py36-plus'
- repo: 'https://github.com/asottile/pyupgrade'
rev: v2.34.0
rev: v2.37.3
hooks:
- id: pyupgrade
args:
@ -42,11 +42,9 @@ repos:
hooks:
- id: black
- repo: 'https://github.com/igorshubovych/markdownlint-cli'
rev: v0.31.1
rev: v0.32.1
hooks:
- id: markdownlint
- repo: local
hooks:
- repo: local
hooks:
- id: wily

View File

@ -6,10 +6,11 @@ from extras.plugins import PluginConfig
class NetBoxAccessListsConfig(PluginConfig):
name = 'netbox_access_lists'
verbose_name = 'Access Lists'
description = 'Manage simple ACLs in NetBox'
version = '0.1'
base_url = 'access-lists'
name = "netbox_access_lists"
verbose_name = "Access Lists"
description = "Manage simple ACLs in NetBox"
version = "0.1"
base_url = "access-lists"
config = NetBoxAccessListsConfig

View File

@ -6,75 +6,88 @@ while Django itself handles the database abstraction.
from netbox.api.serializers import WritableNestedSerializer
from rest_framework import serializers
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment,
ACLStandardRule)
from ..models import (
AccessList,
ACLExtendedRule,
ACLInterfaceAssignment,
ACLStandardRule,
)
__all__ = [
'NestedAccessListSerializer',
'NestedACLInterfaceAssignmentSerializer',
'NestedACLStandardRuleSerializer',
'NestedACLExtendedRuleSerializer'
"NestedAccessListSerializer",
"NestedACLInterfaceAssignmentSerializer",
"NestedACLStandardRuleSerializer",
"NestedACLExtendedRuleSerializer",
]
class NestedAccessListSerializer(WritableNestedSerializer):
"""
Defines the nested serializer for the django AccessList model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:accesslist-detail'
view_name="plugins-api:netbox_access_lists-api:accesslist-detail",
)
class Meta:
"""
Associates the django model ACLStandardRule & fields to the nested serializer.
"""
model = AccessList
fields = ('id', 'url', 'display', 'name')
fields = ("id", "url", "display", "name")
class NestedACLInterfaceAssignmentSerializer(WritableNestedSerializer):
"""
Defines the nested serializer for the django ACLInterfaceAssignment model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclinterfaceassignment-detail'
view_name="plugins-api:netbox_access_lists-api:aclinterfaceassignment-detail",
)
class Meta:
"""
Associates the django model ACLInterfaceAssignment & fields to the nested serializer.
"""
model = ACLInterfaceAssignment
fields = ('id', 'url', 'display', 'access_list')
fields = ("id", "url", "display", "access_list")
class NestedACLStandardRuleSerializer(WritableNestedSerializer):
"""
Defines the nested serializer for the django ACLStandardRule model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclstandardrule-detail'
view_name="plugins-api:netbox_access_lists-api:aclstandardrule-detail",
)
class Meta:
"""
Associates the django model ACLStandardRule & fields to the nested serializer.
"""
model = ACLStandardRule
fields = ('id', 'url', 'display', 'index')
fields = ("id", "url", "display", "index")
class NestedACLExtendedRuleSerializer(WritableNestedSerializer):
"""
Defines the nested serializer for the django ACLExtendedRule model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclextendedrule-detail'
view_name="plugins-api:netbox_access_lists-api:aclextendedrule-detail",
)
class Meta:
"""
Associates the django model ACLExtendedRule & fields to the nested serializer.
"""
model = ACLExtendedRule
fields = ('id', 'url', 'display', 'index')
fields = ("id", "url", "display", "index")

View File

@ -4,50 +4,60 @@ while Django itself handles the database abstraction.
"""
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from drf_yasg.utils import swagger_serializer_method
from ipam.api.serializers import NestedPrefixSerializer
from django.core.exceptions import ObjectDoesNotExist
from netbox.api import ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer
from rest_framework import serializers
from utilities.api import get_serializer_for_model
from ..constants import (ACL_HOST_ASSIGNMENT_MODELS,
ACL_INTERFACE_ASSIGNMENT_MODELS)
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment,
ACLStandardRule)
from .nested_serializers import (NestedAccessListSerializer,
NestedACLExtendedRuleSerializer,
NestedACLInterfaceAssignmentSerializer,
NestedACLStandardRuleSerializer)
from ..constants import ACL_HOST_ASSIGNMENT_MODELS, ACL_INTERFACE_ASSIGNMENT_MODELS
from ..models import (
AccessList,
ACLExtendedRule,
ACLInterfaceAssignment,
ACLStandardRule,
)
from .nested_serializers import (
NestedAccessListSerializer,
NestedACLExtendedRuleSerializer,
NestedACLInterfaceAssignmentSerializer,
NestedACLStandardRuleSerializer,
)
__all__ = [
'AccessListSerializer',
'ACLInterfaceAssignmentSerializer',
'ACLStandardRuleSerializer',
'ACLExtendedRuleSerializer'
"AccessListSerializer",
"ACLInterfaceAssignmentSerializer",
"ACLStandardRuleSerializer",
"ACLExtendedRuleSerializer",
]
# Sets a standard error message for ACL rules with an action of remark, but no remark set.
error_message_no_remark = 'Action is set to remark, you MUST add a remark.'
error_message_no_remark = "Action is set to remark, you MUST add a remark."
# Sets a standard error message for ACL rules with an action of remark, but no source_prefix is set.
error_message_action_remark_source_prefix_set = 'Action is set to remark, Source Prefix CANNOT be set.'
error_message_action_remark_source_prefix_set = (
"Action is set to remark, Source Prefix CANNOT be set."
)
# Sets a standard error message for ACL rules with an action not set to remark, but no remark is set.
error_message_remark_without_action_remark = 'CANNOT set remark unless action is set to remark.'
error_message_remark_without_action_remark = (
"CANNOT set remark unless action is set to remark."
)
# Sets a standard error message for ACL rules no associated to an ACL of the same type.
error_message_acl_type = 'Provided parent Access List is not of right type.'
error_message_acl_type = "Provided parent Access List is not of right type."
class AccessListSerializer(NetBoxModelSerializer):
"""
Defines the serializer for the django AccessList model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:accesslist-detail'
view_name="plugins-api:netbox_access_lists-api:accesslist-detail",
)
rule_count = serializers.IntegerField(read_only=True)
assigned_object_type = ContentTypeField(
queryset=ContentType.objects.filter(ACL_HOST_ASSIGNMENT_MODELS)
queryset=ContentType.objects.filter(ACL_HOST_ASSIGNMENT_MODELS),
)
assigned_object = serializers.SerializerMethodField(read_only=True)
@ -55,16 +65,30 @@ class AccessListSerializer(NetBoxModelSerializer):
"""
Associates the django model AccessList & fields to the serializer.
"""
model = AccessList
fields = (
'id', 'url', 'display', 'name', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'type', 'default_action', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'rule_count'
"id",
"url",
"display",
"name",
"assigned_object_type",
"assigned_object_id",
"assigned_object",
"type",
"default_action",
"comments",
"tags",
"custom_fields",
"created",
"last_updated",
"rule_count",
)
@swagger_serializer_method(serializer_or_field=serializers.DictField)
def get_assigned_object(self, obj):
serializer = get_serializer_for_model(obj.assigned_object, prefix='Nested')
context = {'request': self.context['request']}
serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested")
context = {"request": self.context["request"]}
return serializer(obj.assigned_object, context=context).data
def validate(self, data):
@ -76,18 +100,26 @@ class AccessListSerializer(NetBoxModelSerializer):
error_message = {}
# Check that the GFK object is valid.
if 'assigned_object_type' in data and 'assigned_object_id' in data:
if "assigned_object_type" in data and "assigned_object_id" in data:
try:
assigned_object = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id'])
assigned_object = data["assigned_object_type"].get_object_for_this_type(
id=data["assigned_object_id"]
)
except ObjectDoesNotExist:
# Sets a standard error message for invalid GFK
error_message_invalid_gfk = f"Invalid assigned_object {data['assigned_object_type']} ID {data['assigned_object_id']}"
error_message['assigned_object_type'] = [error_message_invalid_gfk]
error_message['assigned_object_id'] = [error_message_invalid_gfk]
error_message["assigned_object_type"] = [error_message_invalid_gfk]
error_message["assigned_object_id"] = [error_message_invalid_gfk]
# Check if Access List has no existing rules before change the Access List's type.
if self.instance and self.instance.type != data.get('type') and self.instance.rule_count > 0:
error_message['type'] = ['This ACL has ACL rules associated, CANNOT change ACL type.']
if (
self.instance
and self.instance.type != data.get("type")
and self.instance.rule_count > 0
):
error_message["type"] = [
"This ACL has ACL rules associated, CANNOT change ACL type."
]
if error_message:
raise serializers.ValidationError(error_message)
@ -99,11 +131,12 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer):
"""
Defines the serializer for the django ACLInterfaceAssignment model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclinterfaceassignment-detail'
view_name="plugins-api:netbox_access_lists-api:aclinterfaceassignment-detail",
)
assigned_object_type = ContentTypeField(
queryset=ContentType.objects.filter(ACL_INTERFACE_ASSIGNMENT_MODELS)
queryset=ContentType.objects.filter(ACL_INTERFACE_ASSIGNMENT_MODELS),
)
assigned_object = serializers.SerializerMethodField(read_only=True)
@ -111,16 +144,27 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer):
"""
Associates the django model ACLInterfaceAssignment & fields to the serializer.
"""
model = ACLInterfaceAssignment
fields = (
'id', 'url', 'access_list', 'direction', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'comments', 'tags', 'custom_fields', 'created',
'last_updated'
"id",
"url",
"access_list",
"direction",
"assigned_object_type",
"assigned_object_id",
"assigned_object",
"comments",
"tags",
"custom_fields",
"created",
"last_updated",
)
@swagger_serializer_method(serializer_or_field=serializers.DictField)
def get_assigned_object(self, obj):
serializer = get_serializer_for_model(obj.assigned_object, prefix='Nested')
context = {'request': self.context['request']}
serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested")
context = {"request": self.context["request"]}
return serializer(obj.assigned_object, context=context).data
def validate(self, data):
@ -130,56 +174,81 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer):
- Check that the associated interface's parent host has the selected ACL defined.
"""
error_message = {}
acl_host = data['access_list'].assigned_object
acl_host = data["access_list"].assigned_object
# Check that the GFK object is vlaid.
if 'assigned_object_type' in data and 'assigned_object_id' in data:
if "assigned_object_type" in data and "assigned_object_id" in data:
try:
assigned_object = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id'])
assigned_object = data["assigned_object_type"].get_object_for_this_type(
id=data["assigned_object_id"]
)
except ObjectDoesNotExist:
# Sets a standard error message for invalid GFK
error_message_invalid_gfk = f"Invalid assigned_object {data['assigned_object_type']} ID {data['assigned_object_id']}"
error_message['assigned_object_type'] = [error_message_invalid_gfk]
error_message['assigned_object_id'] = [error_message_invalid_gfk]
error_message["assigned_object_type"] = [error_message_invalid_gfk]
error_message["assigned_object_id"] = [error_message_invalid_gfk]
if data['assigned_object_type'].model == 'interface':
interface_host = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id']).device
elif data['assigned_object_type'].model == 'vminterface':
interface_host = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id']).virtual_machine
if data["assigned_object_type"].model == "interface":
interface_host = (
data["assigned_object_type"]
.get_object_for_this_type(id=data["assigned_object_id"])
.device
)
elif data["assigned_object_type"].model == "vminterface":
interface_host = (
data["assigned_object_type"]
.get_object_for_this_type(id=data["assigned_object_id"])
.virtual_machine
)
# Check that the associated interface's parent host has the selected ACL defined.
if acl_host != interface_host:
error_acl_not_assigned_to_host = "Access List not present on the selected interface's host."
error_message['access_list'] = [error_acl_not_assigned_to_host]
error_message['assigned_object_id'] = [error_acl_not_assigned_to_host]
error_acl_not_assigned_to_host = (
"Access List not present on the selected interface's host."
)
error_message["access_list"] = [error_acl_not_assigned_to_host]
error_message["assigned_object_id"] = [error_acl_not_assigned_to_host]
if error_message:
raise serializers.ValidationError(error_message)
return super().validate(data)
class ACLStandardRuleSerializer(NetBoxModelSerializer):
"""
Defines the serializer for the django ACLStandardRule model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclstandardrule-detail'
view_name="plugins-api:netbox_access_lists-api:aclstandardrule-detail",
)
access_list = NestedAccessListSerializer()
source_prefix = NestedPrefixSerializer(
required=False,
allow_null=True,
default=None
default=None,
)
class Meta:
"""
Associates the django model ACLStandardRule & fields to the serializer.
"""
model = ACLStandardRule
fields = (
'id', 'url', 'display', 'access_list', 'index', 'action', 'tags', 'description',
'remark', 'created', 'custom_fields', 'last_updated', 'source_prefix'
"id",
"url",
"display",
"access_list",
"index",
"action",
"tags",
"description",
"remark",
"created",
"custom_fields",
"last_updated",
"source_prefix",
)
def validate(self, data):
@ -191,11 +260,13 @@ class ACLStandardRuleSerializer(NetBoxModelSerializer):
error_message = {}
# Check if action set to remark, but no remark set.
if data.get('action') == 'remark' and data.get('remark') is None:
error_message['remark'] = [error_message_no_remark]
if data.get("action") == "remark" and data.get("remark") is None:
error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set.
if data.get('source_prefix'):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set]
if data.get("source_prefix"):
error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
if error_message:
raise serializers.ValidationError(error_message)
@ -207,30 +278,46 @@ class ACLExtendedRuleSerializer(NetBoxModelSerializer):
"""
Defines the serializer for the django ACLExtendedRule model & associates it to a view.
"""
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_access_lists-api:aclextendedrule-detail'
view_name="plugins-api:netbox_access_lists-api:aclextendedrule-detail",
)
access_list = NestedAccessListSerializer()
source_prefix = NestedPrefixSerializer(
required=False,
allow_null=True,
default=None
default=None,
)
destination_prefix = NestedPrefixSerializer(
required=False,
allow_null=True,
default=None
default=None,
)
class Meta:
"""
Associates the django model ACLExtendedRule & fields to the serializer.
"""
model = ACLExtendedRule
fields = (
'id', 'url', 'display', 'access_list', 'index', 'action', 'tags', 'description',
'created', 'custom_fields', 'last_updated', 'source_prefix', 'source_ports',
'destination_prefix', 'destination_ports', 'protocol', 'remark',
"id",
"url",
"display",
"access_list",
"index",
"action",
"tags",
"description",
"created",
"custom_fields",
"last_updated",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
"remark",
)
def validate(self, data):
@ -247,23 +334,33 @@ class ACLExtendedRuleSerializer(NetBoxModelSerializer):
error_message = {}
# Check if action set to remark, but no remark set.
if data.get('action') == 'remark' and data.get('remark') is None:
error_message['remark'] = [error_message_no_remark]
if data.get("action") == "remark" and data.get("remark") is None:
error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set.
if data.get('source_prefix'):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set]
if data.get("source_prefix"):
error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
# Check if action set to remark, but source_ports set.
if data.get('source_ports'):
error_message['source_ports'] = ['Action is set to remark, Source Ports CANNOT be set.']
if data.get("source_ports"):
error_message["source_ports"] = [
"Action is set to remark, Source Ports CANNOT be set."
]
# Check if action set to remark, but destination_prefix set.
if data.get('destination_prefix'):
error_message['destination_prefix'] = ['Action is set to remark, Destination Prefix CANNOT be set.']
if data.get("destination_prefix"):
error_message["destination_prefix"] = [
"Action is set to remark, Destination Prefix CANNOT be set."
]
# Check if action set to remark, but destination_ports set.
if data.get('destination_ports'):
error_message['destination_ports'] = ['Action is set to remark, Destination Ports CANNOT be set.']
if data.get("destination_ports"):
error_message["destination_ports"] = [
"Action is set to remark, Destination Ports CANNOT be set."
]
# Check if action set to remark, but protocol set.
if data.get('protocol'):
error_message['protocol'] = ['Action is set to remark, Protocol CANNOT be set.']
if data.get("protocol"):
error_message["protocol"] = [
"Action is set to remark, Protocol CANNOT be set."
]
if error_message:
raise serializers.ValidationError(error_message)

View File

@ -6,12 +6,12 @@ from netbox.api.routers import NetBoxRouter
from . import views
app_name = 'netbox_access_list'
app_name = "netbox_access_list"
router = NetBoxRouter()
router.register('access-lists', views.AccessListViewSet)
router.register('interface-assignments', views.ACLInterfaceAssignmentViewSet)
router.register('standard-acl-rules', views.ACLStandardRuleViewSet)
router.register('extended-acl-rules', views.ACLExtendedRuleViewSet)
router.register("access-lists", views.AccessListViewSet)
router.register("interface-assignments", views.ACLInterfaceAssignmentViewSet)
router.register("standard-acl-rules", views.ACLStandardRuleViewSet)
router.register("extended-acl-rules", views.ACLExtendedRuleViewSet)
urlpatterns = router.urls

View File

@ -8,15 +8,17 @@ from django.db.models import Count
from netbox.api.viewsets import NetBoxModelViewSet
from .. import filtersets, models
from .serializers import (AccessListSerializer, ACLExtendedRuleSerializer,
ACLInterfaceAssignmentSerializer,
ACLStandardRuleSerializer)
from .serializers import (
AccessListSerializer,
ACLExtendedRuleSerializer,
ACLInterfaceAssignmentSerializer,
ACLStandardRuleSerializer,
)
__all__ = [
'AccessListViewSet',
'ACLStandardRuleViewSet',
'ACLInterfaceAssignmentViewSet'
'ACLExtendedRuleViewSet',
"AccessListViewSet",
"ACLStandardRuleViewSet",
"ACLInterfaceAssignmentViewSet" "ACLExtendedRuleViewSet",
]
@ -24,8 +26,9 @@ class AccessListViewSet(NetBoxModelViewSet):
"""
Defines the view set for the django AccessList model & associates it to a view.
"""
queryset = models.AccessList.objects.prefetch_related('tags').annotate(
rule_count=Count('aclextendedrules') + Count('aclstandardrules')
queryset = models.AccessList.objects.prefetch_related("tags").annotate(
rule_count=Count("aclextendedrules") + Count("aclstandardrules"),
)
serializer_class = AccessListSerializer
filterset_class = filtersets.AccessListFilterSet
@ -35,7 +38,10 @@ class ACLInterfaceAssignmentViewSet(NetBoxModelViewSet):
"""
Defines the view set for the django ACLInterfaceAssignment model & associates it to a view.
"""
queryset = models.ACLInterfaceAssignment.objects.prefetch_related('access_list', 'tags')
queryset = models.ACLInterfaceAssignment.objects.prefetch_related(
"access_list", "tags"
)
serializer_class = ACLInterfaceAssignmentSerializer
filterset_class = filtersets.ACLInterfaceAssignmentFilterSet
@ -44,8 +50,11 @@ class ACLStandardRuleViewSet(NetBoxModelViewSet):
"""
Defines the view set for the django ACLStandardRule model & associates it to a view.
"""
queryset = models.ACLStandardRule.objects.prefetch_related(
'access_list', 'tags', 'source_prefix'
"access_list",
"tags",
"source_prefix",
)
serializer_class = ACLStandardRuleSerializer
filterset_class = filtersets.ACLStandardRuleFilterSet
@ -55,8 +64,12 @@ class ACLExtendedRuleViewSet(NetBoxModelViewSet):
"""
Defines the view set for the django ACLExtendedRule model & associates it to a view.
"""
queryset = models.ACLExtendedRule.objects.prefetch_related(
'access_list', 'tags', 'source_prefix', 'destination_prefix',
"access_list",
"tags",
"source_prefix",
"destination_prefix",
)
serializer_class = ACLExtendedRuleSerializer
filterset_class = filtersets.ACLExtendedRuleFilterSet

View File

@ -5,12 +5,12 @@ Defines the various choices to be used by the models, forms, and other plugin sp
from utilities.choices import ChoiceSet
__all__ = (
'ACLActionChoices',
'ACLAssignmentDirectionChoices',
'ACLProtocolChoices',
'ACLRuleActionChoices',
'ACLTypeChoices',
'ACLProtocolChoices',
"ACLActionChoices",
"ACLAssignmentDirectionChoices",
"ACLProtocolChoices",
"ACLRuleActionChoices",
"ACLTypeChoices",
"ACLProtocolChoices",
)
@ -18,14 +18,15 @@ class ACLActionChoices(ChoiceSet):
"""
Defines the choices availble for the Access Lists plugin specific to ACL default_action.
"""
ACTION_DENY = 'deny'
ACTION_PERMIT = 'permit'
ACTION_REJECT = 'reject'
ACTION_DENY = "deny"
ACTION_PERMIT = "permit"
ACTION_REJECT = "reject"
CHOICES = [
(ACTION_DENY, 'Deny', 'red'),
(ACTION_PERMIT, 'Permit', 'green'),
(ACTION_REJECT, 'Reject (Reset)', 'orange'),
(ACTION_DENY, "Deny", "red"),
(ACTION_PERMIT, "Permit", "green"),
(ACTION_REJECT, "Reject (Reset)", "orange"),
]
@ -33,14 +34,15 @@ class ACLRuleActionChoices(ChoiceSet):
"""
Defines the choices availble for the Access Lists plugin specific to ACL rule actions.
"""
ACTION_DENY = 'deny'
ACTION_PERMIT = 'permit'
ACTION_REMARK = 'remark'
ACTION_DENY = "deny"
ACTION_PERMIT = "permit"
ACTION_REMARK = "remark"
CHOICES = [
(ACTION_DENY, 'Deny', 'red'),
(ACTION_PERMIT, 'Permit', 'green'),
(ACTION_REMARK, 'Remark', 'blue'),
(ACTION_DENY, "Deny", "red"),
(ACTION_PERMIT, "Permit", "green"),
(ACTION_REMARK, "Remark", "blue"),
]
@ -50,8 +52,8 @@ class ACLAssignmentDirectionChoices(ChoiceSet):
"""
CHOICES = [
('ingress', 'Ingress', 'blue'),
('egress', 'Egress', 'purple'),
("ingress", "Ingress", "blue"),
("egress", "Egress", "purple"),
]
@ -59,9 +61,10 @@ class ACLTypeChoices(ChoiceSet):
"""
Defines the choices availble for the Access Lists plugin specific to ACL type.
"""
CHOICES = [
('extended', 'Extended', 'purple'),
('standard', 'Standard', 'blue'),
("extended", "Extended", "purple"),
("standard", "Standard", "blue"),
]
@ -69,8 +72,9 @@ class ACLProtocolChoices(ChoiceSet):
"""
Defines the choices availble for the Access Lists plugin specific to ACL Rule protocol.
"""
CHOICES = [
('icmp', 'ICMP', 'purple'),
('tcp', 'TCP', 'blue'),
('udp', 'UDP', 'orange'),
("icmp", "ICMP", "purple"),
("tcp", "TCP", "blue"),
("udp", "UDP", "orange"),
]

View File

@ -4,12 +4,12 @@ Constants for filters
from django.db.models import Q
ACL_HOST_ASSIGNMENT_MODELS = Q(
Q(app_label='dcim', model='device') |
Q(app_label='dcim', model='virtualchassis') |
Q(app_label='virtualization', model='virtualmachine')
Q(app_label="dcim", model="device")
| Q(app_label="dcim", model="virtualchassis")
| Q(app_label="virtualization", model="virtualmachine"),
)
ACL_INTERFACE_ASSIGNMENT_MODELS = Q(
Q(app_label='dcim', model='interface') |
Q(app_label='virtualization', model='vminterface')
Q(app_label="dcim", model="interface")
| Q(app_label="virtualization", model="vminterface"),
)

View File

@ -10,10 +10,10 @@ from virtualization.models import VirtualMachine, VMInterface
from .models import *
__all__ = (
'AccessListFilterSet',
'ACLStandardRuleFilterSet',
'ACLInterfaceAssignmentFilterSet',
'ACLExtendedRuleFilterSet',
"AccessListFilterSet",
"ACLStandardRuleFilterSet",
"ACLInterfaceAssignmentFilterSet",
"ACLExtendedRuleFilterSet",
)
@ -21,46 +21,60 @@ class AccessListFilterSet(NetBoxModelFilterSet):
"""
Define the filter set for the django model AccessList.
"""
device = django_filters.ModelMultipleChoiceFilter(
field_name='device__name',
field_name="device__name",
queryset=Device.objects.all(),
to_field_name='name',
label='Device (name)',
to_field_name="name",
label="Device (name)",
)
device_id = django_filters.ModelMultipleChoiceFilter(
field_name='device',
field_name="device",
queryset=Device.objects.all(),
label='Device (ID)',
label="Device (ID)",
)
virtual_chassis = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_chassis__name',
field_name="virtual_chassis__name",
queryset=VirtualChassis.objects.all(),
to_field_name='name',
label='Virtual Chassis (name)',
to_field_name="name",
label="Virtual Chassis (name)",
)
virtual_chassis_id = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_chassis',
field_name="virtual_chassis",
queryset=VirtualChassis.objects.all(),
label='Virtual Chassis (ID)',
label="Virtual Chassis (ID)",
)
virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__name',
field_name="virtual_machine__name",
queryset=VirtualMachine.objects.all(),
to_field_name='name',
label='Virtual Machine (name)',
to_field_name="name",
label="Virtual Machine (name)",
)
virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine',
field_name="virtual_machine",
queryset=VirtualMachine.objects.all(),
label='Virtual machine (ID)',
label="Virtual machine (ID)",
)
class Meta:
"""
Associates the django model AccessList & fields to the filter set.
"""
model = AccessList
fields = ('id', 'name', 'device', 'device_id', 'virtual_chassis', 'virtual_chassis_id', 'virtual_machine', 'virtual_machine_id', 'type', 'default_action', 'comments')
fields = (
"id",
"name",
"device",
"device_id",
"virtual_chassis",
"virtual_chassis_id",
"virtual_machine",
"virtual_machine_id",
"type",
"default_action",
"comments",
)
def search(self, queryset, name, value):
"""
@ -73,35 +87,45 @@ class ACLInterfaceAssignmentFilterSet(NetBoxModelFilterSet):
"""
Define the filter set for the django model ACLInterfaceAssignment.
"""
interface = django_filters.ModelMultipleChoiceFilter(
field_name='interface__name',
field_name="interface__name",
queryset=Interface.objects.all(),
to_field_name='name',
label='Interface (name)',
to_field_name="name",
label="Interface (name)",
)
interface_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface',
field_name="interface",
queryset=Interface.objects.all(),
label='Interface (ID)',
label="Interface (ID)",
)
vminterface = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__name',
field_name="vminterface__name",
queryset=VMInterface.objects.all(),
to_field_name='name',
label='VM Interface (name)',
to_field_name="name",
label="VM Interface (name)",
)
vminterface_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface',
field_name="vminterface",
queryset=VMInterface.objects.all(),
label='VM Interface (ID)',
label="VM Interface (ID)",
)
class Meta:
"""
Associates the django model ACLInterfaceAssignment & fields to the filter set.
"""
model = ACLInterfaceAssignment
fields = ('id', 'access_list', 'direction', 'interface', 'interface_id', 'vminterface', 'vminterface_id')
fields = (
"id",
"access_list",
"direction",
"interface",
"interface_id",
"vminterface",
"vminterface_id",
)
def search(self, queryset, name, value):
"""
@ -119,8 +143,9 @@ class ACLStandardRuleFilterSet(NetBoxModelFilterSet):
"""
Associates the django model ACLStandardRule & fields to the filter set.
"""
model = ACLStandardRule
fields = ('id', 'access_list', 'index', 'action')
fields = ("id", "access_list", "index", "action")
def search(self, queryset, name, value):
"""
@ -138,8 +163,9 @@ class ACLExtendedRuleFilterSet(NetBoxModelFilterSet):
"""
Associates the django model ACLExtendedRule & fields to the filter set.
"""
model = ACLExtendedRule
fields = ('id', 'access_list', 'index', 'action', 'protocol')
fields = ("id", "access_list", "index", "action", "protocol")
def search(self, queryset, name, value):
"""

View File

@ -2,13 +2,15 @@
Import each of the directory's scripts.
"""
#from .bulk_create import *
# from .bulk_create import *
from .bulk_edit import *
#from .bulk_import import *
#from .connections import *
# from .bulk_import import *
# from .connections import *
from .filtersets import *
#from .formsets import *
# from .formsets import *
from .models import *
#from .object_create import *
#from .object_import import *
# from .object_create import *
# from .object_import import *

View File

@ -7,19 +7,23 @@ from django import forms
from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe
from netbox.forms import NetBoxModelBulkEditForm
from utilities.forms import (ChoiceField, DynamicModelChoiceField,
StaticSelect, add_blank_choice)
from utilities.forms import (
ChoiceField,
DynamicModelChoiceField,
StaticSelect,
add_blank_choice,
)
from virtualization.models import VirtualMachine
from ..choices import ACLActionChoices, ACLTypeChoices
from ..models import AccessList
#__all__ = (
# __all__ = (
# 'AccessListBulkEditForm',
#)
# )
#class AccessListBulkEditForm(NetBoxModelBulkEditForm):
# class AccessListBulkEditForm(NetBoxModelBulkEditForm):
# model = AccessList
#
# region = DynamicModelChoiceField(

View File

@ -2,27 +2,39 @@
Defines each django model's GUI filter/search options.
"""
from dcim.models import (Device, Interface, Region, Site, SiteGroup,
VirtualChassis)
from dcim.models import Device, Interface, Region, Site, SiteGroup, VirtualChassis
from django import forms
from ipam.models import Prefix
from netbox.forms import NetBoxModelFilterSetForm
from utilities.forms import (ChoiceField, DynamicModelChoiceField,
StaticSelect, StaticSelectMultiple,
TagFilterField, add_blank_choice)
from utilities.forms import (
ChoiceField,
DynamicModelChoiceField,
StaticSelect,
StaticSelectMultiple,
TagFilterField,
add_blank_choice,
)
from virtualization.models import VirtualMachine, VMInterface
from ..choices import (ACLActionChoices, ACLAssignmentDirectionChoices,
ACLProtocolChoices, ACLRuleActionChoices,
ACLTypeChoices)
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment,
ACLStandardRule)
from ..choices import (
ACLActionChoices,
ACLAssignmentDirectionChoices,
ACLProtocolChoices,
ACLRuleActionChoices,
ACLTypeChoices,
)
from ..models import (
AccessList,
ACLExtendedRule,
ACLInterfaceAssignment,
ACLStandardRule,
)
__all__ = (
'AccessListFilterForm',
'ACLInterfaceAssignmentFilterForm',
'ACLStandardRuleFilterForm',
'ACLExtendedRuleFilterForm',
"AccessListFilterForm",
"ACLInterfaceAssignmentFilterForm",
"ACLStandardRuleFilterForm",
"ACLExtendedRuleFilterForm",
)
@ -30,6 +42,7 @@ class AccessListFilterForm(NetBoxModelFilterSetForm):
"""
GUI filter form to search the django AccessList model.
"""
model = AccessList
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
@ -38,40 +51,40 @@ class AccessListFilterForm(NetBoxModelFilterSetForm):
site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label='Site Group'
label="Site Group",
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
required=False,
)
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
query_params={
'region': '$region',
'group_id': '$site_group',
'site_id': '$site',
"region": "$region",
"group_id": "$site_group",
"site_id": "$site",
},
required=False
required=False,
)
type = ChoiceField(
choices=add_blank_choice(ACLTypeChoices),
required=False,
initial='',
initial="",
widget=StaticSelect(),
)
default_action = ChoiceField(
choices=add_blank_choice(ACLActionChoices),
required=False,
initial='',
initial="",
widget=StaticSelect(),
label='Default Action',
label="Default Action",
)
tag = TagFilterField(model)
fieldsets = (
(None, ('q', 'tag')),
('Host Details', ('region', 'site_group', 'site', 'device')),
('ACL Details', ('type', 'default_action')),
(None, ("q", "tag")),
("Host Details", ("region", "site_group", "site", "device")),
("ACL Details", ("type", "default_action")),
)
@ -79,6 +92,7 @@ class ACLInterfaceAssignmentFilterForm(NetBoxModelFilterSetForm):
"""
GUI filter form to search the django AccessList model.
"""
model = ACLInterfaceAssignment
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
@ -87,84 +101,85 @@ class ACLInterfaceAssignmentFilterForm(NetBoxModelFilterSetForm):
site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label='Site Group'
label="Site Group",
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
required=False,
)
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
query_params={
'region': '$region',
'group_id': '$site_group',
'site_id': '$site',
"region": "$region",
"group_id": "$site_group",
"site_id": "$site",
},
required=False
required=False,
)
interface = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
query_params={
'device_id': '$device'
}
"device_id": "$device",
},
)
virtual_machine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label='Virtual Machine',
label="Virtual Machine",
)
vminterface = DynamicModelChoiceField(
queryset=VMInterface.objects.all(),
required=False,
query_params={
'virtual_machine_id': '$virtual_machine'
"virtual_machine_id": "$virtual_machine",
},
label='Interface'
label="Interface",
)
access_list = DynamicModelChoiceField(
queryset=AccessList.objects.all(),
query_params={
'assigned_object': '$device',
"assigned_object": "$device",
},
label='Access List',
label="Access List",
)
direction = ChoiceField(
choices=add_blank_choice(ACLAssignmentDirectionChoices),
required=False,
initial='',
initial="",
widget=StaticSelect(),
)
tag = TagFilterField(model)
#fieldsets = (
# fieldsets = (
# (None, ('q', 'tag')),
# ('Host Details', ('region', 'site_group', 'site', 'device')),
# ('ACL Details', ('type', 'default_action')),
#)
# )
class ACLStandardRuleFilterForm(NetBoxModelFilterSetForm):
"""
GUI filter form to search the django ACLStandardRule model.
"""
model = ACLStandardRule
tag = TagFilterField(model)
source_prefix = forms.ModelMultipleChoiceField(
queryset=Prefix.objects.all(),
required=False,
widget=StaticSelectMultiple(),
label='Source Prefix',
label="Source Prefix",
)
action = forms.ChoiceField(
choices=add_blank_choice(ACLRuleActionChoices),
required=False,
initial='',
initial="",
widget=StaticSelect(),
)
fieldsets = (
(None, ('q', 'tag')),
('Rule Details', ('action', 'source_prefix',)),
(None, ("q", "tag")),
("Rule Details", ("action", "source_prefix")),
)
@ -172,37 +187,38 @@ class ACLExtendedRuleFilterForm(NetBoxModelFilterSetForm):
"""
GUI filter form to search the django ACLExtendedRule model.
"""
model = ACLExtendedRule
index = forms.IntegerField(
required=False
required=False,
)
tag = TagFilterField(model)
action = forms.ChoiceField(
choices=add_blank_choice(ACLRuleActionChoices),
required=False,
widget=StaticSelect(),
initial='',
initial="",
)
source_prefix = forms.ModelMultipleChoiceField(
queryset=Prefix.objects.all(),
required=False,
widget=StaticSelectMultiple(),
label='Source Prefix',
label="Source Prefix",
)
desintation_prefix = forms.ModelMultipleChoiceField(
queryset=Prefix.objects.all(),
required=False,
widget=StaticSelectMultiple(),
label='Destination Prefix',
label="Destination Prefix",
)
protocol = ChoiceField(
choices=add_blank_choice(ACLProtocolChoices),
required=False,
widget=StaticSelect(),
initial='',
initial="",
)
fieldsets = (
(None, ('q', 'tag')),
('Rule Details', ('action', 'source_prefix', 'desintation_prefix', 'protocol')),
(None, ("q", "tag")),
("Rule Details", ("action", "source_prefix", "desintation_prefix", "protocol")),
)

View File

@ -2,41 +2,55 @@
Defines each django model's GUI form to add or edit objects for each django model.
"""
from dcim.models import (Device, Interface, Region, Site, SiteGroup,
VirtualChassis)
from dcim.models import Device, Interface, Region, Site, SiteGroup, VirtualChassis
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.safestring import mark_safe
from extras.models import Tag
from ipam.models import Prefix
from netbox.forms import NetBoxModelForm
from utilities.forms import (CommentField, DynamicModelChoiceField,
DynamicModelMultipleChoiceField)
from utilities.forms import (
CommentField,
DynamicModelChoiceField,
DynamicModelMultipleChoiceField,
)
from virtualization.models import VirtualMachine, VMInterface
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment,
ACLStandardRule)
from ..models import (
AccessList,
ACLExtendedRule,
ACLInterfaceAssignment,
ACLStandardRule,
)
__all__ = (
'AccessListForm',
'ACLInterfaceAssignmentForm',
'ACLStandardRuleForm',
'ACLExtendedRuleForm',
"AccessListForm",
"ACLInterfaceAssignmentForm",
"ACLStandardRuleForm",
"ACLExtendedRuleForm",
)
# Sets a standard mark_safe help_text value to be used by the various classes
help_text_acl_rule_logic = mark_safe('<b>*Note:</b> CANNOT be set if action is set to remark.')
help_text_acl_rule_logic = mark_safe(
"<b>*Note:</b> CANNOT be set if action is set to remark."
)
# Sets a standard help_text value to be used by the various classes for acl action
help_text_acl_action = 'Action the rule will take (remark, deny, or allow).'
help_text_acl_action = "Action the rule will take (remark, deny, or allow)."
# Sets a standard help_text value to be used by the various classes for acl index
help_text_acl_rule_index = 'Determines the order of the rule in the ACL processing. AKA Sequence Number.'
help_text_acl_rule_index = (
"Determines the order of the rule in the ACL processing. AKA Sequence Number."
)
# Sets a standard error message for ACL rules with an action of remark, but no remark set.
error_message_no_remark = 'Action is set to remark, you MUST add a remark.'
error_message_no_remark = "Action is set to remark, you MUST add a remark."
# Sets a standard error message for ACL rules with an action of remark, but no source_prefix is set.
error_message_action_remark_source_prefix_set = 'Action is set to remark, Source Prefix CANNOT be set.'
error_message_action_remark_source_prefix_set = (
"Action is set to remark, Source Prefix CANNOT be set."
)
# Sets a standard error message for ACL rules with an action not set to remark, but no remark is set.
error_message_remark_without_action_remark = 'CANNOT set remark unless action is set to remark.'
error_message_remark_without_action_remark = (
"CANNOT set remark unless action is set to remark."
)
class AccessListForm(NetBoxModelForm):
@ -44,6 +58,7 @@ class AccessListForm(NetBoxModelForm):
GUI form to add or edit an AccessList.
Requires a device, a name, a type, and a default_action.
"""
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False,
@ -51,59 +66,73 @@ class AccessListForm(NetBoxModelForm):
site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label='Site Group'
label="Site Group",
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
required=False,
)
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
required=False,
query_params={
'region': '$region',
'group_id': '$site_group',
'site_id': '$site',
"region": "$region",
"group_id": "$site_group",
"site_id": "$site",
},
)
virtual_chassis = DynamicModelChoiceField(
queryset=VirtualChassis.objects.all(),
required=False,
label='Virtual Chassis',
label="Virtual Chassis",
)
virtual_machine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label='Virtual Machine',
label="Virtual Machine",
)
comments = CommentField()
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
required=False,
)
class Meta:
model = AccessList
fields = ('region', 'site_group', 'site', 'device', 'virtual_machine', 'virtual_chassis', 'name', 'type', 'default_action', 'comments', 'tags')
fields = (
"region",
"site_group",
"site",
"device",
"virtual_machine",
"virtual_chassis",
"name",
"type",
"default_action",
"comments",
"tags",
)
help_texts = {
'default_action': 'The default behavior of the ACL.',
'name': 'The name uniqueness per device is case insensitive.',
'type': mark_safe('<b>*Note:</b> CANNOT be changed if ACL Rules are assoicated to this Access List.'),
"default_action": "The default behavior of the ACL.",
"name": "The name uniqueness per device is case insensitive.",
"type": mark_safe(
"<b>*Note:</b> CANNOT be changed if ACL Rules are assoicated to this Access List."
),
}
def __init__(self, *args, **kwargs):
# Initialize helper selectors
instance = kwargs.get('instance')
initial = kwargs.get('initial', {}).copy()
instance = kwargs.get("instance")
initial = kwargs.get("initial", {}).copy()
if instance:
if type(instance.assigned_object) is Device:
initial['device'] = instance.assigned_object
initial["device"] = instance.assigned_object
elif type(instance.assigned_object) is VirtualChassis:
initial['virtual_chassis'] = instance.assigned_object
initial["virtual_chassis"] = instance.assigned_object
elif type(instance.assigned_object) is VirtualMachine:
initial['virtual_machine'] = instance.assigned_object
kwargs['initial'] = initial
initial["virtual_machine"] = instance.assigned_object
kwargs["initial"] = initial
super().__init__(*args, **kwargs)
@ -117,40 +146,62 @@ class AccessListForm(NetBoxModelForm):
"""
cleaned_data = super().clean()
error_message = {}
if self.errors.get('name'):
if self.errors.get("name"):
return cleaned_data
name = cleaned_data.get('name')
acl_type = cleaned_data.get('type')
device = cleaned_data.get('device')
virtual_chassis = cleaned_data.get('virtual_chassis')
virtual_machine = cleaned_data.get('virtual_machine')
name = cleaned_data.get("name")
acl_type = cleaned_data.get("type")
device = cleaned_data.get("device")
virtual_chassis = cleaned_data.get("virtual_chassis")
virtual_machine = cleaned_data.get("virtual_machine")
# Check if more than one host type selected.
if (device and virtual_chassis) or (device and virtual_machine) or (virtual_chassis and virtual_machine):
raise forms.ValidationError('Access Lists must be assigned to one host (either a device, virtual chassis or virtual machine) at a time.')
if (
(device and virtual_chassis)
or (device and virtual_machine)
or (virtual_chassis and virtual_machine)
):
raise forms.ValidationError(
"Access Lists must be assigned to one host (either a device, virtual chassis or virtual machine) at a time."
)
# Check if no hosts selected.
if not device and not virtual_chassis and not virtual_machine:
raise forms.ValidationError('Access Lists must be assigned to a device, virtual chassis or virtual machine.')
raise forms.ValidationError(
"Access Lists must be assigned to a device, virtual chassis or virtual machine."
)
if device:
host_type = 'device'
host_type = "device"
existing_acls = AccessList.objects.filter(name=name, device=device).exists()
elif virtual_chassis:
host_type = 'virtual_chassis'
existing_acls = AccessList.objects.filter(name=name, virtual_chassis=virtual_chassis).exists()
host_type = "virtual_chassis"
existing_acls = AccessList.objects.filter(
name=name, virtual_chassis=virtual_chassis
).exists()
elif virtual_machine:
host_type = 'virtual_machine'
existing_acls = AccessList.objects.filter(name=name, virtual_machine=virtual_machine).exists()
host_type = "virtual_machine"
existing_acls = AccessList.objects.filter(
name=name, virtual_machine=virtual_machine
).exists()
host = cleaned_data.get(host_type)
# Check if duplicate entry.
if ('name' in self.changed_data or host_type in self.changed_data) and existing_acls:
error_same_acl_name = 'An ACL with this name is already associated to this host.'
error_message |= {host_type: [error_same_acl_name], 'name': [error_same_acl_name]}
if (
"name" in self.changed_data or host_type in self.changed_data
) and existing_acls:
error_same_acl_name = (
"An ACL with this name is already associated to this host."
)
error_message |= {
host_type: [error_same_acl_name],
"name": [error_same_acl_name],
}
# Check if Access List has no existing rules before change the Access List's type.
if (acl_type == 'extended' and self.instance.aclstandardrules.exists()) or (acl_type == 'standard' and self.instance.aclextendedrules.exists()):
error_message['type'] = ['This ACL has ACL rules associated, CANNOT change ACL type.']
if (acl_type == "extended" and self.instance.aclstandardrules.exists()) or (
acl_type == "standard" and self.instance.aclextendedrules.exists()
):
error_message["type"] = [
"This ACL has ACL rules associated, CANNOT change ACL type."
]
if error_message:
raise forms.ValidationError(error_message)
@ -159,7 +210,11 @@ class AccessListForm(NetBoxModelForm):
def save(self, *args, **kwargs):
# Set assigned object
self.instance.assigned_object = self.cleaned_data.get('device') or self.cleaned_data.get('virtual_chassis') or self.cleaned_data.get('virtual_machine')
self.instance.assigned_object = (
self.cleaned_data.get("device")
or self.cleaned_data.get("virtual_chassis")
or self.cleaned_data.get("virtual_machine")
)
return super().save(*args, **kwargs)
@ -169,78 +224,88 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm):
GUI form to add or edit ACL Host Object assignments
Requires an access_list, a name, a type, and a default_action.
"""
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
required=False,
query_params={
# Need to pass ACL device to it
# Need to pass ACL device to it
},
)
interface = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
query_params={
'device_id': '$device'
}
"device_id": "$device",
},
)
virtual_machine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label='Virtual Machine',
label="Virtual Machine",
)
vminterface = DynamicModelChoiceField(
queryset=VMInterface.objects.all(),
required=False,
query_params={
'virtual_machine_id': '$virtual_machine'
"virtual_machine_id": "$virtual_machine",
},
label='VM Interface'
label="VM Interface",
)
#virtual_chassis = DynamicModelChoiceField(
# virtual_chassis = DynamicModelChoiceField(
# queryset=VirtualChassis.objects.all(),
# required=False,
# label='Virtual Chassis',
#)
# )
access_list = DynamicModelChoiceField(
queryset=AccessList.objects.all(),
#query_params={
# query_params={
# 'assigned_object': '$device',
# 'assigned_object': '$virtual_machine',
#},
label='Access List',
help_text=mark_safe('<b>*Note:</b> Access List must be present on the device already.')
# },
label="Access List",
help_text=mark_safe(
"<b>*Note:</b> Access List must be present on the device already."
),
)
comments = CommentField()
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
required=False,
)
def __init__(self, *args, **kwargs):
# Initialize helper selectors
instance = kwargs.get('instance')
initial = kwargs.get('initial', {}).copy()
instance = kwargs.get("instance")
initial = kwargs.get("initial", {}).copy()
if instance:
if type(instance.assigned_object) is Interface:
initial['interface'] = instance.assigned_object
initial['device'] = 'device'
initial["interface"] = instance.assigned_object
initial["device"] = "device"
elif type(instance.assigned_object) is VMInterface:
initial['vminterface'] = instance.assigned_object
initial['virtual_machine'] = 'virtual_machine'
kwargs['initial'] = initial
initial["vminterface"] = instance.assigned_object
initial["virtual_machine"] = "virtual_machine"
kwargs["initial"] = initial
super().__init__(*args, **kwargs)
class Meta:
model = ACLInterfaceAssignment
fields = (
'access_list', 'direction', 'device', 'interface', 'virtual_machine',
'vminterface', 'comments', 'tags',
"access_list",
"direction",
"device",
"interface",
"virtual_machine",
"vminterface",
"comments",
"tags",
)
help_texts = {
'direction': mark_safe('<b>*Note:</b> CANNOT assign 2 ACLs to the same interface & direction.'),
"direction": mark_safe(
"<b>*Note:</b> CANNOT assign 2 ACLs to the same interface & direction."
),
}
def clean(self):
@ -255,47 +320,81 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm):
"""
cleaned_data = super().clean()
error_message = {}
access_list = cleaned_data.get('access_list')
direction = cleaned_data.get('direction')
interface = cleaned_data.get('interface')
vminterface = cleaned_data.get('vminterface')
assigned_object = cleaned_data.get('assigned_object')
access_list = cleaned_data.get("access_list")
direction = cleaned_data.get("direction")
interface = cleaned_data.get("interface")
vminterface = cleaned_data.get("vminterface")
assigned_object = cleaned_data.get("assigned_object")
if interface:
assigned_object = interface
assigned_object_type = 'interface'
host_type = 'device'
assigned_object_type = "interface"
host_type = "device"
host = Interface.objects.get(pk=assigned_object.pk).device
elif vminterface:
assigned_object = vminterface
assigned_object_type = 'vminterface'
host_type = 'virtual_machine'
assigned_object_type = "vminterface"
host_type = "virtual_machine"
host = VMInterface.objects.get(pk=assigned_object.pk).virtual_machine
if interface or vminterface:
assigned_object_id = VMInterface.objects.get(pk=assigned_object.pk).pk
assigned_object_type_id = ContentType.objects.get_for_model(assigned_object).pk
assigned_object_type_id = ContentType.objects.get_for_model(
assigned_object
).pk
access_list_host = AccessList.objects.get(pk=access_list.pk).assigned_object
# Check if both interface and vminterface are set.
if interface and vminterface:
error_too_many_interfaces = 'Access Lists must be assigned to one type of interface at a time (VM interface or physical interface)'
error_too_many_hosts = 'Access Lists must be assigned to one type of device at a time (VM or physical device).'
error_message |= {'device': [error_too_many_hosts], 'interface': [error_too_many_interfaces], 'virtual_machine': [error_too_many_hosts], 'vminterface': [error_too_many_interfaces]}
error_too_many_interfaces = "Access Lists must be assigned to one type of interface at a time (VM interface or physical interface)"
error_too_many_hosts = "Access Lists must be assigned to one type of device at a time (VM or physical device)."
error_message |= {
"device": [error_too_many_hosts],
"interface": [error_too_many_interfaces],
"virtual_machine": [error_too_many_hosts],
"vminterface": [error_too_many_interfaces],
}
# Check if neither interface or vminterface are set.
elif not (interface or vminterface):
error_no_interface = 'An Access List assignment but specify an Interface or VM Interface.'
error_message |= {'interface': [error_no_interface], 'vminterface': [error_no_interface]}
error_no_interface = (
"An Access List assignment but specify an Interface or VM Interface."
)
error_message |= {
"interface": [error_no_interface],
"vminterface": [error_no_interface],
}
# Check that an interface's parent device/virtual_machine is assigned to the Access List.
elif access_list_host != host:
error_acl_not_assigned_to_host = 'Access List not present on selected host.'
error_message |= {'access_list': [error_acl_not_assigned_to_host], assigned_object_type: [error_acl_not_assigned_to_host], host_type: [error_acl_not_assigned_to_host]}
error_acl_not_assigned_to_host = "Access List not present on selected host."
error_message |= {
"access_list": [error_acl_not_assigned_to_host],
assigned_object_type: [error_acl_not_assigned_to_host],
host_type: [error_acl_not_assigned_to_host],
}
# Check for duplicate entry.
elif ACLInterfaceAssignment.objects.filter(access_list=access_list, assigned_object_id=assigned_object_id, assigned_object_type=assigned_object_type_id, direction=direction).exists():
error_duplicate_entry = 'An ACL with this name is already associated to this interface & direction.'
error_message |= {'access_list': [error_duplicate_entry], 'direction': [error_duplicate_entry], assigned_object_type: [error_duplicate_entry]}
elif ACLInterfaceAssignment.objects.filter(
access_list=access_list,
assigned_object_id=assigned_object_id,
assigned_object_type=assigned_object_type_id,
direction=direction,
).exists():
error_duplicate_entry = "An ACL with this name is already associated to this interface & direction."
error_message |= {
"access_list": [error_duplicate_entry],
"direction": [error_duplicate_entry],
assigned_object_type: [error_duplicate_entry],
}
# Check that the interface does not have an existing ACL applied in the direction already.
elif ACLInterfaceAssignment.objects.filter(assigned_object_id=assigned_object_id, assigned_object_type=assigned_object_type_id, direction=direction).exists():
error_interface_already_assigned = 'Interfaces can only have 1 Access List assigned in each direction.'
error_message |= {'direction': [error_interface_already_assigned], assigned_object_type: [error_interface_already_assigned]}
elif ACLInterfaceAssignment.objects.filter(
assigned_object_id=assigned_object_id,
assigned_object_type=assigned_object_type_id,
direction=direction,
).exists():
error_interface_already_assigned = (
"Interfaces can only have 1 Access List assigned in each direction."
)
error_message |= {
"direction": [error_interface_already_assigned],
assigned_object_type: [error_interface_already_assigned],
}
if error_message:
raise forms.ValidationError(error_message)
@ -303,7 +402,9 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm):
def save(self, *args, **kwargs):
# Set assigned object
self.instance.assigned_object = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface')
self.instance.assigned_object = self.cleaned_data.get(
"interface"
) or self.cleaned_data.get("vminterface")
return super().save(*args, **kwargs)
@ -314,40 +415,50 @@ class ACLStandardRuleForm(NetBoxModelForm):
Requires an access_list, an index, and ACL rule type.
See the clean function for logic on other field requirements.
"""
access_list = DynamicModelChoiceField(
queryset=AccessList.objects.all(),
query_params={
'type': 'standard'
"type": "standard",
},
help_text=mark_safe('<b>*Note:</b> This field will only display Standard ACLs.'),
label='Access List',
help_text=mark_safe(
"<b>*Note:</b> This field will only display Standard ACLs."
),
label="Access List",
)
source_prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
help_text=help_text_acl_rule_logic,
label='Source Prefix',
label="Source Prefix",
)
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
required=False,
)
fieldsets = (
('Access List Details', ('access_list', 'description', 'tags')),
('Rule Definition', ('index', 'action', 'remark', 'source_prefix')),
("Access List Details", ("access_list", "description", "tags")),
("Rule Definition", ("index", "action", "remark", "source_prefix")),
)
class Meta:
model = ACLStandardRule
fields = (
'access_list', 'index', 'action', 'remark', 'source_prefix',
'tags', 'description'
"access_list",
"index",
"action",
"remark",
"source_prefix",
"tags",
"description",
)
help_texts = {
'index': help_text_acl_rule_index,
'action': help_text_acl_action,
'remark': mark_safe('<b>*Note:</b> CANNOT be set if source prefix OR action is set.'),
"index": help_text_acl_rule_index,
"action": help_text_acl_action,
"remark": mark_safe(
"<b>*Note:</b> CANNOT be set if source prefix OR action is set."
),
}
def clean(self):
@ -362,16 +473,18 @@ class ACLStandardRuleForm(NetBoxModelForm):
# No need to check for unique_together since there is no usage of GFK
if cleaned_data.get('action') == 'remark':
if cleaned_data.get("action") == "remark":
# Check if action set to remark, but no remark set.
if not cleaned_data.get('remark'):
error_message['remark'] = [error_message_no_remark]
if not cleaned_data.get("remark"):
error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set.
if cleaned_data.get('source_prefix'):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set]
if cleaned_data.get("source_prefix"):
error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
# Check remark set, but action not set to remark.
elif cleaned_data.get('remark'):
error_message['remark'] = [error_message_remark_without_action_remark]
elif cleaned_data.get("remark"):
error_message["remark"] = [error_message_remark_without_action_remark]
if error_message:
raise forms.ValidationError(error_message)
@ -384,49 +497,74 @@ class ACLExtendedRuleForm(NetBoxModelForm):
Requires an access_list, an index, and ACL rule type.
See the clean function for logic on other field requirements.
"""
access_list = DynamicModelChoiceField(
queryset=AccessList.objects.all(),
query_params={
'type': 'extended'
"type": "extended",
},
help_text=mark_safe('<b>*Note:</b> This field will only display Extended ACLs.'),
label='Access List',
help_text=mark_safe(
"<b>*Note:</b> This field will only display Extended ACLs."
),
label="Access List",
)
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
required=False,
)
source_prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
help_text=help_text_acl_rule_logic,
label='Source Prefix',
label="Source Prefix",
)
destination_prefix = DynamicModelChoiceField(
queryset=Prefix.objects.all(),
required=False,
help_text=help_text_acl_rule_logic,
label='Destination Prefix',
label="Destination Prefix",
)
fieldsets = (
('Access List Details', ('access_list', 'description', 'tags')),
('Rule Definition', ('index', 'action', 'remark', 'source_prefix', 'source_ports', 'destination_prefix', 'destination_ports', 'protocol',)),
("Access List Details", ("access_list", "description", "tags")),
(
"Rule Definition",
(
"index",
"action",
"remark",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
),
),
)
class Meta:
model = ACLExtendedRule
fields = (
'access_list', 'index', 'action', 'remark', 'source_prefix',
'source_ports', 'destination_prefix', 'destination_ports', 'protocol',
'tags', 'description'
"access_list",
"index",
"action",
"remark",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
"tags",
"description",
)
help_texts = {
'action': help_text_acl_action,
'destination_ports': help_text_acl_rule_logic,
'index': help_text_acl_rule_index,
'protocol': help_text_acl_rule_logic,
'remark': mark_safe('<b>*Note:</b> CANNOT be set if action is not set to remark.'),
'source_ports': help_text_acl_rule_logic,
"action": help_text_acl_action,
"destination_ports": help_text_acl_rule_logic,
"index": help_text_acl_rule_index,
"protocol": help_text_acl_rule_logic,
"remark": mark_safe(
"<b>*Note:</b> CANNOT be set if action is not set to remark."
),
"source_ports": help_text_acl_rule_logic,
}
def clean(self):
@ -446,28 +584,38 @@ class ACLExtendedRuleForm(NetBoxModelForm):
# No need to check for unique_together since there is no usage of GFK
if cleaned_data.get('action') == 'remark':
if cleaned_data.get("action") == "remark":
# Check if action set to remark, but no remark set.
if not cleaned_data.get('remark'):
error_message['remark'] = [error_message_no_remark]
if not cleaned_data.get("remark"):
error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set.
if cleaned_data.get('source_prefix'):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set]
if cleaned_data.get("source_prefix"):
error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
# Check if action set to remark, but source_ports set.
if cleaned_data.get('source_ports'):
error_message['source_ports'] = ['Action is set to remark, Source Ports CANNOT be set.']
if cleaned_data.get("source_ports"):
error_message["source_ports"] = [
"Action is set to remark, Source Ports CANNOT be set."
]
# Check if action set to remark, but destination_prefix set.
if cleaned_data.get('destination_prefix'):
error_message['destination_prefix'] = ['Action is set to remark, Destination Prefix CANNOT be set.']
if cleaned_data.get("destination_prefix"):
error_message["destination_prefix"] = [
"Action is set to remark, Destination Prefix CANNOT be set."
]
# Check if action set to remark, but destination_ports set.
if cleaned_data.get('destination_ports'):
error_message['destination_ports'] = ['Action is set to remark, Destination Ports CANNOT be set.']
if cleaned_data.get("destination_ports"):
error_message["destination_ports"] = [
"Action is set to remark, Destination Ports CANNOT be set."
]
# Check if action set to remark, but protocol set.
if cleaned_data.get('protocol'):
error_message['protocol'] = ['Action is set to remark, Protocol CANNOT be set.']
if cleaned_data.get("protocol"):
error_message["protocol"] = [
"Action is set to remark, Protocol CANNOT be set."
]
# Check if action not set to remark, but remark set.
elif cleaned_data.get('remark'):
error_message['remark'] = [error_message_remark_without_action_remark]
elif cleaned_data.get("remark"):
error_message["remark"] = [error_message_remark_without_action_remark]
if error_message:
raise forms.ValidationError(error_message)

View File

@ -9,10 +9,10 @@ from netbox.graphql.types import NetBoxObjectType
from . import filtersets, models
__all__ = (
'AccessListType',
'ACLInterfaceAssignmentType',
'ACLExtendedRuleType',
'ACLStandardRuleType',
"AccessListType",
"ACLInterfaceAssignmentType",
"ACLExtendedRuleType",
"ACLStandardRuleType",
)
#
@ -29,8 +29,9 @@ class AccessListType(NetBoxObjectType):
"""
Associates the filterset, fields, and model for the django model AccessList.
"""
model = models.AccessList
fields = '__all__'
fields = "__all__"
filterset_class = filtersets.AccessListFilterSet
@ -43,8 +44,9 @@ class ACLInterfaceAssignmentType(NetBoxObjectType):
"""
Associates the filterset, fields, and model for the django model ACLInterfaceAssignment.
"""
model = models.ACLInterfaceAssignment
fields = '__all__'
fields = "__all__"
filterset_class = filtersets.ACLInterfaceAssignmentFilterSet
@ -57,8 +59,9 @@ class ACLExtendedRuleType(NetBoxObjectType):
"""
Associates the filterset, fields, and model for the django model ACLExtendedRule.
"""
model = models.ACLExtendedRule
fields = '__all__'
fields = "__all__"
filterset_class = filtersets.ACLExtendedRuleFilterSet
@ -71,10 +74,12 @@ class ACLStandardRuleType(NetBoxObjectType):
"""
Associates the filterset, fields, and model for the django model ACLStandardRule.
"""
model = models.ACLStandardRule
fields = '__all__'
fields = "__all__"
filterset_class = filtersets.ACLStandardRuleFilterSet
#
# Queries
#
@ -94,4 +99,5 @@ class Query(ObjectType):
acl_standard_rule = ObjectField(ACLStandardRuleType)
acl_standard_rule_list = ObjectListField(ACLStandardRuleType)
schema = Query

View File

@ -8,9 +8,8 @@ import django.db.models.deletion
import taggit.managers
from django.db import migrations, models
__all__ = (
'Migration',
)
__all__ = ("Migration",)
class Migration(migrations.Migration):
"""
@ -20,100 +19,258 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('extras', '0072_created_datetimefield'),
('ipam', '0057_created_datetimefield'),
("extras", "0072_created_datetimefield"),
("ipam", "0057_created_datetimefield"),
]
operations = [
migrations.CreateModel(
name='AccessList',
name="AccessList",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('name', models.CharField(max_length=500)),
('assigned_object_id', models.PositiveIntegerField()),
('assigned_object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
('type', models.CharField(max_length=100)),
('default_action', models.CharField(default='deny', max_length=30)),
('comments', models.TextField(blank=True)),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False
),
),
("created", models.DateTimeField(auto_now_add=True, null=True)),
("last_updated", models.DateTimeField(auto_now=True, null=True)),
(
"custom_field_data",
models.JSONField(
blank=True,
default=dict,
encoder=django.core.serializers.json.DjangoJSONEncoder,
),
),
("name", models.CharField(max_length=500)),
("assigned_object_id", models.PositiveIntegerField()),
(
"assigned_object_type",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="contenttypes.contenttype",
),
),
("type", models.CharField(max_length=100)),
("default_action", models.CharField(default="deny", max_length=30)),
("comments", models.TextField(blank=True)),
(
"tags",
taggit.managers.TaggableManager(
through="extras.TaggedItem", to="extras.Tag"
),
),
],
options={
'ordering': ('name', 'device'),
'unique_together': {('assigned_object_type', 'assigned_object_id', 'name')},
'verbose_name': 'Access List',
"ordering": ("name", "device"),
"unique_together": {
("assigned_object_type", "assigned_object_id", "name")
},
"verbose_name": "Access List",
},
),
migrations.CreateModel(
name='ACLInterfaceAssignment',
name="ACLInterfaceAssignment",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('access_list', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='aclinterfaceassignment', to='netbox_access_lists.accesslist')),
('direction', models.CharField(max_length=100)),
('assigned_object_id', models.PositiveIntegerField()),
('assigned_object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
('comments', models.TextField(blank=True)),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False
),
),
("created", models.DateTimeField(auto_now_add=True, null=True)),
("last_updated", models.DateTimeField(auto_now=True, null=True)),
(
"custom_field_data",
models.JSONField(
blank=True,
default=dict,
encoder=django.core.serializers.json.DjangoJSONEncoder,
),
),
(
"access_list",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="aclinterfaceassignment",
to="netbox_access_lists.accesslist",
),
),
("direction", models.CharField(max_length=100)),
("assigned_object_id", models.PositiveIntegerField()),
(
"assigned_object_type",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="contenttypes.contenttype",
),
),
("comments", models.TextField(blank=True)),
(
"tags",
taggit.managers.TaggableManager(
through="extras.TaggedItem", to="extras.Tag"
),
),
],
options={
'ordering': ('access_list', 'assigned_object_type', 'assigned_object_id', 'direction'),
'unique_together': {('assigned_object_type', 'assigned_object_id', 'access_list', 'direction')},
'verbose_name': 'ACL Interface Assignment',
"ordering": (
"access_list",
"assigned_object_type",
"assigned_object_id",
"direction",
),
"unique_together": {
(
"assigned_object_type",
"assigned_object_id",
"access_list",
"direction",
)
},
"verbose_name": "ACL Interface Assignment",
},
),
migrations.CreateModel(
name='ACLStandardRule',
name="ACLStandardRule",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
('access_list', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='aclstandardrules', to='netbox_access_lists.accesslist')),
('index', models.PositiveIntegerField()),
('description', models.CharField(blank=True, max_length=500)),
('action', models.CharField(max_length=30)),
('remark', models.CharField(blank=True, null=True, max_length=500)),
('source_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')),
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False
),
),
("created", models.DateTimeField(auto_now_add=True, null=True)),
("last_updated", models.DateTimeField(auto_now=True, null=True)),
(
"custom_field_data",
models.JSONField(
blank=True,
default=dict,
encoder=django.core.serializers.json.DjangoJSONEncoder,
),
),
(
"tags",
taggit.managers.TaggableManager(
through="extras.TaggedItem", to="extras.Tag"
),
),
(
"access_list",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="aclstandardrules",
to="netbox_access_lists.accesslist",
),
),
("index", models.PositiveIntegerField()),
("description", models.CharField(blank=True, max_length=500)),
("action", models.CharField(max_length=30)),
("remark", models.CharField(blank=True, null=True, max_length=500)),
(
"source_prefix",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="ipam.prefix",
),
),
],
options={
'ordering': ('access_list', 'index'),
'unique_together': {('access_list', 'index')},
'verbose_name': 'ACL Standard Rule',
"ordering": ("access_list", "index"),
"unique_together": {("access_list", "index")},
"verbose_name": "ACL Standard Rule",
},
),
migrations.CreateModel(
name='ACLExtendedRule',
name="ACLExtendedRule",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
('access_list', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='aclstandardrules', to='netbox_access_lists.accesslist')),
('index', models.PositiveIntegerField()),
('description', models.CharField(blank=True, max_length=500)),
('action', models.CharField(max_length=30)),
('remark', models.CharField(blank=True, null=True, max_length=500)),
('source_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')),
('source_ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(), blank=True, null=True, size=None)),
('destination_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')),
('destination_ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(), blank=True, null=True, size=None)),
('protocol', models.CharField(blank=True, max_length=30)),
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False
),
),
("created", models.DateTimeField(auto_now_add=True, null=True)),
("last_updated", models.DateTimeField(auto_now=True, null=True)),
(
"custom_field_data",
models.JSONField(
blank=True,
default=dict,
encoder=django.core.serializers.json.DjangoJSONEncoder,
),
),
(
"tags",
taggit.managers.TaggableManager(
through="extras.TaggedItem", to="extras.Tag"
),
),
(
"access_list",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="aclstandardrules",
to="netbox_access_lists.accesslist",
),
),
("index", models.PositiveIntegerField()),
("description", models.CharField(blank=True, max_length=500)),
("action", models.CharField(max_length=30)),
("remark", models.CharField(blank=True, null=True, max_length=500)),
(
"source_prefix",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="ipam.prefix",
),
),
(
"source_ports",
django.contrib.postgres.fields.ArrayField(
base_field=models.PositiveIntegerField(),
blank=True,
null=True,
size=None,
),
),
(
"destination_prefix",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="ipam.prefix",
),
),
(
"destination_ports",
django.contrib.postgres.fields.ArrayField(
base_field=models.PositiveIntegerField(),
blank=True,
null=True,
size=None,
),
),
("protocol", models.CharField(blank=True, max_length=30)),
],
options={
'ordering': ('access_list', 'index'),
'unique_together': {('access_list', 'index')},
'verbose_name': 'ACL Extended Rule',
"ordering": ("access_list", "index"),
"unique_together": {("access_list", "index")},
"verbose_name": "ACL Extended Rule",
},
),
#migrations.AddConstraint(
# migrations.AddConstraint(
# model_name='accesslist',
# constraint=models.UniqueConstraint(fields=('assigned_object_type', 'assigned_object_id'), name='accesslist_assigned_object'),
#),
# ),
]

View File

@ -11,9 +11,9 @@ from ..choices import *
from .access_lists import AccessList
__all__ = (
'ACLRule',
'ACLStandardRule',
'ACLExtendedRule',
"ACLRule",
"ACLStandardRule",
"ACLExtendedRule",
)
@ -22,20 +22,21 @@ class ACLRule(NetBoxModel):
Abstract model for ACL Rules.
Inherrited by both ACLStandardRule and ACLExtendedRule.
"""
access_list = models.ForeignKey(
on_delete=models.CASCADE,
to=AccessList,
verbose_name='Access List',
related_name='rules',
verbose_name="Access List",
related_name="rules",
)
index = models.PositiveIntegerField()
remark = models.CharField(
max_length=500,
blank=True
blank=True,
)
description = models.CharField(
max_length=500,
blank=True
blank=True,
)
action = models.CharField(
choices=ACLRuleActionChoices,
@ -45,13 +46,13 @@ class ACLRule(NetBoxModel):
blank=True,
null=True,
on_delete=models.PROTECT,
related_name='+',
to='ipam.Prefix',
verbose_name='Source Prefix'
related_name="+",
to="ipam.Prefix",
verbose_name="Source Prefix",
)
def __str__(self):
return f'{self.access_list}: Rule {self.index}'
return f"{self.access_list}: Rule {self.index}"
def get_action_color(self):
return ACLRuleActionChoices.colors.get(self.action)
@ -63,21 +64,23 @@ class ACLRule(NetBoxModel):
- ordering
- unique together
"""
abstract = True
ordering = ['access_list', 'index']
unique_together = ['access_list', 'index']
ordering = ["access_list", "index"]
unique_together = ["access_list", "index"]
class ACLStandardRule(ACLRule):
"""
Inherits ACLRule.
"""
access_list = models.ForeignKey(
on_delete=models.CASCADE,
to=AccessList,
verbose_name='Standard Access List',
limit_choices_to={'type': 'standard'},
related_name='aclstandardrules',
verbose_name="Standard Access List",
limit_choices_to={"type": "standard"},
related_name="aclstandardrules",
)
def get_absolute_url(self):
@ -85,7 +88,7 @@ class ACLStandardRule(ACLRule):
The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object.
"""
return reverse('plugins:netbox_access_lists:aclstandardrule', args=[self.pk])
return reverse("plugins:netbox_access_lists:aclstandardrule", args=[self.pk])
class Meta(ACLRule.Meta):
"""
@ -94,40 +97,43 @@ class ACLStandardRule(ACLRule):
- verbose name (for displaying in the GUI)
- verbose name plural (for displaying in the GUI)
"""
verbose_name='ACL Standard Rule'
verbose_name_plural='ACL Standard Rules'
verbose_name = "ACL Standard Rule"
verbose_name_plural = "ACL Standard Rules"
class ACLExtendedRule(ACLRule):
"""
Inherits ACLRule.
Add ACLExtendedRule specific fields: source_ports, desintation_prefix, destination_ports, and protocol
"""
access_list = models.ForeignKey(
on_delete=models.CASCADE,
to=AccessList,
verbose_name='Extended Access List',
limit_choices_to={'type': 'extended'},
related_name='aclextendedrules',
verbose_name="Extended Access List",
limit_choices_to={"type": "extended"},
related_name="aclextendedrules",
)
source_ports = ArrayField(
base_field=models.PositiveIntegerField(),
blank=True,
null=True,
verbose_name='Soure Ports'
verbose_name="Soure Ports",
)
destination_prefix = models.ForeignKey(
blank=True,
null=True,
on_delete=models.PROTECT,
related_name='+',
to='ipam.Prefix',
verbose_name='Destination Prefix'
related_name="+",
to="ipam.Prefix",
verbose_name="Destination Prefix",
)
destination_ports = ArrayField(
base_field=models.PositiveIntegerField(),
blank=True,
null=True,
verbose_name='Destination Ports'
verbose_name="Destination Ports",
)
protocol = models.CharField(
blank=True,
@ -140,7 +146,7 @@ class ACLExtendedRule(ACLRule):
The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object.
"""
return reverse('plugins:netbox_access_lists:aclextendedrule', args=[self.pk])
return reverse("plugins:netbox_access_lists:aclextendedrule", args=[self.pk])
def get_protocol_color(self):
return ACLProtocolChoices.colors.get(self.protocol)
@ -152,5 +158,6 @@ class ACLExtendedRule(ACLRule):
- verbose name (for displaying in the GUI)
- verbose name plural (for displaying in the GUI)
"""
verbose_name='ACL Extended Rule'
verbose_name_plural='ACL Extended Rules'
verbose_name = "ACL Extended Rule"
verbose_name_plural = "ACL Extended Rules"

View File

@ -3,8 +3,7 @@ Define the django models for this plugin.
"""
from dcim.models import Device, Interface, VirtualChassis
from django.contrib.contenttypes.fields import (GenericForeignKey,
GenericRelation)
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.validators import RegexValidator
from django.db import models
@ -13,54 +12,58 @@ from netbox.models import NetBoxModel
from virtualization.models import VirtualMachine, VMInterface
from ..choices import *
from ..constants import (ACL_HOST_ASSIGNMENT_MODELS,
ACL_INTERFACE_ASSIGNMENT_MODELS)
from ..constants import ACL_HOST_ASSIGNMENT_MODELS, ACL_INTERFACE_ASSIGNMENT_MODELS
__all__ = (
'AccessList',
'ACLInterfaceAssignment',
"AccessList",
"ACLInterfaceAssignment",
)
alphanumeric_plus = RegexValidator(r'^[0-9a-zA-Z,-,_]*$', 'Only alphanumeric, hyphens, and underscores characters are allowed.')
alphanumeric_plus = RegexValidator(
r"^[0-9a-zA-Z,-,_]*$",
"Only alphanumeric, hyphens, and underscores characters are allowed.",
)
class AccessList(NetBoxModel):
"""
Model defintion for Access Lists.
"""
name = models.CharField(
max_length=500,
validators=[alphanumeric_plus]
validators=[alphanumeric_plus],
)
assigned_object_type = models.ForeignKey(
to=ContentType,
limit_choices_to=ACL_HOST_ASSIGNMENT_MODELS,
on_delete=models.PROTECT
on_delete=models.PROTECT,
)
assigned_object_id = models.PositiveBigIntegerField()
assigned_object = GenericForeignKey(
ct_field='assigned_object_type',
fk_field='assigned_object_id'
ct_field="assigned_object_type",
fk_field="assigned_object_id",
)
type = models.CharField(
max_length=30,
choices=ACLTypeChoices
choices=ACLTypeChoices,
)
default_action = models.CharField(
default=ACLActionChoices.ACTION_DENY,
max_length=30,
choices=ACLActionChoices,
verbose_name='Default Action'
verbose_name="Default Action",
)
comments = models.TextField(
blank=True
blank=True,
)
class Meta:
unique_together = ['assigned_object_type', 'assigned_object_id', 'name']
ordering = ['assigned_object_type', 'assigned_object_id', 'name']
verbose_name = 'Access List'
verbose_name_plural = 'Access Lists'
unique_together = ["assigned_object_type", "assigned_object_id", "name"]
ordering = ["assigned_object_type", "assigned_object_id", "name"]
verbose_name = "Access List"
verbose_name_plural = "Access Lists"
def __str__(self):
return self.name
@ -70,7 +73,7 @@ class AccessList(NetBoxModel):
The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object.
"""
return reverse('plugins:netbox_access_lists:accesslist', args=[self.pk])
return reverse("plugins:netbox_access_lists:accesslist", args=[self.pk])
def get_default_action_color(self):
return ACLActionChoices.colors.get(self.default_action)
@ -90,38 +93,50 @@ class ACLInterfaceAssignment(NetBoxModel):
access_list = models.ForeignKey(
on_delete=models.CASCADE,
to=AccessList,
verbose_name='Access List',
verbose_name="Access List",
)
direction = models.CharField(
max_length=30,
choices=ACLAssignmentDirectionChoices
choices=ACLAssignmentDirectionChoices,
)
assigned_object_type = models.ForeignKey(
to=ContentType,
limit_choices_to=ACL_INTERFACE_ASSIGNMENT_MODELS,
on_delete=models.PROTECT
on_delete=models.PROTECT,
)
assigned_object_id = models.PositiveBigIntegerField()
assigned_object = GenericForeignKey(
ct_field='assigned_object_type',
fk_field='assigned_object_id'
ct_field="assigned_object_type",
fk_field="assigned_object_id",
)
comments = models.TextField(
blank=True
blank=True,
)
class Meta:
unique_together = ['assigned_object_type', 'assigned_object_id', 'access_list', 'direction']
ordering = ['assigned_object_type', 'assigned_object_id', 'access_list', 'direction']
verbose_name = 'ACL Interface Assignment'
verbose_name_plural = 'ACL Interface Assignments'
unique_together = [
"assigned_object_type",
"assigned_object_id",
"access_list",
"direction",
]
ordering = [
"assigned_object_type",
"assigned_object_id",
"access_list",
"direction",
]
verbose_name = "ACL Interface Assignment"
verbose_name_plural = "ACL Interface Assignments"
def get_absolute_url(self):
"""
The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object.
"""
return reverse('plugins:netbox_access_lists:aclinterfaceassignment', args=[self.pk])
return reverse(
"plugins:netbox_access_lists:aclinterfaceassignment", args=[self.pk]
)
def get_direction_color(self):
return ACLAssignmentDirectionChoices.colors.get(self.direction)
@ -129,35 +144,35 @@ class ACLInterfaceAssignment(NetBoxModel):
GenericRelation(
to=ACLInterfaceAssignment,
content_type_field='assigned_object_type',
object_id_field='assigned_object_id',
related_query_name='interface'
).contribute_to_class(Interface, 'accesslistassignments')
content_type_field="assigned_object_type",
object_id_field="assigned_object_id",
related_query_name="interface",
).contribute_to_class(Interface, "accesslistassignments")
GenericRelation(
to=ACLInterfaceAssignment,
content_type_field='assigned_object_type',
object_id_field='assigned_object_id',
related_query_name='vminterface'
).contribute_to_class(VMInterface, 'accesslistassignments')
content_type_field="assigned_object_type",
object_id_field="assigned_object_id",
related_query_name="vminterface",
).contribute_to_class(VMInterface, "accesslistassignments")
GenericRelation(
to=AccessList,
content_type_field='assigned_object_type',
object_id_field='assigned_object_id',
related_query_name='device'
).contribute_to_class(Device, 'accesslists')
content_type_field="assigned_object_type",
object_id_field="assigned_object_id",
related_query_name="device",
).contribute_to_class(Device, "accesslists")
GenericRelation(
to=AccessList,
content_type_field='assigned_object_type',
object_id_field='assigned_object_id',
related_query_name='virtual_chassis'
).contribute_to_class(VirtualChassis, 'accesslists')
content_type_field="assigned_object_type",
object_id_field="assigned_object_id",
related_query_name="virtual_chassis",
).contribute_to_class(VirtualChassis, "accesslists")
GenericRelation(
to=AccessList,
content_type_field='assigned_object_type',
object_id_field='assigned_object_id',
related_query_name='virtual_machine'
).contribute_to_class(VirtualMachine, 'accesslists')
content_type_field="assigned_object_type",
object_id_field="assigned_object_id",
related_query_name="virtual_machine",
).contribute_to_class(VirtualMachine, "accesslists")

View File

@ -11,38 +11,38 @@ from utilities.choices import ButtonColorChoices
accesslist_buttons = [
PluginMenuButton(
link='plugins:netbox_access_lists:accesslist_add',
title='Add',
icon_class='mdi mdi-plus-thick',
color=ButtonColorChoices.GREEN
)
link="plugins:netbox_access_lists:accesslist_add",
title="Add",
icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN,
),
]
aclstandardrule_butons = [
PluginMenuButton(
link='plugins:netbox_access_lists:aclstandardrule_add',
title='Add',
icon_class='mdi mdi-plus-thick',
color=ButtonColorChoices.GREEN
)
link="plugins:netbox_access_lists:aclstandardrule_add",
title="Add",
icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN,
),
]
aclextendedrule_butons = [
PluginMenuButton(
link='plugins:netbox_access_lists:aclextendedrule_add',
title='Add',
icon_class='mdi mdi-plus-thick',
color=ButtonColorChoices.GREEN
)
link="plugins:netbox_access_lists:aclextendedrule_add",
title="Add",
icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN,
),
]
accesslistassignment_buttons = [
PluginMenuButton(
link='plugins:netbox_access_lists:aclinterfaceassignment_add',
title='Add',
icon_class='mdi mdi-plus-thick',
color=ButtonColorChoices.GREEN
)
link="plugins:netbox_access_lists:aclinterfaceassignment_add",
title="Add",
icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN,
),
]
#
@ -51,25 +51,25 @@ accesslistassignment_buttons = [
menu_items = (
PluginMenuItem(
link='plugins:netbox_access_lists:accesslist_list',
link_text='Access Lists',
buttons=accesslist_buttons
link="plugins:netbox_access_lists:accesslist_list",
link_text="Access Lists",
buttons=accesslist_buttons,
),
# Comment out Standard Access List rule to force creation in the ACL view
PluginMenuItem(
link='plugins:netbox_access_lists:aclstandardrule_list',
link_text='ACL Standard Rules',
buttons=aclstandardrule_butons
link="plugins:netbox_access_lists:aclstandardrule_list",
link_text="ACL Standard Rules",
buttons=aclstandardrule_butons,
),
# Comment out Extended Access List rule to force creation in the ACL view
PluginMenuItem(
link='plugins:netbox_access_lists:aclextendedrule_list',
link_text='ACL Extended Rules',
buttons=aclextendedrule_butons
link="plugins:netbox_access_lists:aclextendedrule_list",
link_text="ACL Extended Rules",
buttons=aclextendedrule_butons,
),
PluginMenuItem(
link='plugins:netbox_access_lists:aclinterfaceassignment_list',
link_text='ACL Interface Assignments',
buttons=accesslistassignment_buttons
link="plugins:netbox_access_lists:aclinterfaceassignment_list",
link_text="ACL Interface Assignments",
buttons=accesslistassignment_buttons,
),
)

View File

@ -3,17 +3,15 @@ Define the object lists / table view for each of the plugin models.
"""
import django_tables2 as tables
from netbox.tables import (ChoiceFieldColumn, NetBoxTable, TemplateColumn,
columns)
from netbox.tables import ChoiceFieldColumn, NetBoxTable, TemplateColumn, columns
from .models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment,
ACLStandardRule)
from .models import AccessList, ACLExtendedRule, ACLInterfaceAssignment, ACLStandardRule
__all__ = (
'AccessListTable',
'ACLInterfaceAssignmentTable',
'ACLStandardRuleTable',
'ACLExtendedRuleTable',
"AccessListTable",
"ACLInterfaceAssignmentTable",
"ACLStandardRuleTable",
"ACLExtendedRuleTable",
)
@ -25,93 +23,144 @@ COL_HOST_ASSIGNMENT = """
{% endif %}
"""
class AccessListTable(NetBoxTable):
"""
Defines the table view for the AccessList model.
"""
pk = columns.ToggleColumn()
id = tables.Column(
linkify=True
linkify=True,
)
assigned_object = tables.Column(
linkify=True,
orderable=False,
verbose_name='Assigned Host'
verbose_name="Assigned Host",
)
name = tables.Column(
linkify=True
linkify=True,
)
device = tables.Column(
linkify=True
linkify=True,
)
type = ChoiceFieldColumn()
default_action = ChoiceFieldColumn()
rule_count = tables.Column(
verbose_name='Rule Count'
verbose_name="Rule Count",
)
tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:accesslist_list'
url_name="plugins:netbox_access_lists:accesslist_list",
)
class Meta(NetBoxTable.Meta):
model = AccessList
fields = ('pk', 'id', 'name', 'assigned_object', 'type', 'rule_count', 'default_action', 'comments', 'actions', 'tags')
default_columns = ('name', 'assigned_object', 'type', 'rule_count', 'default_action', 'tags')
fields = (
"pk",
"id",
"name",
"assigned_object",
"type",
"rule_count",
"default_action",
"comments",
"actions",
"tags",
)
default_columns = (
"name",
"assigned_object",
"type",
"rule_count",
"default_action",
"tags",
)
class ACLInterfaceAssignmentTable(NetBoxTable):
"""
Defines the table view for the AccessList model.
"""
pk = columns.ToggleColumn()
id = tables.Column(
linkify=True
linkify=True,
)
access_list = tables.Column(
linkify=True
linkify=True,
)
direction = ChoiceFieldColumn()
host = tables.TemplateColumn(
template_code=COL_HOST_ASSIGNMENT
template_code=COL_HOST_ASSIGNMENT,
)
assigned_object = tables.Column(
linkify=True,
orderable=False,
verbose_name='Assigned Interface'
verbose_name="Assigned Interface",
)
tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclinterfaceassignment_list'
url_name="plugins:netbox_access_lists:aclinterfaceassignment_list",
)
class Meta(NetBoxTable.Meta):
model = ACLInterfaceAssignment
fields = ('pk', 'id', 'access_list', 'direction', 'host', 'assigned_object', 'tags')
default_columns = ('id', 'access_list', 'direction', 'host', 'assigned_object', 'tags')
fields = (
"pk",
"id",
"access_list",
"direction",
"host",
"assigned_object",
"tags",
)
default_columns = (
"id",
"access_list",
"direction",
"host",
"assigned_object",
"tags",
)
class ACLStandardRuleTable(NetBoxTable):
"""
Defines the table view for the ACLStandardRule model.
"""
access_list = tables.Column(
linkify=True
linkify=True,
)
index = tables.Column(
linkify=True
linkify=True,
)
action = ChoiceFieldColumn()
tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclstandardrule_list'
url_name="plugins:netbox_access_lists:aclstandardrule_list",
)
class Meta(NetBoxTable.Meta):
model = ACLStandardRule
fields = (
'pk', 'id', 'access_list', 'index', 'action', 'actions', 'remark', 'tags', 'description', 'source_prefix',
"pk",
"id",
"access_list",
"index",
"action",
"actions",
"remark",
"tags",
"description",
"source_prefix",
)
default_columns = (
'access_list', 'index', 'action', 'actions', 'remark', 'source_prefix', 'tags'
"access_list",
"index",
"action",
"actions",
"remark",
"source_prefix",
"tags",
)
@ -119,25 +168,47 @@ class ACLExtendedRuleTable(NetBoxTable):
"""
Defines the table view for the ACLExtendedRule model.
"""
access_list = tables.Column(
linkify=True
linkify=True,
)
index = tables.Column(
linkify=True
linkify=True,
)
action = ChoiceFieldColumn()
tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclextendedrule_list'
url_name="plugins:netbox_access_lists:aclextendedrule_list",
)
protocol = ChoiceFieldColumn()
class Meta(NetBoxTable.Meta):
model = ACLExtendedRule
fields = (
'pk', 'id', 'access_list', 'index', 'action', 'actions', 'remark', 'tags', 'description',
'source_prefix', 'source_ports', 'destination_prefix', 'destination_ports', 'protocol'
"pk",
"id",
"access_list",
"index",
"action",
"actions",
"remark",
"tags",
"description",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
)
default_columns = (
'access_list', 'index', 'action', 'actions', 'remark', 'tags',
'source_prefix', 'source_ports', 'destination_prefix', 'destination_ports', 'protocol'
"access_list",
"index",
"action",
"actions",
"remark",
"tags",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
)

View File

@ -1,70 +1,87 @@
from django.contrib.contenttypes.models import ContentType
from extras.plugins import PluginTemplateExtension
from .models import AccessList, ACLInterfaceAssignment
__all__ = (
'AccessLists',
"AccessLists",
"ACLInterfaceAssignments",
'DeviceAccessLists',
'VirtualChassisAccessLists',
'VMAccessLists',
'DeviceACLInterfaceAssignments',
'VMAACLInterfaceAssignments',
"DeviceAccessLists",
"VirtualChassisAccessLists",
"VMAccessLists",
"DeviceACLInterfaceAssignments",
"VMAACLInterfaceAssignments",
)
class ACLInterfaceAssignments(PluginTemplateExtension):
def right_page(self):
obj = self.context['object']
obj = self.context["object"]
acl_interface_assignments = None
ctype = ContentType.objects.get_for_model(obj)
if ctype.model in ['interface', 'vminterface']:
acl_interface_assignments = ACLInterfaceAssignment.objects.filter(assigned_object_id=obj.pk, assigned_object_type=ctype)
if ctype.model in ["interface", "vminterface"]:
acl_interface_assignments = ACLInterfaceAssignment.objects.filter(
assigned_object_id=obj.pk, assigned_object_type=ctype
)
return self.render('inc/assigned_interface/access_lists.html', extra_context={
'acl_interface_assignments': acl_interface_assignments,
'type': ctype.model if ctype.model == 'device' else ctype.name.replace(' ', '_'),
})
return self.render(
"inc/assigned_interface/access_lists.html",
extra_context={
"acl_interface_assignments": acl_interface_assignments,
"type": ctype.model
if ctype.model == "device"
else ctype.name.replace(" ", "_"),
},
)
class AccessLists(PluginTemplateExtension):
def right_page(self):
obj = self.context['object']
obj = self.context["object"]
access_lists = None
ctype = ContentType.objects.get_for_model(obj)
if ctype.model in ['device', 'virtualchassis', 'virtualmachine']:
access_lists = AccessList.objects.filter(assigned_object_id=obj.pk, assigned_object_type=ctype)
if ctype.model in ["device", "virtualchassis", "virtualmachine"]:
access_lists = AccessList.objects.filter(
assigned_object_id=obj.pk, assigned_object_type=ctype
)
return self.render('inc/assigned_host/access_lists.html', extra_context={
'access_lists': access_lists,
'type': ctype.model if ctype.model == 'device' else ctype.name.replace(' ', '_'),
})
return self.render(
"inc/assigned_host/access_lists.html",
extra_context={
"access_lists": access_lists,
"type": ctype.model
if ctype.model == "device"
else ctype.name.replace(" ", "_"),
},
)
class DeviceAccessLists(AccessLists):
model = 'dcim.device'
model = "dcim.device"
class VirtualChassisAccessLists(AccessLists):
model = 'dcim.virtualchassis'
model = "dcim.virtualchassis"
class VMAccessLists(AccessLists):
model = 'virtualization.virtualmachine'
model = "virtualization.virtualmachine"
class DeviceACLInterfaceAssignments(ACLInterfaceAssignments):
model = 'dcim.interface'
model = "dcim.interface"
class VMAACLInterfaceAssignments(ACLInterfaceAssignments):
model = 'virtualization.vminterface'
model = "virtualization.vminterface"
template_extensions = [DeviceAccessLists, VirtualChassisAccessLists, VMAccessLists, DeviceACLInterfaceAssignments, VMAACLInterfaceAssignments]
template_extensions = [
DeviceAccessLists,
VirtualChassisAccessLists,
VMAccessLists,
DeviceACLInterfaceAssignments,
VMAACLInterfaceAssignments,
]

View File

@ -8,51 +8,152 @@ from netbox.views.generic import ObjectChangeLogView
from . import models, views
urlpatterns = (
# Access Lists
path('access-lists/', views.AccessListListView.as_view(), name='accesslist_list'),
path('access-lists/add/', views.AccessListEditView.as_view(), name='accesslist_add'),
#path('access-lists/edit/', views.AccessListBulkEditView.as_view(), name='accesslist_bulk_edit'),
path('access-lists/delete/', views.AccessListBulkDeleteView.as_view(), name='accesslist_bulk_delete'),
path('access-lists/<int:pk>/', views.AccessListView.as_view(), name='accesslist'),
path('access-lists/<int:pk>/edit/', views.AccessListEditView.as_view(), name='accesslist_edit'),
path('access-lists/<int:pk>/delete/', views.AccessListDeleteView.as_view(), name='accesslist_delete'),
path('access-lists/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='accesslist_changelog', kwargs={
'model': models.AccessList
}),
path("access-lists/", views.AccessListListView.as_view(), name="accesslist_list"),
path(
"access-lists/add/", views.AccessListEditView.as_view(), name="accesslist_add"
),
# path('access-lists/edit/', views.AccessListBulkEditView.as_view(), name='accesslist_bulk_edit'),
path(
"access-lists/delete/",
views.AccessListBulkDeleteView.as_view(),
name="accesslist_bulk_delete",
),
path("access-lists/<int:pk>/", views.AccessListView.as_view(), name="accesslist"),
path(
"access-lists/<int:pk>/edit/",
views.AccessListEditView.as_view(),
name="accesslist_edit",
),
path(
"access-lists/<int:pk>/delete/",
views.AccessListDeleteView.as_view(),
name="accesslist_delete",
),
path(
"access-lists/<int:pk>/changelog/",
ObjectChangeLogView.as_view(),
name="accesslist_changelog",
kwargs={
"model": models.AccessList,
},
),
# Access List Interface Assignments
path('interface-assignments/', views.ACLInterfaceAssignmentListView.as_view(), name='aclinterfaceassignment_list'),
path('interface-assignments/add/', views.ACLInterfaceAssignmentEditView.as_view(), name='aclinterfaceassignment_add'),
#path('interface-assignments/edit/', views.ACLInterfaceAssignmentBulkEditView.as_view(), name='aclinterfaceassignment_bulk_edit'),
path('interface-assignments/delete/', views.ACLInterfaceAssignmentBulkDeleteView.as_view(), name='aclinterfaceassignment_bulk_delete'),
path('interface-assignments/<int:pk>/', views.ACLInterfaceAssignmentView.as_view(), name='aclinterfaceassignment'),
path('interface-assignments/<int:pk>/edit/', views.ACLInterfaceAssignmentEditView.as_view(), name='aclinterfaceassignment_edit'),
path('interface-assignments/<int:pk>/delete/', views.ACLInterfaceAssignmentDeleteView.as_view(), name='aclinterfaceassignment_delete'),
path('interface-assignments/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclinterfaceassignment_changelog', kwargs={
'model': models.ACLInterfaceAssignment
}),
path(
"interface-assignments/",
views.ACLInterfaceAssignmentListView.as_view(),
name="aclinterfaceassignment_list",
),
path(
"interface-assignments/add/",
views.ACLInterfaceAssignmentEditView.as_view(),
name="aclinterfaceassignment_add",
),
# path('interface-assignments/edit/', views.ACLInterfaceAssignmentBulkEditView.as_view(), name='aclinterfaceassignment_bulk_edit'),
path(
"interface-assignments/delete/",
views.ACLInterfaceAssignmentBulkDeleteView.as_view(),
name="aclinterfaceassignment_bulk_delete",
),
path(
"interface-assignments/<int:pk>/",
views.ACLInterfaceAssignmentView.as_view(),
name="aclinterfaceassignment",
),
path(
"interface-assignments/<int:pk>/edit/",
views.ACLInterfaceAssignmentEditView.as_view(),
name="aclinterfaceassignment_edit",
),
path(
"interface-assignments/<int:pk>/delete/",
views.ACLInterfaceAssignmentDeleteView.as_view(),
name="aclinterfaceassignment_delete",
),
path(
"interface-assignments/<int:pk>/changelog/",
ObjectChangeLogView.as_view(),
name="aclinterfaceassignment_changelog",
kwargs={
"model": models.ACLInterfaceAssignment,
},
),
# Standard Access List Rules
path('standard-rules/', views.ACLStandardRuleListView.as_view(), name='aclstandardrule_list'),
path('standard-rules/add/', views.ACLStandardRuleEditView.as_view(), name='aclstandardrule_add'),
path('standard-rules/delete/', views.ACLStandardRuleBulkDeleteView.as_view(), name='aclstandardrule_bulk_delete'),
path('standard-rules/<int:pk>/', views.ACLStandardRuleView.as_view(), name='aclstandardrule'),
path('standard-rules/<int:pk>/edit/', views.ACLStandardRuleEditView.as_view(), name='aclstandardrule_edit'),
path('standard-rules/<int:pk>/delete/', views.ACLStandardRuleDeleteView.as_view(), name='aclstandardrule_delete'),
path('standard-rules/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclstandardrule_changelog', kwargs={
'model': models.ACLStandardRule
}),
path(
"standard-rules/",
views.ACLStandardRuleListView.as_view(),
name="aclstandardrule_list",
),
path(
"standard-rules/add/",
views.ACLStandardRuleEditView.as_view(),
name="aclstandardrule_add",
),
path(
"standard-rules/delete/",
views.ACLStandardRuleBulkDeleteView.as_view(),
name="aclstandardrule_bulk_delete",
),
path(
"standard-rules/<int:pk>/",
views.ACLStandardRuleView.as_view(),
name="aclstandardrule",
),
path(
"standard-rules/<int:pk>/edit/",
views.ACLStandardRuleEditView.as_view(),
name="aclstandardrule_edit",
),
path(
"standard-rules/<int:pk>/delete/",
views.ACLStandardRuleDeleteView.as_view(),
name="aclstandardrule_delete",
),
path(
"standard-rules/<int:pk>/changelog/",
ObjectChangeLogView.as_view(),
name="aclstandardrule_changelog",
kwargs={
"model": models.ACLStandardRule,
},
),
# Extended Access List Rules
path('extended-rules/', views.ACLExtendedRuleListView.as_view(), name='aclextendedrule_list'),
path('extended-rules/add/', views.ACLExtendedRuleEditView.as_view(), name='aclextendedrule_add'),
path('extended-rules/delete/', views.ACLExtendedRuleBulkDeleteView.as_view(), name='aclextendedrule_bulk_delete'),
path('extended-rules/<int:pk>/', views.ACLExtendedRuleView.as_view(), name='aclextendedrule'),
path('extended-rules/<int:pk>/edit/', views.ACLExtendedRuleEditView.as_view(), name='aclextendedrule_edit'),
path('extended-rules/<int:pk>/delete/', views.ACLExtendedRuleDeleteView.as_view(), name='aclextendedrule_delete'),
path('extended-rules/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclextendedrule_changelog', kwargs={
'model': models.ACLExtendedRule
}),
path(
"extended-rules/",
views.ACLExtendedRuleListView.as_view(),
name="aclextendedrule_list",
),
path(
"extended-rules/add/",
views.ACLExtendedRuleEditView.as_view(),
name="aclextendedrule_add",
),
path(
"extended-rules/delete/",
views.ACLExtendedRuleBulkDeleteView.as_view(),
name="aclextendedrule_bulk_delete",
),
path(
"extended-rules/<int:pk>/",
views.ACLExtendedRuleView.as_view(),
name="aclextendedrule",
),
path(
"extended-rules/<int:pk>/edit/",
views.ACLExtendedRuleEditView.as_view(),
name="aclextendedrule_edit",
),
path(
"extended-rules/<int:pk>/delete/",
views.ACLExtendedRuleDeleteView.as_view(),
name="aclextendedrule_delete",
),
path(
"extended-rules/<int:pk>/changelog/",
ObjectChangeLogView.as_view(),
name="aclextendedrule_changelog",
kwargs={
"model": models.ACLExtendedRule,
},
),
)

View File

@ -9,26 +9,26 @@ from netbox.views import generic
from . import filtersets, forms, models, tables
__all__ = (
'AccessListView',
'AccessListListView',
'AccessListEditView',
'AccessListDeleteView',
'AccessListBulkDeleteView',
'ACLInterfaceAssignmentView',
'ACLInterfaceAssignmentListView',
'ACLInterfaceAssignmentEditView',
'ACLInterfaceAssignmentDeleteView',
'ACLInterfaceAssignmentBulkDeleteView',
'ACLStandardRuleView',
'ACLStandardRuleListView',
'ACLStandardRuleEditView',
'ACLStandardRuleDeleteView',
'ACLStandardRuleBulkDeleteView',
'ACLExtendedRuleView',
'ACLExtendedRuleListView',
'ACLExtendedRuleEditView',
'ACLExtendedRuleDeleteView',
'ACLExtendedRuleBulkDeleteView',
"AccessListView",
"AccessListListView",
"AccessListEditView",
"AccessListDeleteView",
"AccessListBulkDeleteView",
"ACLInterfaceAssignmentView",
"ACLInterfaceAssignmentListView",
"ACLInterfaceAssignmentEditView",
"ACLInterfaceAssignmentDeleteView",
"ACLInterfaceAssignmentBulkDeleteView",
"ACLStandardRuleView",
"ACLStandardRuleListView",
"ACLStandardRuleEditView",
"ACLStandardRuleDeleteView",
"ACLStandardRuleBulkDeleteView",
"ACLExtendedRuleView",
"ACLExtendedRuleListView",
"ACLExtendedRuleEditView",
"ACLExtendedRuleDeleteView",
"ACLExtendedRuleBulkDeleteView",
)
@ -36,24 +36,26 @@ __all__ = (
# AccessList views
#
class AccessListView(generic.ObjectView):
"""
Defines the view for the AccessLists django model.
"""
queryset = models.AccessList.objects.all()
def get_extra_context(self, request, instance):
"""
Depending on the Access List type, the list view will return the required ACL Rule using the previous defined tables in tables.py.
"""
if instance.type == 'extended':
if instance.type == "extended":
table = tables.ACLExtendedRuleTable(instance.aclextendedrules.all())
elif instance.type == 'standard':
elif instance.type == "standard":
table = tables.ACLStandardRuleTable(instance.aclstandardrules.all())
table.configure(request)
return {
'rules_table': table
"rules_table": table,
}
@ -61,8 +63,9 @@ class AccessListListView(generic.ObjectListView):
"""
Defines the list view for the AccessLists django model.
"""
queryset = models.AccessList.objects.annotate(
rule_count=Count('aclextendedrules') + Count('aclstandardrules')
rule_count=Count("aclextendedrules") + Count("aclstandardrules"),
)
table = tables.AccessListTable
filterset = filtersets.AccessListFilterSet
@ -73,15 +76,17 @@ class AccessListEditView(generic.ObjectEditView):
"""
Defines the edit view for the AccessLists django model.
"""
queryset = models.AccessList.objects.all()
form = forms.AccessListForm
template_name = 'netbox_access_lists/accesslist_edit.html'
template_name = "netbox_access_lists/accesslist_edit.html"
class AccessListDeleteView(generic.ObjectDeleteView):
"""
Defines the delete view for the AccessLists django model.
"""
queryset = models.AccessList.objects.all()
@ -90,14 +95,17 @@ class AccessListBulkDeleteView(generic.BulkDeleteView):
filterset = filtersets.AccessListFilterSet
table = tables.AccessListTable
#
# ACLInterfaceAssignment views
#
class ACLInterfaceAssignmentView(generic.ObjectView):
"""
Defines the view for the ACLInterfaceAssignments django model.
"""
queryset = models.ACLInterfaceAssignment.objects.all()
@ -105,6 +113,7 @@ class ACLInterfaceAssignmentListView(generic.ObjectListView):
"""
Defines the list view for the ACLInterfaceAssignments django model.
"""
queryset = models.ACLInterfaceAssignment.objects.all()
table = tables.ACLInterfaceAssignmentTable
filterset = filtersets.ACLInterfaceAssignmentFilterSet
@ -115,15 +124,17 @@ class ACLInterfaceAssignmentEditView(generic.ObjectEditView):
"""
Defines the edit view for the ACLInterfaceAssignments django model.
"""
queryset = models.ACLInterfaceAssignment.objects.all()
form = forms.ACLInterfaceAssignmentForm
template_name = 'netbox_access_lists/aclinterfaceassignment_edit.html'
template_name = "netbox_access_lists/aclinterfaceassignment_edit.html"
class ACLInterfaceAssignmentDeleteView(generic.ObjectDeleteView):
"""
Defines the delete view for the ACLInterfaceAssignments django model.
"""
queryset = models.ACLInterfaceAssignment.objects.all()
@ -142,6 +153,7 @@ class ACLStandardRuleView(generic.ObjectView):
"""
Defines the view for the ACLStandardRule django model.
"""
queryset = models.ACLStandardRule.objects.all()
@ -149,6 +161,7 @@ class ACLStandardRuleListView(generic.ObjectListView):
"""
Defines the list view for the ACLStandardRule django model.
"""
queryset = models.ACLStandardRule.objects.all()
table = tables.ACLStandardRuleTable
filterset = filtersets.ACLStandardRuleFilterSet
@ -159,6 +172,7 @@ class ACLStandardRuleEditView(generic.ObjectEditView):
"""
Defines the edit view for the ACLStandardRule django model.
"""
queryset = models.ACLStandardRule.objects.all()
form = forms.ACLStandardRuleForm
@ -167,6 +181,7 @@ class ACLStandardRuleDeleteView(generic.ObjectDeleteView):
"""
Defines the delete view for the ACLStandardRules django model.
"""
queryset = models.ACLStandardRule.objects.all()
@ -175,6 +190,7 @@ class ACLStandardRuleBulkDeleteView(generic.BulkDeleteView):
filterset = filtersets.ACLStandardRuleFilterSet
table = tables.ACLStandardRuleTable
#
# ACLExtendedRule views
#
@ -184,6 +200,7 @@ class ACLExtendedRuleView(generic.ObjectView):
"""
Defines the view for the ACLExtendedRule django model.
"""
queryset = models.ACLExtendedRule.objects.all()
@ -191,6 +208,7 @@ class ACLExtendedRuleListView(generic.ObjectListView):
"""
Defines the list view for the ACLExtendedRule django model.
"""
queryset = models.ACLExtendedRule.objects.all()
table = tables.ACLExtendedRuleTable
filterset = filtersets.ACLExtendedRuleFilterSet
@ -201,6 +219,7 @@ class ACLExtendedRuleEditView(generic.ObjectEditView):
"""
Defines the edit view for the ACLExtendedRule django model.
"""
queryset = models.ACLExtendedRule.objects.all()
form = forms.ACLExtendedRuleForm
@ -209,8 +228,10 @@ class ACLExtendedRuleDeleteView(generic.ObjectDeleteView):
"""
Defines the delete view for the ACLExtendedRules django model.
"""
queryset = models.ACLExtendedRule.objects.all()
class ACLExtendedRuleBulkDeleteView(generic.BulkDeleteView):
queryset = models.ACLExtendedRule.objects.all()
filterset = filtersets.ACLExtendedRuleFilterSet

View File

@ -1,20 +1,20 @@
#import codecs
#import os.path
# import codecs
# import os.path
#
from setuptools import find_packages, setup
#
#with open("README.md", "r") as fh:
# with open("README.md", "r") as fh:
# long_description = fh.read()
#
#
#def read(rel_path):
# def read(rel_path):
# here = os.path.abspath(os.path.dirname(__file__))
# with codecs.open(os.path.join(here, rel_path), 'r') as fp:
# with codecs.open(os.path.join(here, rel_path), "r") as fp:
# return fp.read()
#
#
#def get_version(rel_path):
# def get_version(rel_path):
# for line in read(rel_path).splitlines():
# if line.startswith('__version__'):
# delim = '"' if '"' in line else "'"
@ -24,13 +24,13 @@ from setuptools import find_packages, setup
#
setup(
name='netbox-access-lists',
version='0.1.0',
#version=get_version('netbox_access_lists/version.py'),
description='A NetBox plugin for Access List management',
#long_description=long_description,
name="netbox-access-lists",
version="0.1.0",
# version=get_version("netbox_access_lists/version.py"),
description="A NetBox plugin for Access List management",
# long_description=long_description,
long_description_content_type="text/markdown",
url='https://github.com/ryanmerolle/netbox-access-lists',
url="https://github.com/ryanmerolle/netbox-access-lists",
install_requires=[],
packages=find_packages(),
include_package_data=True,