From 605b7c5b3eead23d2a4531878dc64278d693fb12 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 25 Jun 2021 15:31:43 -0400 Subject: [PATCH] Add GraphQL for virtualization --- netbox/ipam/graphql/__init__.py | 11 ----- netbox/netbox/graphql/__init__.py | 11 +++++ netbox/netbox/graphql/schema.py | 2 + netbox/utilities/testing/api.py | 10 ++++- netbox/virtualization/graphql/__init__.py | 0 netbox/virtualization/graphql/schema.py | 21 ++++++++++ netbox/virtualization/graphql/types.py | 50 +++++++++++++++++++++++ netbox/virtualization/tests/test_api.py | 13 +++--- 8 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 netbox/virtualization/graphql/__init__.py create mode 100644 netbox/virtualization/graphql/schema.py create mode 100644 netbox/virtualization/graphql/types.py diff --git a/netbox/ipam/graphql/__init__.py b/netbox/ipam/graphql/__init__.py index d36399cc0..e69de29bb 100644 --- a/netbox/ipam/graphql/__init__.py +++ b/netbox/ipam/graphql/__init__.py @@ -1,11 +0,0 @@ -import graphene -from graphene_django.converter import convert_django_field - -from ipam.fields import IPAddressField, IPNetworkField - - -@convert_django_field.register(IPAddressField) -@convert_django_field.register(IPNetworkField) -def convert_field_to_string(field, registry=None): - # TODO: Update to use get_django_field_description under django_graphene v3.0 - return graphene.String(description=field.help_text, required=not field.null) diff --git a/netbox/netbox/graphql/__init__.py b/netbox/netbox/graphql/__init__.py index 6316a2390..069f6a9c8 100644 --- a/netbox/netbox/graphql/__init__.py +++ b/netbox/netbox/graphql/__init__.py @@ -2,6 +2,9 @@ import graphene from graphene_django.converter import convert_django_field from taggit.managers import TaggableManager +from dcim.fields import MACAddressField +from ipam.fields import IPAddressField, IPNetworkField + @convert_django_field.register(TaggableManager) def convert_field_to_tags_list(field, registry=None): @@ -9,3 +12,11 @@ def convert_field_to_tags_list(field, registry=None): Register conversion handler for django-taggit's TaggableManager """ return graphene.List(graphene.String) + + +@convert_django_field.register(IPAddressField) +@convert_django_field.register(IPNetworkField) +@convert_django_field.register(MACAddressField) +def convert_field_to_string(field, registry=None): + # TODO: Update to use get_django_field_description under django_graphene v3.0 + return graphene.String(description=field.help_text, required=not field.null) diff --git a/netbox/netbox/graphql/schema.py b/netbox/netbox/graphql/schema.py index dcb1107e1..da16ea58a 100644 --- a/netbox/netbox/graphql/schema.py +++ b/netbox/netbox/graphql/schema.py @@ -4,6 +4,7 @@ from circuits.graphql.schema import CircuitsQuery from extras.graphql.schema import ExtrasQuery from ipam.graphql.schema import IPAMQuery from tenancy.graphql.schema import TenancyQuery +from virtualization.graphql.schema import VirtualizationQuery class Query( @@ -11,6 +12,7 @@ class Query( ExtrasQuery, IPAMQuery, TenancyQuery, + VirtualizationQuery, graphene.ObjectType ): pass diff --git a/netbox/utilities/testing/api.py b/netbox/utilities/testing/api.py index eff5b9c05..2549492c4 100644 --- a/netbox/utilities/testing/api.py +++ b/netbox/utilities/testing/api.py @@ -425,10 +425,16 @@ class APIViewTestCases: class GraphQLTestCase(APITestCase): + def _get_graphql_base_name(self, plural=False): + if plural: + return getattr(self, 'graphql_base_name_plural', + self.model._meta.verbose_name_plural.lower().replace(' ', '_')) + return getattr(self, 'graphql_base_name', self.model._meta.verbose_name.lower().replace(' ', '_')) + @override_settings(LOGIN_REQUIRED=True) def test_graphql_get_object(self): url = reverse('graphql') - object_type = self.model._meta.verbose_name.lower().replace(' ', '_') + object_type = self._get_graphql_base_name() object_id = self._get_queryset().first().pk query = f""" {{ @@ -459,7 +465,7 @@ class APIViewTestCases: @override_settings(LOGIN_REQUIRED=True) def test_graphql_list_objects(self): url = reverse('graphql') - object_type = self.model._meta.verbose_name_plural.lower().replace(' ', '_') + object_type = self._get_graphql_base_name(plural=True) query = f""" {{ {object_type} {{ diff --git a/netbox/virtualization/graphql/__init__.py b/netbox/virtualization/graphql/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/netbox/virtualization/graphql/schema.py b/netbox/virtualization/graphql/schema.py new file mode 100644 index 000000000..f7d9528f0 --- /dev/null +++ b/netbox/virtualization/graphql/schema.py @@ -0,0 +1,21 @@ +import graphene + +from netbox.graphql.fields import ObjectField, ObjectListField +from .types import * + + +class VirtualizationQuery(graphene.ObjectType): + cluster = ObjectField(ClusterType) + clusters = ObjectListField(ClusterType) + + cluster_group = ObjectField(ClusterGroupType) + cluster_groups = ObjectListField(ClusterGroupType) + + cluster_type = ObjectField(ClusterTypeType) + cluster_types = ObjectListField(ClusterTypeType) + + virtual_machine = ObjectField(VirtualMachineType) + virtual_machines = ObjectListField(VirtualMachineType) + + vm_interface = ObjectField(VMInterfaceType) + vm_interfaces = ObjectListField(VMInterfaceType) diff --git a/netbox/virtualization/graphql/types.py b/netbox/virtualization/graphql/types.py new file mode 100644 index 000000000..d7b6d344b --- /dev/null +++ b/netbox/virtualization/graphql/types.py @@ -0,0 +1,50 @@ +from virtualization import filtersets, models +from netbox.graphql.types import ObjectType, TaggedObjectType + +__all__ = ( + 'ClusterType', + 'ClusterGroupType', + 'ClusterTypeType', + 'VirtualMachineType', + 'VMInterfaceType', +) + + +class ClusterType(TaggedObjectType): + + class Meta: + model = models.Cluster + fields = '__all__' + filterset_class = filtersets.ClusterFilterSet + + +class ClusterGroupType(ObjectType): + + class Meta: + model = models.ClusterGroup + fields = '__all__' + filterset_class = filtersets.ClusterGroupFilterSet + + +class ClusterTypeType(ObjectType): + + class Meta: + model = models.ClusterType + fields = '__all__' + filterset_class = filtersets.ClusterTypeFilterSet + + +class VirtualMachineType(TaggedObjectType): + + class Meta: + model = models.VirtualMachine + fields = '__all__' + filterset_class = filtersets.VirtualMachineFilterSet + + +class VMInterfaceType(ObjectType): + + class Meta: + model = models.VMInterface + fields = '__all__' + filterset_class = filtersets.VMInterfaceFilterSet diff --git a/netbox/virtualization/tests/test_api.py b/netbox/virtualization/tests/test_api.py index bcf3195f2..1712e93b2 100644 --- a/netbox/virtualization/tests/test_api.py +++ b/netbox/virtualization/tests/test_api.py @@ -17,7 +17,7 @@ class AppTest(APITestCase): self.assertEqual(response.status_code, 200) -class ClusterTypeTest(APIViewTestCases.APIViewTestCase): +class ClusterTypeTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIViewTestCase): model = ClusterType brief_fields = ['cluster_count', 'display', 'id', 'name', 'slug', 'url'] create_data = [ @@ -49,7 +49,7 @@ class ClusterTypeTest(APIViewTestCases.APIViewTestCase): ClusterType.objects.bulk_create(cluster_types) -class ClusterGroupTest(APIViewTestCases.APIViewTestCase): +class ClusterGroupTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIViewTestCase): model = ClusterGroup brief_fields = ['cluster_count', 'display', 'id', 'name', 'slug', 'url'] create_data = [ @@ -81,7 +81,7 @@ class ClusterGroupTest(APIViewTestCases.APIViewTestCase): ClusterGroup.objects.bulk_create(cluster_Groups) -class ClusterTest(APIViewTestCases.APIViewTestCase): +class ClusterTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIViewTestCase): model = Cluster brief_fields = ['display', 'id', 'name', 'url', 'virtualmachine_count'] bulk_update_data = { @@ -129,7 +129,7 @@ class ClusterTest(APIViewTestCases.APIViewTestCase): ] -class VirtualMachineTest(APIViewTestCases.APIViewTestCase): +class VirtualMachineTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIViewTestCase): model = VirtualMachine brief_fields = ['display', 'id', 'name', 'url'] bulk_update_data = { @@ -205,13 +205,16 @@ class VirtualMachineTest(APIViewTestCases.APIViewTestCase): self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) -class VMInterfaceTest(APIViewTestCases.APIViewTestCase): +class VMInterfaceTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIViewTestCase): model = VMInterface brief_fields = ['display', 'id', 'name', 'url', 'virtual_machine'] bulk_update_data = { 'description': 'New description', } + graphql_base_name = 'vm_interface' + graphql_base_name_plural = 'vm_interfaces' + @classmethod def setUpTestData(cls):