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 = [ PLUGINS = [
"netbox_access_lists", "netbox_access_lists",
] ]
PLUGINS_CONFIG = { PLUGINS_CONFIG = {
"netbox_access_lists": {}, "netbox_access_lists": {},

View File

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

View File

@ -48,11 +48,11 @@ jobs:
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality # queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
@ -61,7 +61,7 @@ jobs:
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines. # If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: | # - run: |

View File

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

View File

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

View File

@ -6,75 +6,88 @@ while Django itself handles the database abstraction.
from netbox.api.serializers import WritableNestedSerializer from netbox.api.serializers import WritableNestedSerializer
from rest_framework import serializers from rest_framework import serializers
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment, from ..models import (
ACLStandardRule) AccessList,
ACLExtendedRule,
ACLInterfaceAssignment,
ACLStandardRule,
)
__all__ = [ __all__ = [
'NestedAccessListSerializer', "NestedAccessListSerializer",
'NestedACLInterfaceAssignmentSerializer', "NestedACLInterfaceAssignmentSerializer",
'NestedACLStandardRuleSerializer', "NestedACLStandardRuleSerializer",
'NestedACLExtendedRuleSerializer' "NestedACLExtendedRuleSerializer",
] ]
class NestedAccessListSerializer(WritableNestedSerializer): class NestedAccessListSerializer(WritableNestedSerializer):
""" """
Defines the nested serializer for the django AccessList model & associates it to a view. Defines the nested serializer for the django AccessList model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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: class Meta:
""" """
Associates the django model ACLStandardRule & fields to the nested serializer. Associates the django model ACLStandardRule & fields to the nested serializer.
""" """
model = AccessList model = AccessList
fields = ('id', 'url', 'display', 'name') fields = ("id", "url", "display", "name")
class NestedACLInterfaceAssignmentSerializer(WritableNestedSerializer): class NestedACLInterfaceAssignmentSerializer(WritableNestedSerializer):
""" """
Defines the nested serializer for the django ACLInterfaceAssignment model & associates it to a view. Defines the nested serializer for the django ACLInterfaceAssignment model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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: class Meta:
""" """
Associates the django model ACLInterfaceAssignment & fields to the nested serializer. Associates the django model ACLInterfaceAssignment & fields to the nested serializer.
""" """
model = ACLInterfaceAssignment model = ACLInterfaceAssignment
fields = ('id', 'url', 'display', 'access_list') fields = ("id", "url", "display", "access_list")
class NestedACLStandardRuleSerializer(WritableNestedSerializer): class NestedACLStandardRuleSerializer(WritableNestedSerializer):
""" """
Defines the nested serializer for the django ACLStandardRule model & associates it to a view. Defines the nested serializer for the django ACLStandardRule model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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: class Meta:
""" """
Associates the django model ACLStandardRule & fields to the nested serializer. Associates the django model ACLStandardRule & fields to the nested serializer.
""" """
model = ACLStandardRule model = ACLStandardRule
fields = ('id', 'url', 'display', 'index') fields = ("id", "url", "display", "index")
class NestedACLExtendedRuleSerializer(WritableNestedSerializer): class NestedACLExtendedRuleSerializer(WritableNestedSerializer):
""" """
Defines the nested serializer for the django ACLExtendedRule model & associates it to a view. Defines the nested serializer for the django ACLExtendedRule model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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: class Meta:
""" """
Associates the django model ACLExtendedRule & fields to the nested serializer. Associates the django model ACLExtendedRule & fields to the nested serializer.
""" """
model = ACLExtendedRule 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.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from drf_yasg.utils import swagger_serializer_method from drf_yasg.utils import swagger_serializer_method
from ipam.api.serializers import NestedPrefixSerializer from ipam.api.serializers import NestedPrefixSerializer
from django.core.exceptions import ObjectDoesNotExist
from netbox.api import ContentTypeField from netbox.api import ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from rest_framework import serializers from rest_framework import serializers
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from ..constants import (ACL_HOST_ASSIGNMENT_MODELS, from ..constants import ACL_HOST_ASSIGNMENT_MODELS, ACL_INTERFACE_ASSIGNMENT_MODELS
ACL_INTERFACE_ASSIGNMENT_MODELS) from ..models import (
from ..models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment, AccessList,
ACLStandardRule) ACLExtendedRule,
from .nested_serializers import (NestedAccessListSerializer, ACLInterfaceAssignment,
NestedACLExtendedRuleSerializer, ACLStandardRule,
NestedACLInterfaceAssignmentSerializer, )
NestedACLStandardRuleSerializer) from .nested_serializers import (
NestedAccessListSerializer,
NestedACLExtendedRuleSerializer,
NestedACLInterfaceAssignmentSerializer,
NestedACLStandardRuleSerializer,
)
__all__ = [ __all__ = [
'AccessListSerializer', "AccessListSerializer",
'ACLInterfaceAssignmentSerializer', "ACLInterfaceAssignmentSerializer",
'ACLStandardRuleSerializer', "ACLStandardRuleSerializer",
'ACLExtendedRuleSerializer' "ACLExtendedRuleSerializer",
] ]
# Sets a standard error message for ACL rules with an action of remark, but no remark set. # 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. # 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. # 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. # 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): class AccessListSerializer(NetBoxModelSerializer):
""" """
Defines the serializer for the django AccessList model & associates it to a view. Defines the serializer for the django AccessList model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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) rule_count = serializers.IntegerField(read_only=True)
assigned_object_type = ContentTypeField( 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) assigned_object = serializers.SerializerMethodField(read_only=True)
@ -55,16 +65,30 @@ class AccessListSerializer(NetBoxModelSerializer):
""" """
Associates the django model AccessList & fields to the serializer. Associates the django model AccessList & fields to the serializer.
""" """
model = AccessList model = AccessList
fields = ( fields = (
'id', 'url', 'display', 'name', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'type', 'default_action', 'comments', 'tags', 'custom_fields', 'created', "id",
'last_updated', 'rule_count' "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) @swagger_serializer_method(serializer_or_field=serializers.DictField)
def get_assigned_object(self, obj): def get_assigned_object(self, obj):
serializer = get_serializer_for_model(obj.assigned_object, prefix='Nested') serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested")
context = {'request': self.context['request']} context = {"request": self.context["request"]}
return serializer(obj.assigned_object, context=context).data return serializer(obj.assigned_object, context=context).data
def validate(self, data): def validate(self, data):
@ -76,18 +100,26 @@ class AccessListSerializer(NetBoxModelSerializer):
error_message = {} error_message = {}
# Check that the GFK object is valid. # 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: 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: except ObjectDoesNotExist:
# Sets a standard error message for invalid GFK # 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_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_type"] = [error_message_invalid_gfk]
error_message['assigned_object_id'] = [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. # 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: if (
error_message['type'] = ['This ACL has ACL rules associated, CANNOT change ACL type.'] 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: if error_message:
raise serializers.ValidationError(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. Defines the serializer for the django ACLInterfaceAssignment model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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( 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) assigned_object = serializers.SerializerMethodField(read_only=True)
@ -111,16 +144,27 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer):
""" """
Associates the django model ACLInterfaceAssignment & fields to the serializer. Associates the django model ACLInterfaceAssignment & fields to the serializer.
""" """
model = ACLInterfaceAssignment model = ACLInterfaceAssignment
fields = ( fields = (
'id', 'url', 'access_list', 'direction', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'comments', 'tags', 'custom_fields', 'created', "id",
'last_updated' "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) @swagger_serializer_method(serializer_or_field=serializers.DictField)
def get_assigned_object(self, obj): def get_assigned_object(self, obj):
serializer = get_serializer_for_model(obj.assigned_object, prefix='Nested') serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested")
context = {'request': self.context['request']} context = {"request": self.context["request"]}
return serializer(obj.assigned_object, context=context).data return serializer(obj.assigned_object, context=context).data
def validate(self, 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. - Check that the associated interface's parent host has the selected ACL defined.
""" """
error_message = {} error_message = {}
acl_host = data['access_list'].assigned_object acl_host = data["access_list"].assigned_object
# Check that the GFK object is vlaid. # 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: 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: except ObjectDoesNotExist:
# Sets a standard error message for invalid GFK # 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_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_type"] = [error_message_invalid_gfk]
error_message['assigned_object_id'] = [error_message_invalid_gfk] error_message["assigned_object_id"] = [error_message_invalid_gfk]
if data["assigned_object_type"].model == "interface":
if data['assigned_object_type'].model == 'interface': interface_host = (
interface_host = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id']).device data["assigned_object_type"]
elif data['assigned_object_type'].model == 'vminterface': .get_object_for_this_type(id=data["assigned_object_id"])
interface_host = data['assigned_object_type'].get_object_for_this_type(id=data['assigned_object_id']).virtual_machine .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. # Check that the associated interface's parent host has the selected ACL defined.
if acl_host != interface_host: if acl_host != interface_host:
error_acl_not_assigned_to_host = "Access List not present on the selected interface's host." error_acl_not_assigned_to_host = (
error_message['access_list'] = [error_acl_not_assigned_to_host] "Access List not present on the selected interface's host."
error_message['assigned_object_id'] = [error_acl_not_assigned_to_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: if error_message:
raise serializers.ValidationError(error_message) raise serializers.ValidationError(error_message)
return super().validate(data) return super().validate(data)
class ACLStandardRuleSerializer(NetBoxModelSerializer): class ACLStandardRuleSerializer(NetBoxModelSerializer):
""" """
Defines the serializer for the django ACLStandardRule model & associates it to a view. Defines the serializer for the django ACLStandardRule model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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() access_list = NestedAccessListSerializer()
source_prefix = NestedPrefixSerializer( source_prefix = NestedPrefixSerializer(
required=False, required=False,
allow_null=True, allow_null=True,
default=None default=None,
) )
class Meta: class Meta:
""" """
Associates the django model ACLStandardRule & fields to the serializer. Associates the django model ACLStandardRule & fields to the serializer.
""" """
model = ACLStandardRule model = ACLStandardRule
fields = ( fields = (
'id', 'url', 'display', 'access_list', 'index', 'action', 'tags', 'description', "id",
'remark', 'created', 'custom_fields', 'last_updated', 'source_prefix' "url",
"display",
"access_list",
"index",
"action",
"tags",
"description",
"remark",
"created",
"custom_fields",
"last_updated",
"source_prefix",
) )
def validate(self, data): def validate(self, data):
@ -191,11 +260,13 @@ class ACLStandardRuleSerializer(NetBoxModelSerializer):
error_message = {} error_message = {}
# Check if action set to remark, but no remark set. # Check if action set to remark, but no remark set.
if data.get('action') == 'remark' and data.get('remark') is None: if data.get("action") == "remark" and data.get("remark") is None:
error_message['remark'] = [error_message_no_remark] error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set. # Check if action set to remark, but source_prefix set.
if data.get('source_prefix'): if data.get("source_prefix"):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set] error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
if error_message: if error_message:
raise serializers.ValidationError(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. Defines the serializer for the django ACLExtendedRule model & associates it to a view.
""" """
url = serializers.HyperlinkedIdentityField( 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() access_list = NestedAccessListSerializer()
source_prefix = NestedPrefixSerializer( source_prefix = NestedPrefixSerializer(
required=False, required=False,
allow_null=True, allow_null=True,
default=None default=None,
) )
destination_prefix = NestedPrefixSerializer( destination_prefix = NestedPrefixSerializer(
required=False, required=False,
allow_null=True, allow_null=True,
default=None default=None,
) )
class Meta: class Meta:
""" """
Associates the django model ACLExtendedRule & fields to the serializer. Associates the django model ACLExtendedRule & fields to the serializer.
""" """
model = ACLExtendedRule model = ACLExtendedRule
fields = ( fields = (
'id', 'url', 'display', 'access_list', 'index', 'action', 'tags', 'description', "id",
'created', 'custom_fields', 'last_updated', 'source_prefix', 'source_ports', "url",
'destination_prefix', 'destination_ports', 'protocol', 'remark', "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): def validate(self, data):
@ -247,23 +334,33 @@ class ACLExtendedRuleSerializer(NetBoxModelSerializer):
error_message = {} error_message = {}
# Check if action set to remark, but no remark set. # Check if action set to remark, but no remark set.
if data.get('action') == 'remark' and data.get('remark') is None: if data.get("action") == "remark" and data.get("remark") is None:
error_message['remark'] = [error_message_no_remark] error_message["remark"] = [error_message_no_remark]
# Check if action set to remark, but source_prefix set. # Check if action set to remark, but source_prefix set.
if data.get('source_prefix'): if data.get("source_prefix"):
error_message['source_prefix'] = [error_message_action_remark_source_prefix_set] error_message["source_prefix"] = [
error_message_action_remark_source_prefix_set
]
# Check if action set to remark, but source_ports set. # Check if action set to remark, but source_ports set.
if data.get('source_ports'): if data.get("source_ports"):
error_message['source_ports'] = ['Action is set to remark, Source Ports CANNOT be set.'] error_message["source_ports"] = [
"Action is set to remark, Source Ports CANNOT be set."
]
# Check if action set to remark, but destination_prefix set. # Check if action set to remark, but destination_prefix set.
if data.get('destination_prefix'): if data.get("destination_prefix"):
error_message['destination_prefix'] = ['Action is set to remark, Destination Prefix CANNOT be set.'] error_message["destination_prefix"] = [
"Action is set to remark, Destination Prefix CANNOT be set."
]
# Check if action set to remark, but destination_ports set. # Check if action set to remark, but destination_ports set.
if data.get('destination_ports'): if data.get("destination_ports"):
error_message['destination_ports'] = ['Action is set to remark, Destination Ports CANNOT be set.'] error_message["destination_ports"] = [
"Action is set to remark, Destination Ports CANNOT be set."
]
# Check if action set to remark, but protocol set. # Check if action set to remark, but protocol set.
if data.get('protocol'): if data.get("protocol"):
error_message['protocol'] = ['Action is set to remark, Protocol CANNOT be set.'] error_message["protocol"] = [
"Action is set to remark, Protocol CANNOT be set."
]
if error_message: if error_message:
raise serializers.ValidationError(error_message) raise serializers.ValidationError(error_message)

View File

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

View File

@ -8,15 +8,17 @@ from django.db.models import Count
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from .. import filtersets, models from .. import filtersets, models
from .serializers import (AccessListSerializer, ACLExtendedRuleSerializer, from .serializers import (
ACLInterfaceAssignmentSerializer, AccessListSerializer,
ACLStandardRuleSerializer) ACLExtendedRuleSerializer,
ACLInterfaceAssignmentSerializer,
ACLStandardRuleSerializer,
)
__all__ = [ __all__ = [
'AccessListViewSet', "AccessListViewSet",
'ACLStandardRuleViewSet', "ACLStandardRuleViewSet",
'ACLInterfaceAssignmentViewSet' "ACLInterfaceAssignmentViewSet" "ACLExtendedRuleViewSet",
'ACLExtendedRuleViewSet',
] ]
@ -24,8 +26,9 @@ class AccessListViewSet(NetBoxModelViewSet):
""" """
Defines the view set for the django AccessList model & associates it to a view. 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 serializer_class = AccessListSerializer
filterset_class = filtersets.AccessListFilterSet 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. 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 serializer_class = ACLInterfaceAssignmentSerializer
filterset_class = filtersets.ACLInterfaceAssignmentFilterSet 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. Defines the view set for the django ACLStandardRule model & associates it to a view.
""" """
queryset = models.ACLStandardRule.objects.prefetch_related( queryset = models.ACLStandardRule.objects.prefetch_related(
'access_list', 'tags', 'source_prefix' "access_list",
"tags",
"source_prefix",
) )
serializer_class = ACLStandardRuleSerializer serializer_class = ACLStandardRuleSerializer
filterset_class = filtersets.ACLStandardRuleFilterSet 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. Defines the view set for the django ACLExtendedRule model & associates it to a view.
""" """
queryset = models.ACLExtendedRule.objects.prefetch_related( queryset = models.ACLExtendedRule.objects.prefetch_related(
'access_list', 'tags', 'source_prefix', 'destination_prefix', "access_list",
"tags",
"source_prefix",
"destination_prefix",
) )
serializer_class = ACLExtendedRuleSerializer serializer_class = ACLExtendedRuleSerializer
filterset_class = filtersets.ACLExtendedRuleFilterSet 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 from utilities.choices import ChoiceSet
__all__ = ( __all__ = (
'ACLActionChoices', "ACLActionChoices",
'ACLAssignmentDirectionChoices', "ACLAssignmentDirectionChoices",
'ACLProtocolChoices', "ACLProtocolChoices",
'ACLRuleActionChoices', "ACLRuleActionChoices",
'ACLTypeChoices', "ACLTypeChoices",
'ACLProtocolChoices', "ACLProtocolChoices",
) )
@ -18,14 +18,15 @@ class ACLActionChoices(ChoiceSet):
""" """
Defines the choices availble for the Access Lists plugin specific to ACL default_action. Defines the choices availble for the Access Lists plugin specific to ACL default_action.
""" """
ACTION_DENY = 'deny'
ACTION_PERMIT = 'permit' ACTION_DENY = "deny"
ACTION_REJECT = 'reject' ACTION_PERMIT = "permit"
ACTION_REJECT = "reject"
CHOICES = [ CHOICES = [
(ACTION_DENY, 'Deny', 'red'), (ACTION_DENY, "Deny", "red"),
(ACTION_PERMIT, 'Permit', 'green'), (ACTION_PERMIT, "Permit", "green"),
(ACTION_REJECT, 'Reject (Reset)', 'orange'), (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. Defines the choices availble for the Access Lists plugin specific to ACL rule actions.
""" """
ACTION_DENY = 'deny'
ACTION_PERMIT = 'permit' ACTION_DENY = "deny"
ACTION_REMARK = 'remark' ACTION_PERMIT = "permit"
ACTION_REMARK = "remark"
CHOICES = [ CHOICES = [
(ACTION_DENY, 'Deny', 'red'), (ACTION_DENY, "Deny", "red"),
(ACTION_PERMIT, 'Permit', 'green'), (ACTION_PERMIT, "Permit", "green"),
(ACTION_REMARK, 'Remark', 'blue'), (ACTION_REMARK, "Remark", "blue"),
] ]
@ -50,8 +52,8 @@ class ACLAssignmentDirectionChoices(ChoiceSet):
""" """
CHOICES = [ CHOICES = [
('ingress', 'Ingress', 'blue'), ("ingress", "Ingress", "blue"),
('egress', 'Egress', 'purple'), ("egress", "Egress", "purple"),
] ]
@ -59,9 +61,10 @@ class ACLTypeChoices(ChoiceSet):
""" """
Defines the choices availble for the Access Lists plugin specific to ACL type. Defines the choices availble for the Access Lists plugin specific to ACL type.
""" """
CHOICES = [ CHOICES = [
('extended', 'Extended', 'purple'), ("extended", "Extended", "purple"),
('standard', 'Standard', 'blue'), ("standard", "Standard", "blue"),
] ]
@ -69,8 +72,9 @@ class ACLProtocolChoices(ChoiceSet):
""" """
Defines the choices availble for the Access Lists plugin specific to ACL Rule protocol. Defines the choices availble for the Access Lists plugin specific to ACL Rule protocol.
""" """
CHOICES = [ CHOICES = [
('icmp', 'ICMP', 'purple'), ("icmp", "ICMP", "purple"),
('tcp', 'TCP', 'blue'), ("tcp", "TCP", "blue"),
('udp', 'UDP', 'orange'), ("udp", "UDP", "orange"),
] ]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,9 +8,8 @@ import django.db.models.deletion
import taggit.managers import taggit.managers
from django.db import migrations, models from django.db import migrations, models
__all__ = ( __all__ = ("Migration",)
'Migration',
)
class Migration(migrations.Migration): class Migration(migrations.Migration):
""" """
@ -20,100 +19,258 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('extras', '0072_created_datetimefield'), ("extras", "0072_created_datetimefield"),
('ipam', '0057_created_datetimefield'), ("ipam", "0057_created_datetimefield"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='AccessList', name="AccessList",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), (
('created', models.DateTimeField(auto_now_add=True, null=True)), "id",
('last_updated', models.DateTimeField(auto_now=True, null=True)), models.BigAutoField(
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), auto_created=True, primary_key=True, serialize=False
('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')), ("created", models.DateTimeField(auto_now_add=True, null=True)),
('type', models.CharField(max_length=100)), ("last_updated", models.DateTimeField(auto_now=True, null=True)),
('default_action', models.CharField(default='deny', max_length=30)), (
('comments', models.TextField(blank=True)), "custom_field_data",
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), 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={ options={
'ordering': ('name', 'device'), "ordering": ("name", "device"),
'unique_together': {('assigned_object_type', 'assigned_object_id', 'name')}, "unique_together": {
'verbose_name': 'Access List', ("assigned_object_type", "assigned_object_id", "name")
},
"verbose_name": "Access List",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='ACLInterfaceAssignment', name="ACLInterfaceAssignment",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), (
('created', models.DateTimeField(auto_now_add=True, null=True)), "id",
('last_updated', models.DateTimeField(auto_now=True, null=True)), models.BigAutoField(
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), auto_created=True, primary_key=True, serialize=False
('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()), ("created", models.DateTimeField(auto_now_add=True, null=True)),
('assigned_object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), ("last_updated", models.DateTimeField(auto_now=True, null=True)),
('comments', models.TextField(blank=True)), (
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), "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={ options={
'ordering': ('access_list', 'assigned_object_type', 'assigned_object_id', 'direction'), "ordering": (
'unique_together': {('assigned_object_type', 'assigned_object_id', 'access_list', 'direction')}, "access_list",
'verbose_name': 'ACL Interface Assignment', "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( migrations.CreateModel(
name='ACLStandardRule', name="ACLStandardRule",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), (
('created', models.DateTimeField(auto_now_add=True, null=True)), "id",
('last_updated', models.DateTimeField(auto_now=True, null=True)), models.BigAutoField(
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), auto_created=True, primary_key=True, serialize=False
('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()), ("created", models.DateTimeField(auto_now_add=True, null=True)),
('description', models.CharField(blank=True, max_length=500)), ("last_updated", models.DateTimeField(auto_now=True, null=True)),
('action', models.CharField(max_length=30)), (
('remark', models.CharField(blank=True, null=True, max_length=500)), "custom_field_data",
('source_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')), 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={ options={
'ordering': ('access_list', 'index'), "ordering": ("access_list", "index"),
'unique_together': {('access_list', 'index')}, "unique_together": {("access_list", "index")},
'verbose_name': 'ACL Standard Rule', "verbose_name": "ACL Standard Rule",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='ACLExtendedRule', name="ACLExtendedRule",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), (
('created', models.DateTimeField(auto_now_add=True, null=True)), "id",
('last_updated', models.DateTimeField(auto_now=True, null=True)), models.BigAutoField(
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), auto_created=True, primary_key=True, serialize=False
('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()), ("created", models.DateTimeField(auto_now_add=True, null=True)),
('description', models.CharField(blank=True, max_length=500)), ("last_updated", models.DateTimeField(auto_now=True, null=True)),
('action', models.CharField(max_length=30)), (
('remark', models.CharField(blank=True, null=True, max_length=500)), "custom_field_data",
('source_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')), models.JSONField(
('source_ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(), blank=True, null=True, size=None)), blank=True,
('destination_prefix', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='ipam.prefix')), default=dict,
('destination_ports', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveIntegerField(), blank=True, null=True, size=None)), encoder=django.core.serializers.json.DjangoJSONEncoder,
('protocol', models.CharField(blank=True, max_length=30)), ),
),
(
"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={ options={
'ordering': ('access_list', 'index'), "ordering": ("access_list", "index"),
'unique_together': {('access_list', 'index')}, "unique_together": {("access_list", "index")},
'verbose_name': 'ACL Extended Rule', "verbose_name": "ACL Extended Rule",
}, },
), ),
#migrations.AddConstraint( # migrations.AddConstraint(
# model_name='accesslist', # model_name='accesslist',
# constraint=models.UniqueConstraint(fields=('assigned_object_type', 'assigned_object_id'), name='accesslist_assigned_object'), # 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 from .access_lists import AccessList
__all__ = ( __all__ = (
'ACLRule', "ACLRule",
'ACLStandardRule', "ACLStandardRule",
'ACLExtendedRule', "ACLExtendedRule",
) )
@ -22,20 +22,21 @@ class ACLRule(NetBoxModel):
Abstract model for ACL Rules. Abstract model for ACL Rules.
Inherrited by both ACLStandardRule and ACLExtendedRule. Inherrited by both ACLStandardRule and ACLExtendedRule.
""" """
access_list = models.ForeignKey( access_list = models.ForeignKey(
on_delete=models.CASCADE, on_delete=models.CASCADE,
to=AccessList, to=AccessList,
verbose_name='Access List', verbose_name="Access List",
related_name='rules', related_name="rules",
) )
index = models.PositiveIntegerField() index = models.PositiveIntegerField()
remark = models.CharField( remark = models.CharField(
max_length=500, max_length=500,
blank=True blank=True,
) )
description = models.CharField( description = models.CharField(
max_length=500, max_length=500,
blank=True blank=True,
) )
action = models.CharField( action = models.CharField(
choices=ACLRuleActionChoices, choices=ACLRuleActionChoices,
@ -45,13 +46,13 @@ class ACLRule(NetBoxModel):
blank=True, blank=True,
null=True, null=True,
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+', related_name="+",
to='ipam.Prefix', to="ipam.Prefix",
verbose_name='Source Prefix' verbose_name="Source Prefix",
) )
def __str__(self): def __str__(self):
return f'{self.access_list}: Rule {self.index}' return f"{self.access_list}: Rule {self.index}"
def get_action_color(self): def get_action_color(self):
return ACLRuleActionChoices.colors.get(self.action) return ACLRuleActionChoices.colors.get(self.action)
@ -63,21 +64,23 @@ class ACLRule(NetBoxModel):
- ordering - ordering
- unique together - unique together
""" """
abstract = True abstract = True
ordering = ['access_list', 'index'] ordering = ["access_list", "index"]
unique_together = ['access_list', 'index'] unique_together = ["access_list", "index"]
class ACLStandardRule(ACLRule): class ACLStandardRule(ACLRule):
""" """
Inherits ACLRule. Inherits ACLRule.
""" """
access_list = models.ForeignKey( access_list = models.ForeignKey(
on_delete=models.CASCADE, on_delete=models.CASCADE,
to=AccessList, to=AccessList,
verbose_name='Standard Access List', verbose_name="Standard Access List",
limit_choices_to={'type': 'standard'}, limit_choices_to={"type": "standard"},
related_name='aclstandardrules', related_name="aclstandardrules",
) )
def get_absolute_url(self): def get_absolute_url(self):
@ -85,7 +88,7 @@ class ACLStandardRule(ACLRule):
The method is a Django convention; although not strictly required, The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object. 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): class Meta(ACLRule.Meta):
""" """
@ -94,40 +97,43 @@ class ACLStandardRule(ACLRule):
- verbose name (for displaying in the GUI) - verbose name (for displaying in the GUI)
- verbose name plural (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): class ACLExtendedRule(ACLRule):
""" """
Inherits ACLRule. Inherits ACLRule.
Add ACLExtendedRule specific fields: source_ports, desintation_prefix, destination_ports, and protocol Add ACLExtendedRule specific fields: source_ports, desintation_prefix, destination_ports, and protocol
""" """
access_list = models.ForeignKey( access_list = models.ForeignKey(
on_delete=models.CASCADE, on_delete=models.CASCADE,
to=AccessList, to=AccessList,
verbose_name='Extended Access List', verbose_name="Extended Access List",
limit_choices_to={'type': 'extended'}, limit_choices_to={"type": "extended"},
related_name='aclextendedrules', related_name="aclextendedrules",
) )
source_ports = ArrayField( source_ports = ArrayField(
base_field=models.PositiveIntegerField(), base_field=models.PositiveIntegerField(),
blank=True, blank=True,
null=True, null=True,
verbose_name='Soure Ports' verbose_name="Soure Ports",
) )
destination_prefix = models.ForeignKey( destination_prefix = models.ForeignKey(
blank=True, blank=True,
null=True, null=True,
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+', related_name="+",
to='ipam.Prefix', to="ipam.Prefix",
verbose_name='Destination Prefix' verbose_name="Destination Prefix",
) )
destination_ports = ArrayField( destination_ports = ArrayField(
base_field=models.PositiveIntegerField(), base_field=models.PositiveIntegerField(),
blank=True, blank=True,
null=True, null=True,
verbose_name='Destination Ports' verbose_name="Destination Ports",
) )
protocol = models.CharField( protocol = models.CharField(
blank=True, blank=True,
@ -140,7 +146,7 @@ class ACLExtendedRule(ACLRule):
The method is a Django convention; although not strictly required, The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object. 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): def get_protocol_color(self):
return ACLProtocolChoices.colors.get(self.protocol) return ACLProtocolChoices.colors.get(self.protocol)
@ -152,5 +158,6 @@ class ACLExtendedRule(ACLRule):
- verbose name (for displaying in the GUI) - verbose name (for displaying in the GUI)
- verbose name plural (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 dcim.models import Device, Interface, VirtualChassis
from django.contrib.contenttypes.fields import (GenericForeignKey, from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
GenericRelation)
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models from django.db import models
@ -13,54 +12,58 @@ from netbox.models import NetBoxModel
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from ..choices import * from ..choices import *
from ..constants import (ACL_HOST_ASSIGNMENT_MODELS, from ..constants import ACL_HOST_ASSIGNMENT_MODELS, ACL_INTERFACE_ASSIGNMENT_MODELS
ACL_INTERFACE_ASSIGNMENT_MODELS)
__all__ = ( __all__ = (
'AccessList', "AccessList",
'ACLInterfaceAssignment', "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): class AccessList(NetBoxModel):
""" """
Model defintion for Access Lists. Model defintion for Access Lists.
""" """
name = models.CharField( name = models.CharField(
max_length=500, max_length=500,
validators=[alphanumeric_plus] validators=[alphanumeric_plus],
) )
assigned_object_type = models.ForeignKey( assigned_object_type = models.ForeignKey(
to=ContentType, to=ContentType,
limit_choices_to=ACL_HOST_ASSIGNMENT_MODELS, limit_choices_to=ACL_HOST_ASSIGNMENT_MODELS,
on_delete=models.PROTECT on_delete=models.PROTECT,
) )
assigned_object_id = models.PositiveBigIntegerField() assigned_object_id = models.PositiveBigIntegerField()
assigned_object = GenericForeignKey( assigned_object = GenericForeignKey(
ct_field='assigned_object_type', ct_field="assigned_object_type",
fk_field='assigned_object_id' fk_field="assigned_object_id",
) )
type = models.CharField( type = models.CharField(
max_length=30, max_length=30,
choices=ACLTypeChoices choices=ACLTypeChoices,
) )
default_action = models.CharField( default_action = models.CharField(
default=ACLActionChoices.ACTION_DENY, default=ACLActionChoices.ACTION_DENY,
max_length=30, max_length=30,
choices=ACLActionChoices, choices=ACLActionChoices,
verbose_name='Default Action' verbose_name="Default Action",
) )
comments = models.TextField( comments = models.TextField(
blank=True blank=True,
) )
class Meta: class Meta:
unique_together = ['assigned_object_type', 'assigned_object_id', 'name'] unique_together = ["assigned_object_type", "assigned_object_id", "name"]
ordering = ['assigned_object_type', 'assigned_object_id', 'name'] ordering = ["assigned_object_type", "assigned_object_id", "name"]
verbose_name = 'Access List' verbose_name = "Access List"
verbose_name_plural = 'Access Lists' verbose_name_plural = "Access Lists"
def __str__(self): def __str__(self):
return self.name return self.name
@ -70,7 +73,7 @@ class AccessList(NetBoxModel):
The method is a Django convention; although not strictly required, The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object. 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): def get_default_action_color(self):
return ACLActionChoices.colors.get(self.default_action) return ACLActionChoices.colors.get(self.default_action)
@ -90,38 +93,50 @@ class ACLInterfaceAssignment(NetBoxModel):
access_list = models.ForeignKey( access_list = models.ForeignKey(
on_delete=models.CASCADE, on_delete=models.CASCADE,
to=AccessList, to=AccessList,
verbose_name='Access List', verbose_name="Access List",
) )
direction = models.CharField( direction = models.CharField(
max_length=30, max_length=30,
choices=ACLAssignmentDirectionChoices choices=ACLAssignmentDirectionChoices,
) )
assigned_object_type = models.ForeignKey( assigned_object_type = models.ForeignKey(
to=ContentType, to=ContentType,
limit_choices_to=ACL_INTERFACE_ASSIGNMENT_MODELS, limit_choices_to=ACL_INTERFACE_ASSIGNMENT_MODELS,
on_delete=models.PROTECT on_delete=models.PROTECT,
) )
assigned_object_id = models.PositiveBigIntegerField() assigned_object_id = models.PositiveBigIntegerField()
assigned_object = GenericForeignKey( assigned_object = GenericForeignKey(
ct_field='assigned_object_type', ct_field="assigned_object_type",
fk_field='assigned_object_id' fk_field="assigned_object_id",
) )
comments = models.TextField( comments = models.TextField(
blank=True blank=True,
) )
class Meta: class Meta:
unique_together = ['assigned_object_type', 'assigned_object_id', 'access_list', 'direction'] unique_together = [
ordering = ['assigned_object_type', 'assigned_object_id', 'access_list', 'direction'] "assigned_object_type",
verbose_name = 'ACL Interface Assignment' "assigned_object_id",
verbose_name_plural = 'ACL Interface Assignments' "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): def get_absolute_url(self):
""" """
The method is a Django convention; although not strictly required, The method is a Django convention; although not strictly required,
it conveniently returns the absolute URL for any particular object. 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): def get_direction_color(self):
return ACLAssignmentDirectionChoices.colors.get(self.direction) return ACLAssignmentDirectionChoices.colors.get(self.direction)
@ -129,35 +144,35 @@ class ACLInterfaceAssignment(NetBoxModel):
GenericRelation( GenericRelation(
to=ACLInterfaceAssignment, to=ACLInterfaceAssignment,
content_type_field='assigned_object_type', content_type_field="assigned_object_type",
object_id_field='assigned_object_id', object_id_field="assigned_object_id",
related_query_name='interface' related_query_name="interface",
).contribute_to_class(Interface, 'accesslistassignments') ).contribute_to_class(Interface, "accesslistassignments")
GenericRelation( GenericRelation(
to=ACLInterfaceAssignment, to=ACLInterfaceAssignment,
content_type_field='assigned_object_type', content_type_field="assigned_object_type",
object_id_field='assigned_object_id', object_id_field="assigned_object_id",
related_query_name='vminterface' related_query_name="vminterface",
).contribute_to_class(VMInterface, 'accesslistassignments') ).contribute_to_class(VMInterface, "accesslistassignments")
GenericRelation( GenericRelation(
to=AccessList, to=AccessList,
content_type_field='assigned_object_type', content_type_field="assigned_object_type",
object_id_field='assigned_object_id', object_id_field="assigned_object_id",
related_query_name='device' related_query_name="device",
).contribute_to_class(Device, 'accesslists') ).contribute_to_class(Device, "accesslists")
GenericRelation( GenericRelation(
to=AccessList, to=AccessList,
content_type_field='assigned_object_type', content_type_field="assigned_object_type",
object_id_field='assigned_object_id', object_id_field="assigned_object_id",
related_query_name='virtual_chassis' related_query_name="virtual_chassis",
).contribute_to_class(VirtualChassis, 'accesslists') ).contribute_to_class(VirtualChassis, "accesslists")
GenericRelation( GenericRelation(
to=AccessList, to=AccessList,
content_type_field='assigned_object_type', content_type_field="assigned_object_type",
object_id_field='assigned_object_id', object_id_field="assigned_object_id",
related_query_name='virtual_machine' related_query_name="virtual_machine",
).contribute_to_class(VirtualMachine, 'accesslists') ).contribute_to_class(VirtualMachine, "accesslists")

View File

@ -11,38 +11,38 @@ from utilities.choices import ButtonColorChoices
accesslist_buttons = [ accesslist_buttons = [
PluginMenuButton( PluginMenuButton(
link='plugins:netbox_access_lists:accesslist_add', link="plugins:netbox_access_lists:accesslist_add",
title='Add', title="Add",
icon_class='mdi mdi-plus-thick', icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN color=ButtonColorChoices.GREEN,
) ),
] ]
aclstandardrule_butons = [ aclstandardrule_butons = [
PluginMenuButton( PluginMenuButton(
link='plugins:netbox_access_lists:aclstandardrule_add', link="plugins:netbox_access_lists:aclstandardrule_add",
title='Add', title="Add",
icon_class='mdi mdi-plus-thick', icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN color=ButtonColorChoices.GREEN,
) ),
] ]
aclextendedrule_butons = [ aclextendedrule_butons = [
PluginMenuButton( PluginMenuButton(
link='plugins:netbox_access_lists:aclextendedrule_add', link="plugins:netbox_access_lists:aclextendedrule_add",
title='Add', title="Add",
icon_class='mdi mdi-plus-thick', icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN color=ButtonColorChoices.GREEN,
) ),
] ]
accesslistassignment_buttons = [ accesslistassignment_buttons = [
PluginMenuButton( PluginMenuButton(
link='plugins:netbox_access_lists:aclinterfaceassignment_add', link="plugins:netbox_access_lists:aclinterfaceassignment_add",
title='Add', title="Add",
icon_class='mdi mdi-plus-thick', icon_class="mdi mdi-plus-thick",
color=ButtonColorChoices.GREEN color=ButtonColorChoices.GREEN,
) ),
] ]
# #
@ -51,25 +51,25 @@ accesslistassignment_buttons = [
menu_items = ( menu_items = (
PluginMenuItem( PluginMenuItem(
link='plugins:netbox_access_lists:accesslist_list', link="plugins:netbox_access_lists:accesslist_list",
link_text='Access Lists', link_text="Access Lists",
buttons=accesslist_buttons buttons=accesslist_buttons,
), ),
# Comment out Standard Access List rule to force creation in the ACL view # Comment out Standard Access List rule to force creation in the ACL view
PluginMenuItem( PluginMenuItem(
link='plugins:netbox_access_lists:aclstandardrule_list', link="plugins:netbox_access_lists:aclstandardrule_list",
link_text='ACL Standard Rules', link_text="ACL Standard Rules",
buttons=aclstandardrule_butons buttons=aclstandardrule_butons,
), ),
# Comment out Extended Access List rule to force creation in the ACL view # Comment out Extended Access List rule to force creation in the ACL view
PluginMenuItem( PluginMenuItem(
link='plugins:netbox_access_lists:aclextendedrule_list', link="plugins:netbox_access_lists:aclextendedrule_list",
link_text='ACL Extended Rules', link_text="ACL Extended Rules",
buttons=aclextendedrule_butons buttons=aclextendedrule_butons,
), ),
PluginMenuItem( PluginMenuItem(
link='plugins:netbox_access_lists:aclinterfaceassignment_list', link="plugins:netbox_access_lists:aclinterfaceassignment_list",
link_text='ACL Interface Assignments', link_text="ACL Interface Assignments",
buttons=accesslistassignment_buttons 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 import django_tables2 as tables
from netbox.tables import (ChoiceFieldColumn, NetBoxTable, TemplateColumn, from netbox.tables import ChoiceFieldColumn, NetBoxTable, TemplateColumn, columns
columns)
from .models import (AccessList, ACLExtendedRule, ACLInterfaceAssignment, from .models import AccessList, ACLExtendedRule, ACLInterfaceAssignment, ACLStandardRule
ACLStandardRule)
__all__ = ( __all__ = (
'AccessListTable', "AccessListTable",
'ACLInterfaceAssignmentTable', "ACLInterfaceAssignmentTable",
'ACLStandardRuleTable', "ACLStandardRuleTable",
'ACLExtendedRuleTable', "ACLExtendedRuleTable",
) )
@ -25,93 +23,144 @@ COL_HOST_ASSIGNMENT = """
{% endif %} {% endif %}
""" """
class AccessListTable(NetBoxTable): class AccessListTable(NetBoxTable):
""" """
Defines the table view for the AccessList model. Defines the table view for the AccessList model.
""" """
pk = columns.ToggleColumn() pk = columns.ToggleColumn()
id = tables.Column( id = tables.Column(
linkify=True linkify=True,
) )
assigned_object = tables.Column( assigned_object = tables.Column(
linkify=True, linkify=True,
orderable=False, orderable=False,
verbose_name='Assigned Host' verbose_name="Assigned Host",
) )
name = tables.Column( name = tables.Column(
linkify=True linkify=True,
) )
device = tables.Column( device = tables.Column(
linkify=True linkify=True,
) )
type = ChoiceFieldColumn() type = ChoiceFieldColumn()
default_action = ChoiceFieldColumn() default_action = ChoiceFieldColumn()
rule_count = tables.Column( rule_count = tables.Column(
verbose_name='Rule Count' verbose_name="Rule Count",
) )
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:accesslist_list' url_name="plugins:netbox_access_lists:accesslist_list",
) )
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = AccessList model = AccessList
fields = ('pk', 'id', 'name', 'assigned_object', 'type', 'rule_count', 'default_action', 'comments', 'actions', 'tags') fields = (
default_columns = ('name', 'assigned_object', 'type', 'rule_count', 'default_action', 'tags') "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): class ACLInterfaceAssignmentTable(NetBoxTable):
""" """
Defines the table view for the AccessList model. Defines the table view for the AccessList model.
""" """
pk = columns.ToggleColumn() pk = columns.ToggleColumn()
id = tables.Column( id = tables.Column(
linkify=True linkify=True,
) )
access_list = tables.Column( access_list = tables.Column(
linkify=True linkify=True,
) )
direction = ChoiceFieldColumn() direction = ChoiceFieldColumn()
host = tables.TemplateColumn( host = tables.TemplateColumn(
template_code=COL_HOST_ASSIGNMENT template_code=COL_HOST_ASSIGNMENT,
) )
assigned_object = tables.Column( assigned_object = tables.Column(
linkify=True, linkify=True,
orderable=False, orderable=False,
verbose_name='Assigned Interface' verbose_name="Assigned Interface",
) )
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclinterfaceassignment_list' url_name="plugins:netbox_access_lists:aclinterfaceassignment_list",
) )
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = ACLInterfaceAssignment model = ACLInterfaceAssignment
fields = ('pk', 'id', 'access_list', 'direction', 'host', 'assigned_object', 'tags') fields = (
default_columns = ('id', 'access_list', 'direction', 'host', 'assigned_object', 'tags') "pk",
"id",
"access_list",
"direction",
"host",
"assigned_object",
"tags",
)
default_columns = (
"id",
"access_list",
"direction",
"host",
"assigned_object",
"tags",
)
class ACLStandardRuleTable(NetBoxTable): class ACLStandardRuleTable(NetBoxTable):
""" """
Defines the table view for the ACLStandardRule model. Defines the table view for the ACLStandardRule model.
""" """
access_list = tables.Column( access_list = tables.Column(
linkify=True linkify=True,
) )
index = tables.Column( index = tables.Column(
linkify=True linkify=True,
) )
action = ChoiceFieldColumn() action = ChoiceFieldColumn()
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclstandardrule_list' url_name="plugins:netbox_access_lists:aclstandardrule_list",
) )
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = ACLStandardRule model = ACLStandardRule
fields = ( 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 = ( 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. Defines the table view for the ACLExtendedRule model.
""" """
access_list = tables.Column( access_list = tables.Column(
linkify=True linkify=True,
) )
index = tables.Column( index = tables.Column(
linkify=True linkify=True,
) )
action = ChoiceFieldColumn() action = ChoiceFieldColumn()
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='plugins:netbox_access_lists:aclextendedrule_list' url_name="plugins:netbox_access_lists:aclextendedrule_list",
) )
protocol = ChoiceFieldColumn() protocol = ChoiceFieldColumn()
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = ACLExtendedRule model = ACLExtendedRule
fields = ( fields = (
'pk', 'id', 'access_list', 'index', 'action', 'actions', 'remark', 'tags', 'description', "pk",
'source_prefix', 'source_ports', 'destination_prefix', 'destination_ports', 'protocol' "id",
"access_list",
"index",
"action",
"actions",
"remark",
"tags",
"description",
"source_prefix",
"source_ports",
"destination_prefix",
"destination_ports",
"protocol",
) )
default_columns = ( default_columns = (
'access_list', 'index', 'action', 'actions', 'remark', 'tags', "access_list",
'source_prefix', 'source_ports', 'destination_prefix', 'destination_ports', 'protocol' "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 django.contrib.contenttypes.models import ContentType
from extras.plugins import PluginTemplateExtension from extras.plugins import PluginTemplateExtension
from .models import AccessList, ACLInterfaceAssignment from .models import AccessList, ACLInterfaceAssignment
__all__ = ( __all__ = (
'AccessLists', "AccessLists",
"ACLInterfaceAssignments", "ACLInterfaceAssignments",
'DeviceAccessLists', "DeviceAccessLists",
'VirtualChassisAccessLists', "VirtualChassisAccessLists",
'VMAccessLists', "VMAccessLists",
'DeviceACLInterfaceAssignments', "DeviceACLInterfaceAssignments",
'VMAACLInterfaceAssignments', "VMAACLInterfaceAssignments",
) )
class ACLInterfaceAssignments(PluginTemplateExtension): class ACLInterfaceAssignments(PluginTemplateExtension):
def right_page(self): def right_page(self):
obj = self.context['object'] obj = self.context["object"]
acl_interface_assignments = None acl_interface_assignments = None
ctype = ContentType.objects.get_for_model(obj) ctype = ContentType.objects.get_for_model(obj)
if ctype.model in ['interface', 'vminterface']: if ctype.model in ["interface", "vminterface"]:
acl_interface_assignments = ACLInterfaceAssignment.objects.filter(assigned_object_id=obj.pk, assigned_object_type=ctype) 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={ return self.render(
'acl_interface_assignments': acl_interface_assignments, "inc/assigned_interface/access_lists.html",
'type': ctype.model if ctype.model == 'device' else ctype.name.replace(' ', '_'), extra_context={
}) "acl_interface_assignments": acl_interface_assignments,
"type": ctype.model
if ctype.model == "device"
else ctype.name.replace(" ", "_"),
},
)
class AccessLists(PluginTemplateExtension): class AccessLists(PluginTemplateExtension):
def right_page(self): def right_page(self):
obj = self.context['object'] obj = self.context["object"]
access_lists = None access_lists = None
ctype = ContentType.objects.get_for_model(obj) ctype = ContentType.objects.get_for_model(obj)
if ctype.model in ['device', 'virtualchassis', 'virtualmachine']: if ctype.model in ["device", "virtualchassis", "virtualmachine"]:
access_lists = AccessList.objects.filter(assigned_object_id=obj.pk, assigned_object_type=ctype) 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={ return self.render(
'access_lists': access_lists, "inc/assigned_host/access_lists.html",
'type': ctype.model if ctype.model == 'device' else ctype.name.replace(' ', '_'), extra_context={
}) "access_lists": access_lists,
"type": ctype.model
if ctype.model == "device"
else ctype.name.replace(" ", "_"),
},
)
class DeviceAccessLists(AccessLists): class DeviceAccessLists(AccessLists):
model = 'dcim.device' model = "dcim.device"
class VirtualChassisAccessLists(AccessLists): class VirtualChassisAccessLists(AccessLists):
model = 'dcim.virtualchassis' model = "dcim.virtualchassis"
class VMAccessLists(AccessLists): class VMAccessLists(AccessLists):
model = 'virtualization.virtualmachine' model = "virtualization.virtualmachine"
class DeviceACLInterfaceAssignments(ACLInterfaceAssignments): class DeviceACLInterfaceAssignments(ACLInterfaceAssignments):
model = 'dcim.interface' model = "dcim.interface"
class VMAACLInterfaceAssignments(ACLInterfaceAssignments): 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

@ -24,4 +24,4 @@
<div class="text-muted"> <div class="text-muted">
None found None found
</div> </div>
{% endif %} {% endif %}

View File

@ -8,51 +8,152 @@ from netbox.views.generic import ObjectChangeLogView
from . import models, views from . import models, views
urlpatterns = ( urlpatterns = (
# Access Lists # Access Lists
path('access-lists/', views.AccessListListView.as_view(), name='accesslist_list'), path("access-lists/", views.AccessListListView.as_view(), name="accesslist_list"),
path('access-lists/add/', views.AccessListEditView.as_view(), name='accesslist_add'), path(
#path('access-lists/edit/', views.AccessListBulkEditView.as_view(), name='accesslist_bulk_edit'), "access-lists/add/", views.AccessListEditView.as_view(), name="accesslist_add"
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/edit/', views.AccessListBulkEditView.as_view(), name='accesslist_bulk_edit'),
path('access-lists/<int:pk>/edit/', views.AccessListEditView.as_view(), name='accesslist_edit'), path(
path('access-lists/<int:pk>/delete/', views.AccessListDeleteView.as_view(), name='accesslist_delete'), "access-lists/delete/",
path('access-lists/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='accesslist_changelog', kwargs={ views.AccessListBulkDeleteView.as_view(),
'model': models.AccessList 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 # Access List Interface Assignments
path('interface-assignments/', views.ACLInterfaceAssignmentListView.as_view(), name='aclinterfaceassignment_list'), path(
path('interface-assignments/add/', views.ACLInterfaceAssignmentEditView.as_view(), name='aclinterfaceassignment_add'), "interface-assignments/",
#path('interface-assignments/edit/', views.ACLInterfaceAssignmentBulkEditView.as_view(), name='aclinterfaceassignment_bulk_edit'), views.ACLInterfaceAssignmentListView.as_view(),
path('interface-assignments/delete/', views.ACLInterfaceAssignmentBulkDeleteView.as_view(), name='aclinterfaceassignment_bulk_delete'), name="aclinterfaceassignment_list",
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(
path('interface-assignments/<int:pk>/delete/', views.ACLInterfaceAssignmentDeleteView.as_view(), name='aclinterfaceassignment_delete'), "interface-assignments/add/",
path('interface-assignments/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclinterfaceassignment_changelog', kwargs={ views.ACLInterfaceAssignmentEditView.as_view(),
'model': models.ACLInterfaceAssignment 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 # Standard Access List Rules
path('standard-rules/', views.ACLStandardRuleListView.as_view(), name='aclstandardrule_list'), path(
path('standard-rules/add/', views.ACLStandardRuleEditView.as_view(), name='aclstandardrule_add'), "standard-rules/",
path('standard-rules/delete/', views.ACLStandardRuleBulkDeleteView.as_view(), name='aclstandardrule_bulk_delete'), views.ACLStandardRuleListView.as_view(),
path('standard-rules/<int:pk>/', views.ACLStandardRuleView.as_view(), name='aclstandardrule'), name="aclstandardrule_list",
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(
path('standard-rules/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclstandardrule_changelog', kwargs={ "standard-rules/add/",
'model': models.ACLStandardRule 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 # Extended Access List Rules
path('extended-rules/', views.ACLExtendedRuleListView.as_view(), name='aclextendedrule_list'), path(
path('extended-rules/add/', views.ACLExtendedRuleEditView.as_view(), name='aclextendedrule_add'), "extended-rules/",
path('extended-rules/delete/', views.ACLExtendedRuleBulkDeleteView.as_view(), name='aclextendedrule_bulk_delete'), views.ACLExtendedRuleListView.as_view(),
path('extended-rules/<int:pk>/', views.ACLExtendedRuleView.as_view(), name='aclextendedrule'), name="aclextendedrule_list",
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(
path('extended-rules/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='aclextendedrule_changelog', kwargs={ "extended-rules/add/",
'model': models.ACLExtendedRule 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 from . import filtersets, forms, models, tables
__all__ = ( __all__ = (
'AccessListView', "AccessListView",
'AccessListListView', "AccessListListView",
'AccessListEditView', "AccessListEditView",
'AccessListDeleteView', "AccessListDeleteView",
'AccessListBulkDeleteView', "AccessListBulkDeleteView",
'ACLInterfaceAssignmentView', "ACLInterfaceAssignmentView",
'ACLInterfaceAssignmentListView', "ACLInterfaceAssignmentListView",
'ACLInterfaceAssignmentEditView', "ACLInterfaceAssignmentEditView",
'ACLInterfaceAssignmentDeleteView', "ACLInterfaceAssignmentDeleteView",
'ACLInterfaceAssignmentBulkDeleteView', "ACLInterfaceAssignmentBulkDeleteView",
'ACLStandardRuleView', "ACLStandardRuleView",
'ACLStandardRuleListView', "ACLStandardRuleListView",
'ACLStandardRuleEditView', "ACLStandardRuleEditView",
'ACLStandardRuleDeleteView', "ACLStandardRuleDeleteView",
'ACLStandardRuleBulkDeleteView', "ACLStandardRuleBulkDeleteView",
'ACLExtendedRuleView', "ACLExtendedRuleView",
'ACLExtendedRuleListView', "ACLExtendedRuleListView",
'ACLExtendedRuleEditView', "ACLExtendedRuleEditView",
'ACLExtendedRuleDeleteView', "ACLExtendedRuleDeleteView",
'ACLExtendedRuleBulkDeleteView', "ACLExtendedRuleBulkDeleteView",
) )
@ -36,24 +36,26 @@ __all__ = (
# AccessList views # AccessList views
# #
class AccessListView(generic.ObjectView): class AccessListView(generic.ObjectView):
""" """
Defines the view for the AccessLists django model. Defines the view for the AccessLists django model.
""" """
queryset = models.AccessList.objects.all() queryset = models.AccessList.objects.all()
def get_extra_context(self, request, instance): 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. 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()) table = tables.ACLExtendedRuleTable(instance.aclextendedrules.all())
elif instance.type == 'standard': elif instance.type == "standard":
table = tables.ACLStandardRuleTable(instance.aclstandardrules.all()) table = tables.ACLStandardRuleTable(instance.aclstandardrules.all())
table.configure(request) table.configure(request)
return { return {
'rules_table': table "rules_table": table,
} }
@ -61,8 +63,9 @@ class AccessListListView(generic.ObjectListView):
""" """
Defines the list view for the AccessLists django model. Defines the list view for the AccessLists django model.
""" """
queryset = models.AccessList.objects.annotate( queryset = models.AccessList.objects.annotate(
rule_count=Count('aclextendedrules') + Count('aclstandardrules') rule_count=Count("aclextendedrules") + Count("aclstandardrules"),
) )
table = tables.AccessListTable table = tables.AccessListTable
filterset = filtersets.AccessListFilterSet filterset = filtersets.AccessListFilterSet
@ -73,15 +76,17 @@ class AccessListEditView(generic.ObjectEditView):
""" """
Defines the edit view for the AccessLists django model. Defines the edit view for the AccessLists django model.
""" """
queryset = models.AccessList.objects.all() queryset = models.AccessList.objects.all()
form = forms.AccessListForm form = forms.AccessListForm
template_name = 'netbox_access_lists/accesslist_edit.html' template_name = "netbox_access_lists/accesslist_edit.html"
class AccessListDeleteView(generic.ObjectDeleteView): class AccessListDeleteView(generic.ObjectDeleteView):
""" """
Defines the delete view for the AccessLists django model. Defines the delete view for the AccessLists django model.
""" """
queryset = models.AccessList.objects.all() queryset = models.AccessList.objects.all()
@ -90,14 +95,17 @@ class AccessListBulkDeleteView(generic.BulkDeleteView):
filterset = filtersets.AccessListFilterSet filterset = filtersets.AccessListFilterSet
table = tables.AccessListTable table = tables.AccessListTable
# #
# ACLInterfaceAssignment views # ACLInterfaceAssignment views
# #
class ACLInterfaceAssignmentView(generic.ObjectView): class ACLInterfaceAssignmentView(generic.ObjectView):
""" """
Defines the view for the ACLInterfaceAssignments django model. Defines the view for the ACLInterfaceAssignments django model.
""" """
queryset = models.ACLInterfaceAssignment.objects.all() queryset = models.ACLInterfaceAssignment.objects.all()
@ -105,6 +113,7 @@ class ACLInterfaceAssignmentListView(generic.ObjectListView):
""" """
Defines the list view for the ACLInterfaceAssignments django model. Defines the list view for the ACLInterfaceAssignments django model.
""" """
queryset = models.ACLInterfaceAssignment.objects.all() queryset = models.ACLInterfaceAssignment.objects.all()
table = tables.ACLInterfaceAssignmentTable table = tables.ACLInterfaceAssignmentTable
filterset = filtersets.ACLInterfaceAssignmentFilterSet filterset = filtersets.ACLInterfaceAssignmentFilterSet
@ -115,15 +124,17 @@ class ACLInterfaceAssignmentEditView(generic.ObjectEditView):
""" """
Defines the edit view for the ACLInterfaceAssignments django model. Defines the edit view for the ACLInterfaceAssignments django model.
""" """
queryset = models.ACLInterfaceAssignment.objects.all() queryset = models.ACLInterfaceAssignment.objects.all()
form = forms.ACLInterfaceAssignmentForm form = forms.ACLInterfaceAssignmentForm
template_name = 'netbox_access_lists/aclinterfaceassignment_edit.html' template_name = "netbox_access_lists/aclinterfaceassignment_edit.html"
class ACLInterfaceAssignmentDeleteView(generic.ObjectDeleteView): class ACLInterfaceAssignmentDeleteView(generic.ObjectDeleteView):
""" """
Defines the delete view for the ACLInterfaceAssignments django model. Defines the delete view for the ACLInterfaceAssignments django model.
""" """
queryset = models.ACLInterfaceAssignment.objects.all() queryset = models.ACLInterfaceAssignment.objects.all()
@ -142,6 +153,7 @@ class ACLStandardRuleView(generic.ObjectView):
""" """
Defines the view for the ACLStandardRule django model. Defines the view for the ACLStandardRule django model.
""" """
queryset = models.ACLStandardRule.objects.all() queryset = models.ACLStandardRule.objects.all()
@ -149,6 +161,7 @@ class ACLStandardRuleListView(generic.ObjectListView):
""" """
Defines the list view for the ACLStandardRule django model. Defines the list view for the ACLStandardRule django model.
""" """
queryset = models.ACLStandardRule.objects.all() queryset = models.ACLStandardRule.objects.all()
table = tables.ACLStandardRuleTable table = tables.ACLStandardRuleTable
filterset = filtersets.ACLStandardRuleFilterSet filterset = filtersets.ACLStandardRuleFilterSet
@ -159,6 +172,7 @@ class ACLStandardRuleEditView(generic.ObjectEditView):
""" """
Defines the edit view for the ACLStandardRule django model. Defines the edit view for the ACLStandardRule django model.
""" """
queryset = models.ACLStandardRule.objects.all() queryset = models.ACLStandardRule.objects.all()
form = forms.ACLStandardRuleForm form = forms.ACLStandardRuleForm
@ -167,6 +181,7 @@ class ACLStandardRuleDeleteView(generic.ObjectDeleteView):
""" """
Defines the delete view for the ACLStandardRules django model. Defines the delete view for the ACLStandardRules django model.
""" """
queryset = models.ACLStandardRule.objects.all() queryset = models.ACLStandardRule.objects.all()
@ -175,6 +190,7 @@ class ACLStandardRuleBulkDeleteView(generic.BulkDeleteView):
filterset = filtersets.ACLStandardRuleFilterSet filterset = filtersets.ACLStandardRuleFilterSet
table = tables.ACLStandardRuleTable table = tables.ACLStandardRuleTable
# #
# ACLExtendedRule views # ACLExtendedRule views
# #
@ -184,6 +200,7 @@ class ACLExtendedRuleView(generic.ObjectView):
""" """
Defines the view for the ACLExtendedRule django model. Defines the view for the ACLExtendedRule django model.
""" """
queryset = models.ACLExtendedRule.objects.all() queryset = models.ACLExtendedRule.objects.all()
@ -191,6 +208,7 @@ class ACLExtendedRuleListView(generic.ObjectListView):
""" """
Defines the list view for the ACLExtendedRule django model. Defines the list view for the ACLExtendedRule django model.
""" """
queryset = models.ACLExtendedRule.objects.all() queryset = models.ACLExtendedRule.objects.all()
table = tables.ACLExtendedRuleTable table = tables.ACLExtendedRuleTable
filterset = filtersets.ACLExtendedRuleFilterSet filterset = filtersets.ACLExtendedRuleFilterSet
@ -201,6 +219,7 @@ class ACLExtendedRuleEditView(generic.ObjectEditView):
""" """
Defines the edit view for the ACLExtendedRule django model. Defines the edit view for the ACLExtendedRule django model.
""" """
queryset = models.ACLExtendedRule.objects.all() queryset = models.ACLExtendedRule.objects.all()
form = forms.ACLExtendedRuleForm form = forms.ACLExtendedRuleForm
@ -209,8 +228,10 @@ class ACLExtendedRuleDeleteView(generic.ObjectDeleteView):
""" """
Defines the delete view for the ACLExtendedRules django model. Defines the delete view for the ACLExtendedRules django model.
""" """
queryset = models.ACLExtendedRule.objects.all() queryset = models.ACLExtendedRule.objects.all()
class ACLExtendedRuleBulkDeleteView(generic.BulkDeleteView): class ACLExtendedRuleBulkDeleteView(generic.BulkDeleteView):
queryset = models.ACLExtendedRule.objects.all() queryset = models.ACLExtendedRule.objects.all()
filterset = filtersets.ACLExtendedRuleFilterSet filterset = filtersets.ACLExtendedRuleFilterSet

View File

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