From c09aab73a64cb27da08bec46443fbd51e1e9b069 Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Wed, 5 Jun 2024 23:32:23 +0100 Subject: [PATCH 1/7] Initial 4.0 support --- Dockerfile | 2 +- README.md | 1 + netbox_acls/__init__.py | 6 +++--- netbox_acls/navigation.py | 8 ++------ netbox_acls/version.py | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 43a2c3e..8616db2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG NETBOX_VARIANT=v3.7 +ARG NETBOX_VARIANT=v4.0 FROM netboxcommunity/netbox:${NETBOX_VARIANT} diff --git a/README.md b/README.md index 5f2a8ac..348d71e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Each Plugin Version listed below has been tested with its corresponding NetBox V | NetBox Version | Plugin Version | |:--------------:|:--------------:| +| > 4.0.2 | 1.6.0 | | 3.7 | 1.5.0 | | 3.6 | 1.4.0 | | 3.5 | 1.3.0 | diff --git a/netbox_acls/__init__.py b/netbox_acls/__init__.py index 584592f..6e81b98 100644 --- a/netbox_acls/__init__.py +++ b/netbox_acls/__init__.py @@ -2,7 +2,7 @@ Define the NetBox Plugin """ -from extras.plugins import PluginConfig +from netbox.plugins import PluginConfig from .version import __version__ @@ -17,8 +17,8 @@ class NetBoxACLsConfig(PluginConfig): version = __version__ description = "Manage simple ACLs in NetBox" base_url = "access-lists" - min_version = "3.7.0" - max_version = "3.7.99" + min_version = "4.0.2" + max_version = "4.0.99" config = NetBoxACLsConfig diff --git a/netbox_acls/navigation.py b/netbox_acls/navigation.py index 9790365..433e824 100644 --- a/netbox_acls/navigation.py +++ b/netbox_acls/navigation.py @@ -3,8 +3,8 @@ """ from django.conf import settings -from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem -from utilities.choices import ButtonColorChoices +from netbox.plugins import PluginMenu, PluginMenuButton, PluginMenuItem + plugin_settings = settings.PLUGINS_CONFIG["netbox_acls"] @@ -21,7 +21,6 @@ link="plugins:netbox_acls:accesslist_add", title="Add", icon_class="mdi mdi-plus-thick", - color=ButtonColorChoices.GREEN, permissions=["netbox_acls.add_accesslist"], ), ), @@ -35,7 +34,6 @@ link="plugins:netbox_acls:aclstandardrule_add", title="Add", icon_class="mdi mdi-plus-thick", - color=ButtonColorChoices.GREEN, permissions=["netbox_acls.add_aclstandardrule"], ), ), @@ -49,7 +47,6 @@ link="plugins:netbox_acls:aclextendedrule_add", title="Add", icon_class="mdi mdi-plus-thick", - color=ButtonColorChoices.GREEN, permissions=["netbox_acls.add_aclextendedrule"], ), ), @@ -63,7 +60,6 @@ link="plugins:netbox_acls:aclinterfaceassignment_add", title="Add", icon_class="mdi mdi-plus-thick", - color=ButtonColorChoices.GREEN, permissions=["netbox_acls.add_aclinterfaceassignment"], ), ), diff --git a/netbox_acls/version.py b/netbox_acls/version.py index c179ed2..df44d33 100644 --- a/netbox_acls/version.py +++ b/netbox_acls/version.py @@ -1 +1 @@ -__version__ = "1.5.0" \ No newline at end of file +__version__ = "1.6.0" \ No newline at end of file From 4256a4e787f0522fe5d6a9575b003f65512eea5e Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Wed, 5 Jun 2024 23:37:15 +0100 Subject: [PATCH 2/7] Minor corrections --- README.md | 2 +- setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 348d71e..7460aaf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Each Plugin Version listed below has been tested with its corresponding NetBox V | NetBox Version | Plugin Version | |:--------------:|:--------------:| -| > 4.0.2 | 1.6.0 | +| >= 4.0.2 | 1.6.0 | | 3.7 | 1.5.0 | | 3.6 | 1.4.0 | | 3.5 | 1.3.0 | diff --git a/setup.py b/setup.py index 030dece..2ac195b 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ 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().replace("(docs/img/", "(https://raw.githubusercontent.com/ryanmerolle/netbox-acls/release/docs/img/") + long_description = fh.read().replace("(docs/img/", "(https://raw.githubusercontent.com/netbox-community/netbox-acls/release/docs/img/") def read(relative_path): @@ -37,7 +37,7 @@ def get_version(relative_path): description="A NetBox plugin for Access List management", long_description=long_description, long_description_content_type="text/markdown", - url="https://github.com/ryanmerolle/netbox-acls", + url="https://github.com/netbox-community/netbox-acls", license="Apache 2.0", install_requires=[], python_requires=">=3.10", @@ -61,7 +61,7 @@ def get_version(relative_path): "Topic :: Internet", ], project_urls={ - "Issues": "https://github.com/ryanmerolle/netbox-acls/issues", - "Source": "https://github.com/ryanmerolle/netbox-acls", + "Issues": "https://github.com/netbox-community/netbox-acls/issues", + "Source": "https://github.com/netbox-community/netbox-acls", }, ) From 57c1912a5594e51c95bf5405ac29d9f071ea2e04 Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Fri, 7 Jun 2024 13:02:19 +0100 Subject: [PATCH 3/7] Fix tests device_role > role --- netbox_acls/tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_acls/tests/test_api.py b/netbox_acls/tests/test_api.py index 207f1dd..7d077f7 100644 --- a/netbox_acls/tests/test_api.py +++ b/netbox_acls/tests/test_api.py @@ -44,7 +44,7 @@ def setUpTestData(cls): name="Device 1", site=site, device_type=devicetype, - device_role=devicerole, + role=devicerole, ) access_lists = ( From c89779833b943a5c6a5db5d8e97247d2815db338 Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Fri, 7 Jun 2024 14:42:22 +0100 Subject: [PATCH 4/7] graphql fixes --- netbox_acls/CODEOWNERS | 1 + netbox_acls/graphql/__init__.py | 5 +++ netbox_acls/graphql/filters.py | 30 +++++++++++++ netbox_acls/graphql/schema.py | 30 +++++++------ netbox_acls/graphql/types.py | 77 ++++++++++++++++++++------------- 5 files changed, 100 insertions(+), 43 deletions(-) create mode 100644 netbox_acls/CODEOWNERS create mode 100644 netbox_acls/graphql/filters.py diff --git a/netbox_acls/CODEOWNERS b/netbox_acls/CODEOWNERS new file mode 100644 index 0000000..f6c3d1c --- /dev/null +++ b/netbox_acls/CODEOWNERS @@ -0,0 +1 @@ +* @ryanmerolle @abhi1693 @cruse1977 @natm \ No newline at end of file diff --git a/netbox_acls/graphql/__init__.py b/netbox_acls/graphql/__init__.py index dd2a695..3d07b46 100644 --- a/netbox_acls/graphql/__init__.py +++ b/netbox_acls/graphql/__init__.py @@ -1,2 +1,7 @@ from .schema import * from .types import * + +schema = [ + schema.ACLQuery +] + diff --git a/netbox_acls/graphql/filters.py b/netbox_acls/graphql/filters.py new file mode 100644 index 0000000..1a2e97f --- /dev/null +++ b/netbox_acls/graphql/filters.py @@ -0,0 +1,30 @@ +import strawberry_django +from .. import filtersets, models +from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin + +__all__ = ( + 'AccessListFilter', + 'ACLInterfaceAssignmentFilter', + 'ACLExtendedRuleFilter', + 'ACLStandardRuleFilter', +) + +@strawberry_django.filter(models.AccessList, lookups=True) +@autotype_decorator(filtersets.AccessListFilterSet) +class AccessListFilter(BaseFilterMixin): + pass + +@strawberry_django.filter(models.ACLStandardRule, lookups=True) +@autotype_decorator(filtersets.ACLStandardRuleFilterSet) +class ACLStandardRuleFilter(BaseFilterMixin): + pass + +@strawberry_django.filter(models.ACLExtendedRule, lookups=True) +@autotype_decorator(filtersets.ACLExtendedRuleFilterSet) +class ACLExtendedRuleFilter(BaseFilterMixin): + pass + +@strawberry_django.filter(models.ACLInterfaceAssignment, lookups=True) +@autotype_decorator(filtersets.ACLInterfaceAssignmentFilterSet) +class ACLInterfaceAssignmentFilter(BaseFilterMixin): + pass \ No newline at end of file diff --git a/netbox_acls/graphql/schema.py b/netbox_acls/graphql/schema.py index 0dc2dd2..6e316fb 100644 --- a/netbox_acls/graphql/schema.py +++ b/netbox_acls/graphql/schema.py @@ -1,22 +1,26 @@ -from graphene import ObjectType -from netbox.graphql.fields import ObjectField, ObjectListField - +import strawberry +import strawberry_django from .types import * +from ..models import * - -class Query(ObjectType): +@strawberry.type +class ACLQuery: """ Defines the queries available to this plugin via the graphql api. """ + @strawberry.field + def access_list(self, id: int) -> AccessListType: + return AccessList.objects.get(pk=id) + access_list_list: list[AccessListType] = strawberry_django.field() - access_list = ObjectField(AccessListType) - access_list_list = ObjectListField(AccessListType) - - acl_extended_rule = ObjectField(ACLExtendedRuleType) - acl_extended_rule_list = ObjectListField(ACLExtendedRuleType) + @strawberry.field + def acl_extended_rule(self, id: int) -> ACLExtendedRuleType: + return ACLExtendedRule.objects.get(pk=id) + acl_extended_rule_list: list[ACLExtendedRuleType] = strawberry_django.field() - acl_standard_rule = ObjectField(ACLStandardRuleType) - acl_standard_rule_list = ObjectListField(ACLStandardRuleType) + @strawberry.field + def acl_standard_rule(self, id: int) -> ACLStandardRuleType: + return ACLStandardRule.objects.get(pk=id) + acl_standard_rule_list: list[ACLStandardRuleType] = strawberry_django.field() -schema = Query diff --git a/netbox_acls/graphql/types.py b/netbox_acls/graphql/types.py index f43774c..0b7a8e4 100644 --- a/netbox_acls/graphql/types.py +++ b/netbox_acls/graphql/types.py @@ -2,19 +2,22 @@ Define the object types and queries availble via the graphql api. """ -from netbox.graphql.types import NetBoxObjectType +import strawberry +import strawberry_django -from .. import filtersets, models -__all__ = ( - "AccessListType", - "ACLInterfaceAssignmentType", - "ACLExtendedRuleType", - "ACLStandardRuleType", -) +from typing import Annotated, List +from .filters import * +from .. import models +from netbox.graphql.types import OrganizationalObjectType +@strawberry_django.type( + models.AccessList, + fields='__all__', + filters=AccessListFilter +) -class AccessListType(NetBoxObjectType): +class AccessListType(OrganizationalObjectType): """ Defines the object type for the django model AccessList. """ @@ -23,13 +26,16 @@ class Meta: """ Associates the filterset, fields, and model for the django model AccessList. """ - - model = models.AccessList - fields = "__all__" - filterset_class = filtersets.AccessListFilterSet - - -class ACLInterfaceAssignmentType(NetBoxObjectType): + @strawberry_django.field + def accesslists(self) -> List[Annotated["AccessList", strawberry.lazy('accesslists.graphql.types')]]: + return self.accesslists.all() + +@strawberry_django.type( + models.ACLInterfaceAssignment, + fields='__all__', + filters=ACLInterfaceAssignmentFilter +) +class ACLInterfaceAssignmentType(OrganizationalObjectType): """ Defines the object type for the django model AccessList. """ @@ -38,37 +44,48 @@ class Meta: """ Associates the filterset, fields, and model for the django model ACLInterfaceAssignment. """ + @strawberry_django.field + def aclinterfaceassignments(self) -> List[Annotated["ACLInterfaceAssignment", strawberry.lazy('aclinterfaceassignments.graphql.types')]]: + return self.aclinterfaceassignments.all() + +@strawberry_django.type( + models.ACLExtendedRule, + fields='__all__', + filters=ACLExtendedRuleFilter +) - model = models.ACLInterfaceAssignment - fields = "__all__" - filterset_class = filtersets.ACLInterfaceAssignmentFilterSet - - -class ACLExtendedRuleType(NetBoxObjectType): +class ACLExtendedRuleType(OrganizationalObjectType): """ Defines the object type for the django model ACLExtendedRule. """ + source_ports: List[int] + destination_ports: List[int] class Meta: """ Associates the filterset, fields, and model for the django model ACLExtendedRule. """ + @strawberry_django.field + def aclextendedrules(self) -> List[Annotated["ACLExtendedRule", strawberry.lazy('aclextendedrule.graphql.types')]]: + return self.aclextendedrules.all() - model = models.ACLExtendedRule - fields = "__all__" - filterset_class = filtersets.ACLExtendedRuleFilterSet +@strawberry_django.type( + models.ACLStandardRule, + fields='__all__', + filters=ACLStandardRuleFilter +) -class ACLStandardRuleType(NetBoxObjectType): +class ACLStandardRuleType(OrganizationalObjectType): """ Defines the object type for the django model ACLStandardRule. """ class Meta: """ - Associates the filterset, fields, and model for the django model ACLStandardRule. + Associates the filterset, fields, and model for the django model ACLExtendedRule. """ + @strawberry_django.field + def aclstandardrules(self) -> List[Annotated["ACLStandardRule", strawberry.lazy('aclstandardrule.graphql.types')]]: + return self.aclstandardrules.all() - model = models.ACLStandardRule - fields = "__all__" - filterset_class = filtersets.ACLStandardRuleFilterSet From 74f879fabbbbfe1aaffa687c90e06ccac84212e7 Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Fri, 7 Jun 2024 16:05:18 +0100 Subject: [PATCH 5/7] graphql fixups --- netbox_acls/api/serializers.py | 7 +++++-- netbox_acls/graphql/__init__.py | 4 +++- netbox_acls/graphql/schema.py | 8 +++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/netbox_acls/api/serializers.py b/netbox_acls/api/serializers.py index d79a62d..3715599 100644 --- a/netbox_acls/api/serializers.py +++ b/netbox_acls/api/serializers.py @@ -75,6 +75,7 @@ class Meta: "last_updated", "rule_count", ) + brief_fields = ("id", "url", "name", "display") @extend_schema_field(serializers.DictField()) def get_assigned_object(self, obj): @@ -139,6 +140,7 @@ class Meta: "created", "last_updated", ) + brief_fields = ("id", "url", "access_list") @extend_schema_field(serializers.DictField()) def get_assigned_object(self, obj): @@ -212,6 +214,7 @@ class Meta: "last_updated", "source_prefix", ) + brief_fields = ("id", "url", "display") def validate(self, data): """ @@ -284,7 +287,7 @@ class Meta: "protocol", "remark", ) - + brief_fields = ("id", "url", "display") def validate(self, data): """ Validate the ACLExtendedRule django model's inputs before allowing it to update the instance: @@ -328,7 +331,7 @@ def validate(self, data): if data.get("protocol"): error_message["protocol"] = [ "Action is set to remark, Protocol CANNOT be set.", - ] + ] if error_message: raise serializers.ValidationError(error_message) diff --git a/netbox_acls/graphql/__init__.py b/netbox_acls/graphql/__init__.py index 3d07b46..f778a80 100644 --- a/netbox_acls/graphql/__init__.py +++ b/netbox_acls/graphql/__init__.py @@ -2,6 +2,8 @@ from .types import * schema = [ - schema.ACLQuery + schema.NetBoxACLSAccessListQuery, + schema.NetBoxACLSStandardRuleQuery, + schema.NetBoxACLSACLExtendedRuleQuery ] diff --git a/netbox_acls/graphql/schema.py b/netbox_acls/graphql/schema.py index 6e316fb..94b707d 100644 --- a/netbox_acls/graphql/schema.py +++ b/netbox_acls/graphql/schema.py @@ -4,7 +4,7 @@ from ..models import * @strawberry.type -class ACLQuery: +class NetBoxACLSAccessListQuery: """ Defines the queries available to this plugin via the graphql api. """ @@ -13,11 +13,17 @@ def access_list(self, id: int) -> AccessListType: return AccessList.objects.get(pk=id) access_list_list: list[AccessListType] = strawberry_django.field() +@strawberry.type +class NetBoxACLSACLExtendedRuleQuery: @strawberry.field def acl_extended_rule(self, id: int) -> ACLExtendedRuleType: return ACLExtendedRule.objects.get(pk=id) acl_extended_rule_list: list[ACLExtendedRuleType] = strawberry_django.field() + + +@strawberry.type +class NetBoxACLSStandardRuleQuery: @strawberry.field def acl_standard_rule(self, id: int) -> ACLStandardRuleType: return ACLStandardRule.objects.get(pk=id) From dda4127a991eef0de869b668230014aa3d1cfd86 Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Fri, 7 Jun 2024 16:18:56 +0100 Subject: [PATCH 6/7] more graphql fixes --- netbox_acls/graphql/types.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/netbox_acls/graphql/types.py b/netbox_acls/graphql/types.py index 0b7a8e4..21a9f7a 100644 --- a/netbox_acls/graphql/types.py +++ b/netbox_acls/graphql/types.py @@ -39,7 +39,8 @@ class ACLInterfaceAssignmentType(OrganizationalObjectType): """ Defines the object type for the django model AccessList. """ - + access_list: Annotated["AccessListType", strawberry.lazy("netbox_acls.graphql.types")] + class Meta: """ Associates the filterset, fields, and model for the django model ACLInterfaceAssignment. @@ -60,6 +61,9 @@ class ACLExtendedRuleType(OrganizationalObjectType): """ source_ports: List[int] destination_ports: List[int] + access_list: Annotated["AccessListType", strawberry.lazy("netbox_acls.graphql.types")] + destination_prefix: Annotated["PrefixType", strawberry.lazy("ipam.graphql.types")] + source_prefix: Annotated["PrefixType", strawberry.lazy("ipam.graphql.types")] class Meta: """ @@ -80,6 +84,8 @@ class ACLStandardRuleType(OrganizationalObjectType): """ Defines the object type for the django model ACLStandardRule. """ + access_list: Annotated["AccessListType", strawberry.lazy("netbox_acls.graphql.types")] + source_prefix: Annotated["PrefixType", strawberry.lazy("ipam.graphql.types")] class Meta: """ From f15248afbe17652f7b95346c27ea8d3caf9354db Mon Sep 17 00:00:00 2001 From: Chris Russell Date: Fri, 7 Jun 2024 16:41:16 +0100 Subject: [PATCH 7/7] further graphql fixes --- netbox_acls/graphql/types.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/netbox_acls/graphql/types.py b/netbox_acls/graphql/types.py index 21a9f7a..2cc4d21 100644 --- a/netbox_acls/graphql/types.py +++ b/netbox_acls/graphql/types.py @@ -6,7 +6,7 @@ import strawberry_django -from typing import Annotated, List +from typing import Annotated, List, Union from .filters import * from .. import models from netbox.graphql.types import OrganizationalObjectType @@ -14,13 +14,20 @@ @strawberry_django.type( models.AccessList, fields='__all__', - filters=AccessListFilter + filters=AccessListFilter, + exclude=('assigned_object_type', 'assigned_object_id') ) class AccessListType(OrganizationalObjectType): """ Defines the object type for the django model AccessList. """ + assigned_object_type: Annotated["ContentTypeType", strawberry.lazy("netbox.graphql.types")] + assigned_object: Annotated[Union[ + Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')], + Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')], + ], strawberry.union("ACLAssignmentType")] + class Meta: """ @@ -33,6 +40,7 @@ def accesslists(self) -> List[Annotated["AccessList", strawberry.lazy('accesslis @strawberry_django.type( models.ACLInterfaceAssignment, fields='__all__', + exclude=('assigned_object_type', 'assigned_object_id'), filters=ACLInterfaceAssignmentFilter ) class ACLInterfaceAssignmentType(OrganizationalObjectType): @@ -40,7 +48,15 @@ class ACLInterfaceAssignmentType(OrganizationalObjectType): Defines the object type for the django model AccessList. """ access_list: Annotated["AccessListType", strawberry.lazy("netbox_acls.graphql.types")] + assigned_object_type: Annotated["ContentTypeType", strawberry.lazy("netbox.graphql.types")] + assigned_object: Annotated[Union[ + Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], + Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')], + ], strawberry.union("ACLInterfaceAssignmentType")] + + + class Meta: """ Associates the filterset, fields, and model for the django model ACLInterfaceAssignment.