From 108fbb6751fc0dea209043d56ed93a708632af1d Mon Sep 17 00:00:00 2001 From: Ryan Merolle Date: Fri, 23 Jun 2023 14:41:42 -0400 Subject: [PATCH] NetBox 3.5 Support (#148) * NetBox 3.5 updates --- .devcontainer/Dockerfile-plugin_dev | 4 +- .devcontainer/configuration/configuration.py | 9 +-- .devcontainer/devcontainer.json | 12 ++- .devcontainer/env/netbox.env | 2 +- .devcontainer/requirements-dev.txt | 3 +- .flake8 | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- .isort.cfg | 8 -- .jscpd.json | 4 +- .pre-commit-config.yaml | 14 ++-- Dockerfile | 6 +- README.md | 1 + configuration/configuration.py | 5 +- env/netbox.env | 2 +- netbox_acls/__init__.py | 4 +- netbox_acls/api/serializers.py | 37 +++------ netbox_acls/constants.py | 3 +- netbox_acls/forms/bulk_edit.py | 4 +- netbox_acls/forms/filtersets.py | 4 +- netbox_acls/forms/models.py | 76 ++++++------------- netbox_acls/graphql/schema.py | 1 + netbox_acls/graphql/types.py | 1 - netbox_acls/migrations/0001_initial.py | 6 +- .../0002_alter_accesslist_options_and_more.py | 1 - netbox_acls/migrations/0003_netbox_acls.py | 1 - netbox_acls/tests/test_api.py | 2 +- netbox_acls/urls.py | 6 +- netbox_acls/version.py | 2 +- netbox_acls/views.py | 12 ++- pyproject.toml | 23 ++++++ setup.py | 15 +++- 32 files changed, 133 insertions(+), 143 deletions(-) delete mode 100644 .isort.cfg create mode 100644 pyproject.toml diff --git a/.devcontainer/Dockerfile-plugin_dev b/.devcontainer/Dockerfile-plugin_dev index ea10664..633f053 100644 --- a/.devcontainer/Dockerfile-plugin_dev +++ b/.devcontainer/Dockerfile-plugin_dev @@ -1,8 +1,8 @@ -ARG NETBOX_VARIANT=v3.4 +ARG NETBOX_VARIANT=v3.5 FROM netboxcommunity/netbox:${NETBOX_VARIANT} -ARG NETBOX_INITIALIZERS_VARIANT=3.4.* +ARG NETBOX_INITIALIZERS_VARIANT=3.5.* ARG DEBIAN_FRONTEND=noninteractive diff --git a/.devcontainer/configuration/configuration.py b/.devcontainer/configuration/configuration.py index 004d725..0a41530 100644 --- a/.devcontainer/configuration/configuration.py +++ b/.devcontainer/configuration/configuration.py @@ -7,7 +7,7 @@ from os.path import abspath, dirname, join # Read secret from file def _read_secret(secret_name, default=None): try: - f = open("/run/secrets/" + secret_name, encoding="utf-8") + f = open(f"/run/secrets/{secret_name}", encoding="utf-8") except OSError: return default else: @@ -74,8 +74,7 @@ REDIS = { environ.get("REDIS_CACHE_PASSWORD", environ.get("REDIS_PASSWORD", "")), ), "DATABASE": int(environ.get("REDIS_CACHE_DATABASE", 1)), - "SSL": environ.get("REDIS_CACHE_SSL", environ.get("REDIS_SSL", "False")).lower() - == "true", + "SSL": environ.get("REDIS_CACHE_SSL", environ.get("REDIS_SSL", "False")).lower() == "true", "INSECURE_SKIP_TLS_VERIFY": environ.get( "REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY", environ.get("REDIS_INSECURE_SKIP_TLS_VERIFY", "False"), @@ -252,9 +251,7 @@ REMOTE_AUTH_BACKEND = environ.get( "netbox.authentication.RemoteUserBackend", ) REMOTE_AUTH_HEADER = environ.get("REMOTE_AUTH_HEADER", "HTTP_REMOTE_USER") -REMOTE_AUTH_AUTO_CREATE_USER = ( - environ.get("REMOTE_AUTH_AUTO_CREATE_USER", "True").lower() == "true" -) +REMOTE_AUTH_AUTO_CREATE_USER = environ.get("REMOTE_AUTH_AUTO_CREATE_USER", "True").lower() == "true" REMOTE_AUTH_DEFAULT_GROUPS = list( filter(None, environ.get("REMOTE_AUTH_DEFAULT_GROUPS", "").split(" ")), ) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2d3b513..6453f36 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -78,23 +78,31 @@ "extensions": [ "DavidAnson.vscode-markdownlint", "GitHub.codespaces", - "GitHub.copilot", "GitHub.copilot-labs", "GitHub.vscode-pull-request-github", "Gruntfuggly.todo-tree", "Tyriar.sort-lines", "aaron-bond.better-comments", "batisteo.vscode-django", + "charliermarsh.ruff", "codezombiech.gitignore", "esbenp.prettier-vscode", + "exiasr.hadolint", "formulahendry.auto-rename-tag", "mintlify.document", + "ms-python.isort", + "ms-python.pylint", "ms-python.python", "ms-python.vscode-pylance", + "ms-vscode.makefile-tools", "mutantdino.resourcemonitor", + "oderwat.indent-rainbow", "paulomenezes.duplicated-code", + "redhat.vscode-yaml", "searKing.preview-vscode", - "sourcery.sourcery" + "sourcery.sourcery", + "wholroyd.jinja", + "yzhang.markdown-all-in-one" ] } }, diff --git a/.devcontainer/env/netbox.env b/.devcontainer/env/netbox.env index ba8a54e..13b0f61 100644 --- a/.devcontainer/env/netbox.env +++ b/.devcontainer/env/netbox.env @@ -15,7 +15,7 @@ REDIS_DATABASE=0 REDIS_HOST=redis REDIS_INSECURE_SKIP_TLS_VERIFY=false REDIS_PASSWORD=H733Kdjndks81 -SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj +SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNjaa SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 SUPERUSER_EMAIL=admin@example.com SUPERUSER_NAME=admin diff --git a/.devcontainer/requirements-dev.txt b/.devcontainer/requirements-dev.txt index d4a50d5..80fc9bf 100644 --- a/.devcontainer/requirements-dev.txt +++ b/.devcontainer/requirements-dev.txt @@ -10,6 +10,7 @@ pycodestyle pydocstyle pylint pylint-django +ruff +sourcery-analytics wily yapf -sourcery-analytics diff --git a/.flake8 b/.flake8 index 55e13d2..e599bed 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,3 @@ [flake8] -max-line-length = 160 +max-line-length = 140 extend-ignore = E203 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index ac362e9..7008bae 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -23,14 +23,14 @@ body: attributes: label: NetBox access-list plugin version description: What version of the NetBox access-list plugin are you currently running? - placeholder: v1.2.0 + placeholder: v1.3.0 validations: required: true - type: input attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.4.3 + placeholder: v3.5.4 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index ca31eaf..9f473b7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -15,7 +15,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.4.3 + placeholder: v3.5.4 validations: required: true - type: dropdown diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index a9a8d64..0000000 --- a/.isort.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[settings] -profile = black - -; vertical hanging indent mode also used in black configuration -multi_line_output = 3 - -; necessary because black expect the trailing comma -include_trailing_comma = true diff --git a/.jscpd.json b/.jscpd.json index 338acfe..481edca 100644 --- a/.jscpd.json +++ b/.jscpd.json @@ -1,4 +1,4 @@ { - "threshold": 10, - "ignore": ["**/tests/**"] + "threshold": 10, + "ignore": ["**/migrations/**", "**/tests/**"] } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 374cc10..4580d6c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,13 +21,13 @@ repos: - "--profile=black" exclude: ^.devcontainer/ - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black language_version: python3 exclude: ^.devcontainer/ - repo: https://github.com/asottile/add-trailing-comma - rev: v2.4.0 + rev: v2.5.1 hooks: - id: add-trailing-comma args: @@ -38,13 +38,13 @@ repos: - id: flake8 exclude: ^.devcontainer/ - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.7.0 hooks: - id: pyupgrade args: - "--py39-plus" - repo: https://github.com/adrienverge/yamllint - rev: v1.29.0 + rev: v1.32.0 hooks: - id: yamllint - repo: https://github.com/econchick/interrogate @@ -59,9 +59,13 @@ repos: # - id: htmlhint # args: [--config, .htmlhintrc] - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.33.0 + rev: v0.35.0 hooks: - id: markdownlint + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.272 + hooks: + - id: ruff #- repo: local # hooks: # - id: wily diff --git a/Dockerfile b/Dockerfile index 72b0fcd..3b4a257 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -ARG NETBOX_VARIANT=v3.4 +ARG NETBOX_VARIANT=v3.5 FROM netboxcommunity/netbox:${NETBOX_VARIANT} RUN mkdir -pv /plugins/netbox-acls COPY . /plugins/netbox-acls -RUN /opt/netbox/venv/bin/python3 /plugins/netbox-acls/setup.py develop -RUN cp -rf /plugins/netbox-acls/netbox_acls/ /opt/netbox/venv/lib/python3.10/site-packages/netbox_acls +RUN /opt/netbox/venv/bin/python3 /plugins/netbox-acls/setup.py develop && \ + cp -rf /plugins/netbox-acls/netbox_acls/ /opt/netbox/venv/lib/python3.10/site-packages/netbox_acls diff --git a/README.md b/README.md index 6af94cf..286a368 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Each Plugin Version listed below has been tested with its corresponding NetBox V | 3.2 | 1.0.1 | | 3.3 | 1.1.0 | | 3.4 | 1.2.2 | +| 3.5 | 1.3.0 | ## Installing diff --git a/configuration/configuration.py b/configuration/configuration.py index 353d9d6..2cf4668 100644 --- a/configuration/configuration.py +++ b/configuration/configuration.py @@ -14,7 +14,7 @@ from os.path import abspath, dirname # Read secret from file def _read_secret(secret_name, default=None): try: - f = open("/run/secrets/" + secret_name, encoding="utf-8") + f = open(f"/run/secrets/{secret_name}", encoding="utf-8") except OSError: return default else: @@ -81,8 +81,7 @@ REDIS = { environ.get("REDIS_CACHE_PASSWORD", environ.get("REDIS_PASSWORD", "")), ), "DATABASE": int(environ.get("REDIS_CACHE_DATABASE", 1)), - "SSL": environ.get("REDIS_CACHE_SSL", environ.get("REDIS_SSL", "False")).lower() - == "true", + "SSL": environ.get("REDIS_CACHE_SSL", environ.get("REDIS_SSL", "False")).lower() == "true", "INSECURE_SKIP_TLS_VERIFY": environ.get( "REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY", environ.get("REDIS_INSECURE_SKIP_TLS_VERIFY", "False"), diff --git a/env/netbox.env b/env/netbox.env index ee71174..8950d9f 100644 --- a/env/netbox.env +++ b/env/netbox.env @@ -14,7 +14,7 @@ REDIS_DATABASE=0 REDIS_HOST=redis REDIS_INSECURE_SKIP_TLS_VERIFY=false REDIS_PASSWORD=H733Kdjndks81 -SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj +SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNjaa SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 SUPERUSER_EMAIL=admin@example.com SUPERUSER_NAME=admin diff --git a/netbox_acls/__init__.py b/netbox_acls/__init__.py index fa5e548..4898b59 100644 --- a/netbox_acls/__init__.py +++ b/netbox_acls/__init__.py @@ -17,8 +17,8 @@ class NetBoxACLsConfig(PluginConfig): version = __version__ description = "Manage simple ACLs in NetBox" base_url = "access-lists" - min_version = "3.4.0" - max_version = "3.4.99" + min_version = "3.5.0" + max_version = "3.5.99" config = NetBoxACLsConfig diff --git a/netbox_acls/api/serializers.py b/netbox_acls/api/serializers.py index 2dc4d04..241134e 100644 --- a/netbox_acls/api/serializers.py +++ b/netbox_acls/api/serializers.py @@ -4,8 +4,7 @@ while Django itself handles the database abstraction. """ from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist -from drf_yasg.utils import swagger_serializer_method +from drf_spectacular.utils import extend_schema_field from ipam.api.serializers import NestedPrefixSerializer from netbox.api.fields import ContentTypeField from netbox.api.serializers import NetBoxModelSerializer @@ -32,13 +31,9 @@ __all__ = [ # 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." # Sets a standard error message for ACL rules with an action of remark, but no source_prefix is set. -error_message_action_remark_source_prefix_set = ( - "Action is set to remark, Source Prefix CANNOT be set." -) +error_message_action_remark_source_prefix_set = "Action is set to remark, Source Prefix CANNOT be set." # Sets a standard error message for ACL rules with an action not set to remark, but no remark is set. -error_message_remark_without_action_remark = ( - "CANNOT set remark unless action is set to remark." -) +error_message_remark_without_action_remark = "CANNOT set remark unless action is set to remark." # Sets a standard error message for ACL rules no associated to an ACL of the same type. error_message_acl_type = "Provided parent Access List is not of right type." @@ -81,7 +76,7 @@ class AccessListSerializer(NetBoxModelSerializer): "rule_count", ) - @swagger_serializer_method(serializer_or_field=serializers.DictField) + @extend_schema_field(serializers.DictField()) def get_assigned_object(self, obj): serializer = get_serializer_for_model( obj.assigned_object, @@ -99,11 +94,7 @@ class AccessListSerializer(NetBoxModelSerializer): error_message = {} # 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 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.", ] @@ -149,7 +140,7 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer): "last_updated", ) - @swagger_serializer_method(serializer_or_field=serializers.DictField) + @extend_schema_field(serializers.DictField()) def get_assigned_object(self, obj): serializer = get_serializer_for_model( obj.assigned_object, @@ -168,24 +159,14 @@ class ACLInterfaceAssignmentSerializer(NetBoxModelSerializer): acl_host = data["access_list"].assigned_object if data["assigned_object_type"].model == "interface": - interface_host = ( - data["assigned_object_type"] - .get_object_for_this_type(id=data["assigned_object_id"]) - .device - ) + interface_host = data["assigned_object_type"].get_object_for_this_type(id=data["assigned_object_id"]).device elif data["assigned_object_type"].model == "vminterface": - interface_host = ( - data["assigned_object_type"] - .get_object_for_this_type(id=data["assigned_object_id"]) - .virtual_machine - ) + interface_host = data["assigned_object_type"].get_object_for_this_type(id=data["assigned_object_id"]).virtual_machine else: interface_host = None # Check that the associated interface's parent host has the selected ACL defined. if acl_host != interface_host: - error_acl_not_assigned_to_host = ( - "Access List not present on the selected interface's host." - ) + error_acl_not_assigned_to_host = "Access List not present on the selected interface's host." error_message["access_list"] = [error_acl_not_assigned_to_host] error_message["assigned_object_id"] = [error_acl_not_assigned_to_host] diff --git a/netbox_acls/constants.py b/netbox_acls/constants.py index 8d73006..468845c 100644 --- a/netbox_acls/constants.py +++ b/netbox_acls/constants.py @@ -10,6 +10,5 @@ ACL_HOST_ASSIGNMENT_MODELS = Q( ) ACL_INTERFACE_ASSIGNMENT_MODELS = Q( - Q(app_label="dcim", model="interface") - | Q(app_label="virtualization", model="vminterface"), + Q(app_label="dcim", model="interface") | Q(app_label="virtualization", model="vminterface"), ) diff --git a/netbox_acls/forms/bulk_edit.py b/netbox_acls/forms/bulk_edit.py index 81b4dd8..7ac0ab6 100644 --- a/netbox_acls/forms/bulk_edit.py +++ b/netbox_acls/forms/bulk_edit.py @@ -7,11 +7,11 @@ Draft for a possible BulkEditForm, but may not be worth wile. # from django.core.exceptions import ValidationError # from django.utils.safestring import mark_safe # from netbox.forms import NetBoxModelBulkEditForm -# from utilities.forms import ( +# from utilities.forms.utils import add_blank_choice +# from utilities.forms.fields import ( # ChoiceField, # DynamicModelChoiceField, # StaticSelect, -# add_blank_choice, # ) # from virtualization.models import VirtualMachine diff --git a/netbox_acls/forms/filtersets.py b/netbox_acls/forms/filtersets.py index f227e3f..37f20df 100644 --- a/netbox_acls/forms/filtersets.py +++ b/netbox_acls/forms/filtersets.py @@ -6,13 +6,13 @@ from dcim.models import Device, Interface, Region, Site, SiteGroup, VirtualChass from django import forms from ipam.models import Prefix from netbox.forms import NetBoxModelFilterSetForm -from utilities.forms import ( +from utilities.forms.fields import ( ChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField, - add_blank_choice, ) +from utilities.forms.utils import add_blank_choice from virtualization.models import VirtualMachine, VMInterface from ..choices import ( diff --git a/netbox_acls/forms/models.py b/netbox_acls/forms/models.py index 8d04d3a..0c95ef5 100644 --- a/netbox_acls/forms/models.py +++ b/netbox_acls/forms/models.py @@ -8,7 +8,7 @@ from django.contrib.contenttypes.models import ContentType from django.utils.safestring import mark_safe from ipam.models import Prefix from netbox.forms import NetBoxModelForm -from utilities.forms import CommentField, DynamicModelChoiceField +from utilities.forms.fields import CommentField, DynamicModelChoiceField from virtualization.models import ( Cluster, ClusterGroup, @@ -39,20 +39,14 @@ help_text_acl_rule_logic = mark_safe( # 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)." # Sets a standard help_text value to be used by the various classes for acl index -help_text_acl_rule_index = ( - "Determines the order of the rule in the ACL processing. AKA Sequence Number." -) +help_text_acl_rule_index = "Determines the order of the rule in the ACL processing. AKA Sequence Number." # Sets a standard error message for ACL rules with an action of remark, but no remark set. error_message_no_remark = "Action is set to remark, you MUST add a remark." # Sets a standard error message for ACL rules with an action of remark, but no source_prefix is set. -error_message_action_remark_source_prefix_set = ( - "Action is set to remark, Source Prefix CANNOT be set." -) +error_message_action_remark_source_prefix_set = "Action is set to remark, Source Prefix CANNOT be set." # Sets a standard error message for ACL rules with an action not set to remark, but no remark is set. -error_message_remark_without_action_remark = ( - "CANNOT set remark unless action is set to remark." -) +error_message_remark_without_action_remark = "CANNOT set remark unless action is set to remark." class AccessListForm(NetBoxModelForm): @@ -149,7 +143,6 @@ class AccessListForm(NetBoxModelForm): } def __init__(self, *args, **kwargs): - # Initialize helper selectors instance = kwargs.get("instance") initial = kwargs.get("initial", {}).copy() @@ -168,9 +161,7 @@ class AccessListForm(NetBoxModelForm): if instance.assigned_object.cluster: initial["cluster"] = instance.assigned_object.cluster if instance.assigned_object.cluster.group: - initial[ - "cluster_group" - ] = instance.assigned_object.cluster.group + initial["cluster_group"] = instance.assigned_object.cluster.group if instance.assigned_object.cluster.type: initial["cluster_type"] = instance.assigned_object.cluster.type @@ -199,13 +190,9 @@ class AccessListForm(NetBoxModelForm): virtual_machine = cleaned_data.get("virtual_machine") # Check if more than one host type selected. - if ( - (device and virtual_chassis) - or (device and virtual_machine) - or (virtual_chassis and virtual_machine) - ): + if (device and virtual_chassis) or (device and virtual_machine) or (virtual_chassis and virtual_machine): raise forms.ValidationError( - "Access Lists must be assigned to one host (either a device, virtual chassis or virtual machine) at a time.", + "Access Lists must be assigned to one host at a time. Either a device, virtual chassis or virtual machine." ) # Check if no hosts selected. if not device and not virtual_chassis and not virtual_machine: @@ -230,28 +217,20 @@ class AccessListForm(NetBoxModelForm): ).exists() # Check if duplicate entry. - if ( - "name" in self.changed_data or host_type in self.changed_data - ) and existing_acls: - error_same_acl_name = ( - "An ACL with this name is already associated to this host." - ) + if ("name" in self.changed_data or host_type in self.changed_data) and existing_acls: + error_same_acl_name = "An ACL with this name is already associated to this host." error_message |= { host_type: [error_same_acl_name], "name": [error_same_acl_name], } - if self.instance.pk: - # Check if Access List has no existing rules before change the Access List's type. - if ( - acl_type == ACLTypeChoices.TYPE_EXTENDED - and self.instance.aclstandardrules.exists() - ) or ( - acl_type == ACLTypeChoices.TYPE_STANDARD - and self.instance.aclextendedrules.exists() - ): - error_message["type"] = [ - "This ACL has ACL rules associated, CANNOT change ACL type.", - ] + # Check if Access List has no existing rules before change the Access List's type. + if self.instance.pk and ( + (acl_type == ACLTypeChoices.TYPE_EXTENDED and self.instance.aclstandardrules.exists()) + or (acl_type == ACLTypeChoices.TYPE_STANDARD and self.instance.aclextendedrules.exists()) + ): + error_message["type"] = [ + "This ACL has ACL rules associated, CANNOT change ACL type.", + ] if error_message: raise forms.ValidationError(error_message) @@ -261,9 +240,7 @@ class AccessListForm(NetBoxModelForm): def save(self, *args, **kwargs): # Set assigned object self.instance.assigned_object = ( - self.cleaned_data.get("device") - or self.cleaned_data.get("virtual_chassis") - or self.cleaned_data.get("virtual_machine") + self.cleaned_data.get("device") or self.cleaned_data.get("virtual_chassis") or self.cleaned_data.get("virtual_machine") ) return super().save(*args, **kwargs) @@ -324,7 +301,6 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm): comments = CommentField() def __init__(self, *args, **kwargs): - # Initialize helper selectors instance = kwargs.get("instance") initial = kwargs.get("initial", {}).copy() @@ -376,15 +352,15 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm): # Check if both interface and vminterface are set. if interface and vminterface: - error_too_many_interfaces = "Access Lists must be assigned to one type of interface at a time (VM interface or physical interface)" + error_too_many_interfaces = ( + "Access Lists must be assigned to one type of interface at a time (VM interface or physical interface)" + ) error_message |= { "interface": [error_too_many_interfaces], "vminterface": [error_too_many_interfaces], } elif not (interface or vminterface): - error_no_interface = ( - "An Access List assignment but specify an Interface or VM Interface." - ) + error_no_interface = "An Access List assignment but specify an Interface or VM Interface." error_message |= { "interface": [error_no_interface], "vminterface": [error_no_interface], @@ -410,9 +386,7 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm): # Check that an interface's parent device/virtual_machine is assigned to the Access List. if 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], @@ -437,9 +411,7 @@ class ACLInterfaceAssignmentForm(NetBoxModelForm): 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_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], diff --git a/netbox_acls/graphql/schema.py b/netbox_acls/graphql/schema.py index cdaa8a2..0dc2dd2 100644 --- a/netbox_acls/graphql/schema.py +++ b/netbox_acls/graphql/schema.py @@ -3,6 +3,7 @@ from netbox.graphql.fields import ObjectField, ObjectListField from .types import * + class Query(ObjectType): """ Defines the queries available to this plugin via the graphql api. diff --git a/netbox_acls/graphql/types.py b/netbox_acls/graphql/types.py index 9e05942..f43774c 100644 --- a/netbox_acls/graphql/types.py +++ b/netbox_acls/graphql/types.py @@ -72,4 +72,3 @@ class ACLStandardRuleType(NetBoxObjectType): model = models.ACLStandardRule fields = "__all__" filterset_class = filtersets.ACLStandardRuleFilterSet - diff --git a/netbox_acls/migrations/0001_initial.py b/netbox_acls/migrations/0001_initial.py index 9a530ce..e41a675 100644 --- a/netbox_acls/migrations/0001_initial.py +++ b/netbox_acls/migrations/0001_initial.py @@ -282,7 +282,9 @@ class Migration(migrations.Migration): }, ), # migrations.AddConstraint( - # model_name='accesslist', - # constraint=models.UniqueConstraint(fields=('assigned_object_type', 'assigned_object_id'), name='accesslist_assigned_object'), + # model_name="accesslist", + # constraint=models.UniqueConstraint( + # fields=("assigned_object_type", "assigned_object_id"), name="accesslist_assigned_object" + # ), # ), ] diff --git a/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py b/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py index ea5ab86..902248f 100644 --- a/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py +++ b/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py @@ -6,7 +6,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ("contenttypes", "0002_remove_content_type_name"), ("netbox_acls", "0001_initial"), diff --git a/netbox_acls/migrations/0003_netbox_acls.py b/netbox_acls/migrations/0003_netbox_acls.py index 562e0f3..0af5aef 100644 --- a/netbox_acls/migrations/0003_netbox_acls.py +++ b/netbox_acls/migrations/0003_netbox_acls.py @@ -5,7 +5,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ("netbox_acls", "0002_alter_accesslist_options_and_more"), ] diff --git a/netbox_acls/tests/test_api.py b/netbox_acls/tests/test_api.py index 77559e6..207f1dd 100644 --- a/netbox_acls/tests/test_api.py +++ b/netbox_acls/tests/test_api.py @@ -1,4 +1,4 @@ -from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site +from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from django.contrib.contenttypes.models import ContentType from django.urls import reverse from rest_framework import status diff --git a/netbox_acls/urls.py b/netbox_acls/urls.py index 5c70579..d7624a1 100644 --- a/netbox_acls/urls.py +++ b/netbox_acls/urls.py @@ -47,7 +47,11 @@ urlpatterns = ( views.ACLInterfaceAssignmentEditView.as_view(), name="aclinterfaceassignment_add", ), - # path('interface-assignments/edit/', views.ACLInterfaceAssignmentBulkEditView.as_view(), name='aclinterfaceassignment_bulk_edit'), + # path( + # "interface-assignments/edit/", + # views.ACLInterfaceAssignmentBulkEditView.as_view(), + # name="aclinterfaceassignment_bulk_edit" + # ), path( "interface-assignments/delete/", views.ACLInterfaceAssignmentBulkDeleteView.as_view(), diff --git a/netbox_acls/version.py b/netbox_acls/version.py index bc86c94..67bc602 100644 --- a/netbox_acls/version.py +++ b/netbox_acls/version.py @@ -1 +1 @@ -__version__ = "1.2.2" +__version__ = "1.3.0" diff --git a/netbox_acls/views.py b/netbox_acls/views.py index d986945..9f1fa81 100644 --- a/netbox_acls/views.py +++ b/netbox_acls/views.py @@ -50,7 +50,8 @@ class AccessListView(generic.ObjectView): 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 == choices.ACLTypeChoices.TYPE_EXTENDED: @@ -227,8 +228,7 @@ class ACLInterfaceAssignmentEditView(generic.ObjectEditView): """ return { - "access_list": request.GET.get("access_list") - or request.POST.get("access_list"), + "access_list": request.GET.get("access_list") or request.POST.get("access_list"), "direction": request.GET.get("direction") or request.POST.get("direction"), } @@ -360,8 +360,7 @@ class ACLStandardRuleEditView(generic.ObjectEditView): """ return { - "access_list": request.GET.get("access_list") - or request.POST.get("access_list"), + "access_list": request.GET.get("access_list") or request.POST.get("access_list"), } @@ -443,8 +442,7 @@ class ACLExtendedRuleEditView(generic.ObjectEditView): """ return { - "access_list": request.GET.get("access_list") - or request.POST.get("access_list"), + "access_list": request.GET.get("access_list") or request.POST.get("access_list"), } diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ab061a4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ + +[tool.black] +line-length = 140 + +[tool.isort] +profile = "black" +include_trailing_comma = true +multi_line_output = 3 + +[tool.pylint] +max-line-length = 140 + +[tool.pyright] +include = ["netbox_secrets"] +exclude = [ + "**/node_modules", + "**/__pycache__", +] +reportMissingImports = true +reportMissingTypeStubs = false + +[tool.ruff] +line-length = 140 diff --git a/setup.py b/setup.py index 5059faa..d3b23d4 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ from setuptools import find_packages, setup script_dir = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(script_dir, "README.md"), encoding="utf-8") as fh: - long_description = fh.read() + long_description = fh.read().replace("(docs/img/", "(https://raw.githubusercontent.com/ryanmerolle/netbox-acls/release/docs/img/") def read(relative_path): @@ -43,7 +43,18 @@ setup( include_package_data=True, zip_safe=False, classifiers=[ - "Framework :: Django", + "Development Status :: 5 - Production/Stable", + "Natural Language :: English", + "Programming Language :: Python", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Intended Audience :: System Administrators", + "Intended Audience :: Telecommunications Industry", + "Framework :: Django", + "Topic :: System :: Networking", + "Topic :: Internet", ], )