├── .dockerignore ├── .gitignore ├── .travis.yml ├── Dockerfile ├── EXAMPLES.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── VERSION ├── docker-compose.yml ├── docker ├── settings.py └── urls.py ├── netbox.env ├── netbox_graphql ├── __init__.py ├── circuits_schema.py ├── custom_filter_fields.py ├── dcim_schema.py ├── helper_methods.py ├── ipam_schema.py ├── schema.py ├── tenancy_schema.py ├── tests │ ├── __init__.py │ ├── circuits │ │ ├── __init__.py │ │ ├── tests_circuits.py │ │ ├── tests_providers.py │ │ ├── tests_terminations.py │ │ └── tests_types.py │ ├── dcim │ │ ├── __init__.py │ │ ├── tests_regions.py │ │ └── tests_sites.py │ ├── factories │ │ ├── __init__.py │ │ ├── circuit_factories.py │ │ ├── dcim_factories.py │ │ ├── ipam_factories.py │ │ ├── tenant_factories.py │ │ └── virtualization_factories.py │ ├── ipam │ │ ├── __init__.py │ │ ├── tests_aggregates.py │ │ ├── tests_ip_addresses.py │ │ ├── tests_prefixes.py │ │ ├── tests_rirs.py │ │ ├── tests_roles.py │ │ ├── tests_vlan_groups.py │ │ ├── tests_vlans.py │ │ └── tests_vrfs.py │ ├── tenancy │ │ ├── __init__.py │ │ ├── tests_groups.py │ │ └── tests_tenants.py │ ├── utils.py │ └── virtualization │ │ ├── __init__.py │ │ ├── tests_cluster_groups.py │ │ ├── tests_cluster_types.py │ │ ├── tests_clusters.py │ │ └── tests_virtual_machines.py ├── urls.py └── virtualization_schema.py ├── setup.cfg └── setup.py /.dockerignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | /.git/ 104 | 105 | */*.pyc 106 | 107 | /netbox_graphql/tests/snapshots/ 108 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | *.pyc 103 | 104 | # snaptests output 105 | snapshots/ 106 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: python 3 | 4 | services: 5 | - docker 6 | 7 | install: 8 | - docker-compose build 9 | 10 | script: 11 | - docker-compose run netbox ./manage.py test 12 | 13 | after_script: 14 | - docker-compose down 15 | 16 | deploy: 17 | provider: pypi 18 | user: "${PYPI_USERNAME}" 19 | password: "${PYPI_PASSWORD}" 20 | on: 21 | tags: true 22 | 23 | notifications: 24 | slack: 25 | secure: dj82ihmXsHHaG9tI6uBDZBFNLH2Ira1OVeCAfBPjdSWXcPQhWOweFX2/0PhDCorOc2feZUoDypWaCWqawPJFLFWqiCgoGxrTbbZsOJYHE9XzVnT3YDl7vGqQwunsn35yZe/7tGG+qPV1Am9/HRPfbg5MUqmNsJHqRTFuLj+qsGhXjbVa2FI5T2Tb/zSp6eC9nBz7cMzXW5lEwzAiB3eMZnL/qvsB07ftpcwaqGksy8zzk0KK6XDf7+94p8q1V5850VwQb78DZQw/KCjdAXkw0dwN9J9KOiPmB9r1Gb1cZIB9xeR/FDbomIu84iA6ZdGQqIG/2TI9hDQalRw+cRcJwqD/JVQziPZxFeVRg6DeonA8Q43CR9TtTYIglqQPzSrHWuZoFS099ixam9/OrxRX90tvRW/GqFSYmP1OxhE0F6ZOxsprVAY1w6FyP0KRTOLdYprNwl31v36Dy2ARuC9wgLLeEQbexH2GWWz8hnW66kNZBYoYy/JBCwnaMveDnAp8DfhcykGNw2xlAMMvBH89nmuxOEvdsSRDriZDEF99MJw/uoS4/LdP4/7P8hA+27tFHxVy8rMGtK/lE4TYvLuLCqoZ/0CZx5XhiSNCIjY5G6IlqTDbxI9jnqNoYy01uwA+vKXP1ixH8Ltlc8K1TtXicfY5JlP+0vETH+BQrT5rmtI= 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ninech/netbox 2 | 3 | COPY . /opt/netbox-graphql 4 | RUN pip install /opt/netbox-graphql[test] 5 | 6 | COPY docker /tmp/ 7 | RUN cat /tmp/settings.py >> /opt/netbox/netbox/netbox/settings.py && \ 8 | cat /tmp/urls.py >> /opt/netbox/netbox/netbox/urls.py && \ 9 | ln -s /opt/netbox-graphql/netbox_graphql /opt/netbox/netbox/netbox_graphql 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 The Python Packaging Authority (PyPA) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | recursive-include docs * -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | django-netbox-graphql 3 | ===== 4 | 5 | Netbox-Graphql is a simple Django app which provides a GraphQL API for Netbox. 6 | This module is dockerized and **development of it is still in progress**. Netbox's circuit module with all it's models are covered. 7 | For this part of app you can CRUD operations. 8 | 9 | Available Models for CRUD 10 | ------------------------ 11 | * CIRCUITS 12 | * Provider 13 | * Circuit 14 | * CircuitType 15 | * CircuitTermination 16 | * DCIM 17 | * Region 18 | * Site 19 | * TENANCY 20 | * TenantGroup 21 | * Tenant 22 | * IPAM 23 | * Role 24 | * VlanGroup 25 | * VLAN 26 | * VRF 27 | * RIR 28 | * Aggregate 29 | * Prefix 30 | * VIRTUALIZATION 31 | * ClusterType 32 | * ClusterGroup 33 | * Cluster 34 | * VirtualMachine 35 | 36 | 37 | Build package (optional) 38 | ------------------------ 39 | 40 | | git clone https://github.com/ninech/django-netbox-graphql 41 | | cd django-netbox-graphql 42 | | python setup.py sdist 43 | 44 | This module relies on modules 45 | ----------------------------- 46 | | graphene-django>=1.0 47 | | django-filter>=1.0.2 48 | 49 | Quick start 50 | ----------- 51 | 52 | 1. Install module:: 53 | 54 | pip install django-netbox-graphql #from external storage, not yet deployed 55 | or 56 | pip install dist/django-netbox-graphql-0.0.x.tar.gz 57 | 58 | 2. Add below modules to your INSTALLED_APPS setting like this:: 59 | 60 | INSTALLED_APPS = [ 61 | ... 62 | 'graphene_django', 63 | 'netbox_graphql', 64 | ] 65 | 66 | 3. Add graphene settings to netbox/setting.py:: 67 | 68 | GRAPHIQL_ENABLED = True # optional, by default True, set False to disable it 69 | GRAPHENE = { 70 | 'SCHEMA' : 'netbox_graphql.schema.schema', #points to the netbox-graphql schema variable in schema.py 71 | 'SCHEMA_INDENT': 2, #defines the indentation space in the output 72 | } 73 | 74 | 4. Include the polls URLconf in your project netbox/urls.py like this:: 75 | 76 | url(r'^graphql', include('netbox_graphql.urls')), 77 | 78 | 5. Visit http://127.0.0.1:8000/graphql to fetch records with graphql:: 79 | 80 | curl -H 'Content-Type: application/json'\ 81 | -H "Authorization: Token "\ 82 | -XPOST -d '{"query":"{ circuitTypes { edges { node { id name slug } } } }"}' http://localhost:8000/graphql 83 | 84 | Visit http://localhost:8000/user/api-tokens/ to generate token 85 | 86 | Graphql CRUD examples 87 | --------------------- 88 | 89 | Create:: 90 | 91 | curl -H 'Content-Type: application/json'\ 92 | -H "Authorization: Token "\ 93 | -XPOST -d '{"query":"mutation { newCircuitType(input: {name: \"Type1\", slug: \"type1\"}) { circuitType { id name slug } } }"}' http://localhost:8000/graphql 94 | 95 | {"data":{"newCircuitType":{"circuitType":{"id":"Q2lyY3VpdFR5cGVOb2RlOjI1","name":"Type1","slug":"type1"}}}} 96 | Read:: 97 | 98 | curl -H 'Content-Type: application/json'\ 99 | -H "Authorization: Token "\ 100 | -XPOST -d '{"query":"{ circuitTypes(id: \"\") { edges { node { id name slug } } } }"}' http://localhost:8000/graphql 101 | 102 | {"data":{"circuitTypes":{"edges":[{"node":{"id":"Q2lyY3VpdFR5cGVOb2RlOjI0","name":"Type","slug":"type"}}]}}} 103 | Update:: 104 | 105 | curl -H 'Content-Type: application/json'\ 106 | -H "Authorization: Token "\ 107 | -XPOST -d '{"query":"mutation { updateCircuitType(input: {id:\"\", name: \"TypeX\", slug: \"typeX\"}) { circuitType { slug name slug } } }"}' http://localhost:8000/graphql 108 | 109 | {"data":{"updateCircuitType":{"circuitType":{"id":"Q2lyY3VpdFR5cGVOb2RlOjI0","name":"TypeX","slug":"typeX"}}}} 110 | 111 | Delete:: 112 | 113 | curl -H 'Content-Type: application/json'\ 114 | -H "Authorization: Token "\ 115 | -XPOST -d '{"query":"mutation { deleteCircuitType(input: {id:\"\"}) { circuitType { name slug } } }"}' http://localhost:8000/graphql 116 | 117 | {"data":{"deleteCircuitType":{"circuitType":{"name":"TypeX","slug":"typeX"}}}} 118 | 119 | Graphql editor for writing queries 120 | ---------------------------------- 121 | 122 | 1. You should have installed `graphene_django`:: 123 | 124 | INSTALLED_APPS = [ 125 | ... 126 | 'graphene_django', 127 | ] 128 | 129 | 2. Create url for graphql client with adding new link in `urls.py` :: 130 | 131 | url(r'^graphql/client', GraphQLView.as_view(graphiql=True)), 132 | 133 | 3. Visit http://127.0.0.1:8000/graphql/client :: 134 | 135 | .. image:: https://s11.postimg.org/5vi9lmn1f/django-netbox-graphql.png 136 | 137 | Examples for module Circuit 138 | --------------------------- 139 | 140 | All examples are available `here `_ 141 | 142 | Packaging and deploying to pypi.python.org 143 | ----------------------------------------------- 144 | The simplest way to make package and deploy it is with using `twine`:: 145 | 146 | pip install twine # install twine 147 | python setup.py sdist # build django-netbox-graphql-X.X.X.tar.gz 148 | twine upload dist/django-netbox-graphql-X.X.X.tar.gz 149 | 150 | 151 | Tests 152 | ----- 153 | Run unit tests:: 154 | 155 | docker-compose run netbox ./manage.py test # runs all tests 156 | docker-compose run netbox ./manage.py test netbox_graphql/ # runs only netbox_graphql module tests 157 | 158 | # At the end, you can stop any running service and cleanup as follows: 159 | docker-compose down 160 | 161 | PYPI Distribution 162 | ----------------- 163 | 164 | Can be found at https://pypi.python.org/pypi?:action=display&name=django-netbox-graphql 165 | 166 | About 167 | ----- 168 | This module was developed and funded by `nine `_ 169 | 170 | .. image:: https://logo.apps.at-nine.ch/Dmqied_eSaoBMQwk3vVgn4UIgDo=/trim/500x0/logo_claim.png 171 | :target: https://nine.ch 172 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.4 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | netbox: 4 | build: 5 | context: . 6 | image: ninech/netbox-graphql 7 | depends_on: 8 | - postgres 9 | env_file: netbox.env 10 | volumes: 11 | - .:/opt/netbox-graphql 12 | - netbox-nginx-config:/etc/netbox-nginx/ 13 | - netbox-static-files:/opt/netbox/netbox/static 14 | nginx: 15 | image: nginx:1.11-alpine 16 | command: nginx -g 'daemon off;' -c /etc/netbox-nginx/nginx.conf 17 | depends_on: 18 | - netbox 19 | ports: 20 | - 8080 21 | volumes: 22 | - netbox-static-files:/opt/netbox/netbox/static 23 | - netbox-nginx-config:/etc/netbox-nginx/ 24 | postgres: 25 | image: postgres:9.6-alpine 26 | environment: 27 | POSTGRES_USER: netbox 28 | POSTGRES_PASSWORD: J5brHrAXFLQSif0K 29 | POSTGRES_DB: netbox 30 | volumes: 31 | netbox-static-files: 32 | driver: local 33 | netbox-nginx-config: 34 | driver: local 35 | -------------------------------------------------------------------------------- /docker/settings.py: -------------------------------------------------------------------------------- 1 | # netbox_graphql configuration 2 | # source file docker/setting.py 3 | 4 | INSTALLED_APPS += ( 5 | 'graphene_django', 6 | 'netbox_graphql', 7 | ) 8 | 9 | GRAPHIQL_ENABLED = True # optional, by default True, set False to disable it 10 | GRAPHENE = { 11 | # points to the netbox_graphql schema variable in schema.py 12 | 'SCHEMA': 'netbox_graphql.schema.schema', 13 | 'SCHEMA_INDENT': 2, # defines the indentation space in the output 14 | } 15 | -------------------------------------------------------------------------------- /docker/urls.py: -------------------------------------------------------------------------------- 1 | # netbox_graphql urls 2 | # source docker/urls.py 3 | 4 | _patterns += [ 5 | url(r'^graphql', include('netbox_graphql.urls')), # token required 6 | 7 | # url(r'^graphql/client', GraphQLView.as_view(graphiql=True)), # without token 8 | ] 9 | -------------------------------------------------------------------------------- /netbox.env: -------------------------------------------------------------------------------- 1 | SUPERUSER_NAME=admin 2 | SUPERUSER_EMAIL=admin@example.com 3 | SUPERUSER_PASSWORD=admin 4 | ALLOWED_HOSTS=localhost 5 | DB_NAME=netbox 6 | DB_USER=netbox 7 | DB_PASSWORD=J5brHrAXFLQSif0K 8 | DB_HOST=postgres 9 | SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj 10 | EMAIL_SERVER=localhost 11 | EMAIL_PORT=25 12 | EMAIL_USERNAME=foo 13 | EMAIL_PASSWORD=bar 14 | EMAIL_TIMEOUT=10 15 | EMAIL_FROM=netbox@bar.com 16 | NETBOX_USERNAME=guest 17 | NETBOX_PASSWORD=guest 18 | -------------------------------------------------------------------------------- /netbox_graphql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/circuits_schema.py: -------------------------------------------------------------------------------- 1 | from graphene_django.filter import DjangoFilterConnectionField 2 | from graphene_django.types import DjangoObjectType 3 | from graphene import AbstractType, Field, Node, ClientIDMutation, AbstractType 4 | from graphql_relay.node.node import from_global_id 5 | from graphene import ID, Boolean, Float, Int, List, String 6 | 7 | from circuits.models import CircuitType, Circuit, Provider, CircuitTermination 8 | from dcim.models import Site, Interface 9 | from tenancy.models import Tenant 10 | from .custom_filter_fields import date_types, string_types, number_types 11 | from .helper_methods import not_none, set_and_save 12 | 13 | # Nodes 14 | 15 | 16 | class ProviderNode(DjangoObjectType): 17 | asn = Float() 18 | custom_field_values = String() 19 | 20 | class Meta: 21 | model = Provider 22 | interfaces = (Node, ) 23 | filter_fields = { 24 | 'id': ['exact'], 25 | 'name': string_types, 26 | 'slug': ['exact'], 27 | 'asn': number_types, 28 | } 29 | 30 | 31 | class CircuitNode(DjangoObjectType): 32 | custom_field_values = String() 33 | 34 | class Meta: 35 | model = Circuit 36 | interfaces = (Node, ) 37 | filter_fields = { 38 | 'id': ['exact'], 39 | 'cid': string_types, 40 | 'commit_rate': number_types, 41 | 'install_date': date_types, 42 | 'description': string_types, 43 | 'comments': string_types, 44 | } 45 | 46 | 47 | class CircuitTypeNode(DjangoObjectType): 48 | class Meta: 49 | model = CircuitType 50 | interfaces = (Node, ) 51 | filter_fields = { 52 | 'id': ['exact'], 53 | 'name': string_types, 54 | 'slug': string_types, 55 | } 56 | 57 | 58 | class CircuitTerminationNode(DjangoObjectType): 59 | class Meta: 60 | model = CircuitTermination 61 | interfaces = (Node, ) 62 | filter_fields = { 63 | 'id': ['exact'], 64 | 'term_side': string_types, 65 | } 66 | 67 | # Queries 68 | 69 | 70 | class CircuitsQuery(AbstractType): 71 | providers = DjangoFilterConnectionField(ProviderNode) 72 | 73 | circuit_types = DjangoFilterConnectionField(CircuitTypeNode) 74 | 75 | circuit = Node.Field(CircuitNode) 76 | circuits = DjangoFilterConnectionField(CircuitNode) 77 | 78 | circuit_terminations = DjangoFilterConnectionField(CircuitTerminationNode) 79 | 80 | # Mutations 81 | 82 | 83 | class NewCircuitType(ClientIDMutation): 84 | circuit_type = Field(CircuitTypeNode) 85 | 86 | class Input: 87 | name = String() 88 | slug = String() 89 | 90 | @classmethod 91 | def mutate_and_get_payload(cls, input, context, info): 92 | fields = ['name', 'slug'] 93 | return NewCircuitType(circuit_type=set_and_save(fields, input, CircuitType())) 94 | 95 | 96 | class UpdateCircuitType(ClientIDMutation): 97 | circuit_type = Field(CircuitTypeNode) 98 | 99 | class Input: 100 | id = String() 101 | name = String() 102 | slug = String() 103 | 104 | @classmethod 105 | def mutate_and_get_payload(cls, input, context, info): 106 | temp = CircuitType.objects.get(pk=from_global_id(input.get('id'))[1]) 107 | fields = ['name', 'slug'] 108 | return UpdateCircuitType(circuit_type=set_and_save(fields, input, temp)) 109 | 110 | 111 | class DeleteCircuitType(ClientIDMutation): 112 | circuit_type = Field(CircuitTypeNode) 113 | 114 | class Input: 115 | id = String() 116 | 117 | @classmethod 118 | def mutate_and_get_payload(cls, input, context, info): 119 | temp = CircuitType.objects.get(pk=from_global_id(input.get('id'))[1]) 120 | temp.delete() 121 | return DeleteCircuitType(circuit_type=temp) 122 | 123 | 124 | class NewProvider(ClientIDMutation): 125 | provider = Field(ProviderNode) 126 | 127 | class Input: 128 | name = String() 129 | slug = String() 130 | asn = Float() 131 | account = String(default_value=None) 132 | portal_url = String(default_value=None) 133 | noc_contact = String(default_value=None) 134 | admin_contact = String(default_value=None) 135 | comments = String(default_value=None) 136 | custom_field_values = String(default_value=None) 137 | 138 | @classmethod 139 | def mutate_and_get_payload(cls, input, context, info): 140 | fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 141 | 'admin_contact', 'comments', 'custom_field_values'] 142 | return NewProvider(provider=set_and_save(fields, input, Provider())) 143 | 144 | 145 | class UpdateProvider(ClientIDMutation): 146 | provider = Field(ProviderNode) 147 | 148 | class Input: 149 | id = String() 150 | name = String() 151 | slug = String() 152 | asn = Float() 153 | account = String() 154 | portal_url = String() 155 | noc_contact = String() 156 | admin_contact = String() 157 | comments = String() 158 | custom_field_values = String() 159 | 160 | @classmethod 161 | def mutate_and_get_payload(cls, input, context, info): 162 | temp = Provider.objects.get(pk=from_global_id(input.get('id'))[1]) 163 | fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 164 | 'admin_contact', 'comments', 'custom_field_values'] 165 | return UpdateProvider(provider=set_and_save(fields, input, temp)) 166 | 167 | 168 | class DeleteProvider(ClientIDMutation): 169 | provider = Field(ProviderNode) 170 | 171 | class Input: 172 | id = String() 173 | 174 | @classmethod 175 | def mutate_and_get_payload(cls, input, context, info): 176 | temp = Provider.objects.get(pk=from_global_id(input.get('id'))[1]) 177 | temp.delete() 178 | return DeleteProvider(provider=temp) 179 | 180 | 181 | class NewCircuit(ClientIDMutation): 182 | circuit = Field(CircuitNode) 183 | 184 | class Input: 185 | cid = String(default_value=None) 186 | provider = String(default_value=None) 187 | type = String(default_value=None) 188 | tenant = String(default_value=None) 189 | install_date = String(default_value=None) 190 | commit_rate = Int(default_value=None) 191 | description = String(default_value=None) 192 | comments = String(default_value=None) 193 | custom_field_values = String(default_value=None) 194 | 195 | @classmethod 196 | def mutate_and_get_payload(cls, input, context, info): 197 | provider = input.get('provider') 198 | type = input.get('type') 199 | tenant = input.get('tenant') 200 | 201 | temp = Circuit() 202 | 203 | if not_none(provider): 204 | temp.provider = Provider.objects.get( 205 | pk=from_global_id(provider)[1]) 206 | if not_none(type): 207 | temp.type = CircuitType.objects.get(pk=from_global_id(type)[1]) 208 | if not_none(tenant): 209 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 210 | 211 | fields = ['cid', 'install_date', 'commit_rate', 212 | 'description', 'comments', 'custom_field_values'] 213 | return NewCircuit(circuit=set_and_save(fields, input, temp)) 214 | 215 | 216 | class UpdateCircuit(ClientIDMutation): 217 | circuit = Field(CircuitNode) 218 | 219 | class Input: 220 | id = String(default_value=None) 221 | cid = String(default_value=None) 222 | provider = String(default_value=None) 223 | type = String(default_value=None) 224 | tenant = String(default_value=None) 225 | install_date = String(default_value=None) 226 | commit_rate = Int(default_value=None) 227 | description = String(default_value=None) 228 | comments = String(default_value=None) 229 | custom_field_values = String(default_value=None) 230 | 231 | @classmethod 232 | def mutate_and_get_payload(cls, input, context, info): 233 | provider = input.get('provider') 234 | type = input.get('type') 235 | tenant = input.get('tenant') 236 | 237 | temp = Circuit.objects.get(pk=from_global_id(input.get('id'))[1]) 238 | 239 | if not_none(provider): 240 | temp.provider = Provider.objects.get( 241 | pk=from_global_id(provider)[1]) 242 | if not_none(type): 243 | temp.type = CircuitType.objects.get(pk=from_global_id(type)[1]) 244 | if not_none(tenant): 245 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 246 | 247 | fields = ['cid', 'install_date', 'commit_rate', 248 | 'description', 'comments', 'custom_field_values'] 249 | return UpdateCircuit(circuit=set_and_save(fields, input, temp)) 250 | 251 | 252 | class DeleteCircuit(ClientIDMutation): 253 | circuit = Field(CircuitNode) 254 | 255 | class Input: 256 | id = String() 257 | 258 | @classmethod 259 | def mutate_and_get_payload(cls, input, context, info): 260 | temp = Circuit.objects.get(pk=from_global_id(input.get('id'))[1]) 261 | temp.delete() 262 | return DeleteCircuit(circuit=temp) 263 | 264 | 265 | class NewCircuitTermination(ClientIDMutation): 266 | circuit_termination = Field(CircuitTerminationNode) 267 | 268 | class Input: 269 | circuit = String(default_value=None) 270 | term_side = String(default_value=None) 271 | site = String(default_value=None) 272 | interface = String(default_value=None) 273 | port_speed = Int(default_value=None) 274 | upstream_speed = Int(default_value=None) 275 | xconnect_id = String(default_value=None) 276 | pp_info = String(default_value=None) 277 | 278 | @classmethod 279 | def mutate_and_get_payload(cls, input, context, info): 280 | circuit = input.get('circuit') 281 | site = input.get('site') 282 | interface = input.get('interface') 283 | 284 | temp = CircuitTermination() 285 | 286 | if not_none(circuit): 287 | temp.circuit = Circuit.objects.get(pk=from_global_id(circuit)[1]) 288 | if not_none(site): 289 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 290 | if not_none(interface): 291 | temp.interface = Interface.objects.get( 292 | pk=from_global_id(interface)[1]) 293 | 294 | fields = ['term_side', 'port_speed', 295 | 'upstream_speed', 'xconnect_id', 'pp_info'] 296 | return NewCircuitTermination(circuit_termination=set_and_save(fields, input, temp)) 297 | 298 | 299 | class UpdateCircuitTermination(ClientIDMutation): 300 | circuit_termination = Field(CircuitTerminationNode) 301 | 302 | class Input: 303 | id = String(default_value=None) 304 | circuit = String(default_value=None) 305 | term_side = String(default_value=None) 306 | site = String(default_value=None) 307 | interface = String(default_value=None) 308 | port_speed = Int(default_value=None) 309 | upstream_speed = Int(default_value=None) 310 | xconnect_id = String(default_value=None) 311 | pp_info = String(default_value=None) 312 | 313 | @classmethod 314 | def mutate_and_get_payload(cls, input, context, info): 315 | circuit = input.get('circuit') 316 | site = input.get('site') 317 | interface = input.get('interface') 318 | 319 | temp = CircuitTermination.objects.get( 320 | pk=from_global_id(input.get('id'))[1]) 321 | 322 | if not_none(circuit): 323 | temp.circuit = Circuit.objects.get(pk=from_global_id(circuit)[1]) 324 | if not_none(site): 325 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 326 | if not_none(interface): 327 | temp.interface = Interface.objects.get( 328 | pk=from_global_id(interface)[1]) 329 | 330 | fields = ['term_side', 'port_speed', 331 | 'upstream_speed', 'xconnect_id', 'pp_info'] 332 | return UpdateCircuitTermination(circuit_termination=set_and_save(fields, input, temp)) 333 | 334 | 335 | class DeleteCircuitTermination(ClientIDMutation): 336 | circuit_termination = Field(CircuitTerminationNode) 337 | 338 | class Input: 339 | id = String() 340 | 341 | @classmethod 342 | def mutate_and_get_payload(cls, input, context, info): 343 | temp = CircuitTermination.objects.get( 344 | pk=from_global_id(input.get('id'))[1]) 345 | temp.delete() 346 | return DeleteCircuitTermination(circuit_termination=temp) 347 | 348 | 349 | class CircuitsMutations(AbstractType): 350 | # Circuit 351 | new_circuit = NewCircuit.Field() 352 | update_circuit = UpdateCircuit.Field() 353 | delete_circuit = DeleteCircuit.Field() 354 | # Provider 355 | new_provider = NewProvider.Field() 356 | update_provider = UpdateProvider.Field() 357 | delete_provider = DeleteProvider.Field() 358 | # CircuitType 359 | new_circuit_type = NewCircuitType.Field() 360 | update_circuit_type = UpdateCircuitType.Field() 361 | delete_circuit_type = DeleteCircuitType.Field() 362 | # CircuitTermination 363 | new_circuit_termination = NewCircuitTermination.Field() 364 | update_circuit_termination = UpdateCircuitTermination.Field() 365 | delete_circuit_termination = DeleteCircuitTermination.Field() 366 | -------------------------------------------------------------------------------- /netbox_graphql/custom_filter_fields.py: -------------------------------------------------------------------------------- 1 | number_types = ['exact', 'gte', 'lte', 'in', 'lt', 'gt', 'range'] 2 | string_types = ['exact', 'icontains', 'istartswith'] 3 | date_types = ['exact', 'gte', 'lte', 'in', 'lt', 'gt', 'range'] 4 | -------------------------------------------------------------------------------- /netbox_graphql/dcim_schema.py: -------------------------------------------------------------------------------- 1 | import graphene 2 | from graphene import AbstractType, Node 3 | from graphene_django.filter import DjangoFilterConnectionField 4 | from graphene_django.types import DjangoObjectType 5 | from graphene_django.converter import convert_django_field 6 | from graphene import AbstractType, Field, Node, ClientIDMutation, AbstractType 7 | from graphene import ID, Boolean, Float, Int, List, String 8 | from graphql_relay.node.node import from_global_id 9 | 10 | from .custom_filter_fields import date_types, string_types, number_types 11 | from .helper_methods import not_none, set_and_save 12 | from dcim.models import Device, Interface, Site, Region, Platform, DeviceRole 13 | from dcim.fields import ASNField, MACAddressField 14 | from tenancy.models import Tenant 15 | 16 | # Convert special field 17 | @convert_django_field.register(MACAddressField) 18 | def MACAddressFieldConvert(field, registry=None): 19 | return graphene.String() 20 | 21 | @convert_django_field.register(ASNField) 22 | def ASNFieldConvert(field, registry=None): 23 | return graphene.Float() 24 | 25 | # Nodes 26 | class DeviceNode(DjangoObjectType): 27 | class Meta: 28 | model = Device 29 | interfaces = (Node, ) 30 | 31 | class InterfaceNode(DjangoObjectType): 32 | class Meta: 33 | model = Interface 34 | interfaces = (Node, ) 35 | 36 | class SiteNode(DjangoObjectType): 37 | class Meta: 38 | model = Site 39 | interfaces = (Node, ) 40 | filter_fields = { 41 | 'id': ['exact'], 42 | 'name': string_types, 43 | 'slug': ['exact'], 44 | } 45 | 46 | class RegionNode(DjangoObjectType): 47 | class Meta: 48 | model = Region 49 | interfaces = (Node, ) 50 | filter_fields = { 51 | 'id': ['exact'], 52 | 'name': string_types, 53 | 'slug': ['exact'], 54 | } 55 | 56 | class DeviceRoleNode(DjangoObjectType): 57 | class Meta: 58 | model = DeviceRole 59 | interfaces = (Node, ) 60 | filter_fields = { 61 | 'id': ['exact'], 62 | 'name': string_types, 63 | 'slug': ['exact'], 64 | } 65 | 66 | class PlatformNode(DjangoObjectType): 67 | class Meta: 68 | model = Platform 69 | interfaces = (Node, ) 70 | filter_fields = { 71 | 'id': ['exact'], 72 | 'name': string_types, 73 | 'slug': ['exact'], 74 | } 75 | # Queries 76 | class DcimQuery(AbstractType): 77 | devices = DjangoFilterConnectionField(DeviceNode) 78 | interfaces = DjangoFilterConnectionField(InterfaceNode) 79 | sites = DjangoFilterConnectionField(SiteNode) 80 | regions = DjangoFilterConnectionField(RegionNode) 81 | 82 | # Mutations 83 | class NewRegion(ClientIDMutation): 84 | region = Field(RegionNode) 85 | class Input: 86 | parent = String() 87 | name = String() 88 | slug = String() 89 | 90 | @classmethod 91 | def mutate_and_get_payload(cls, input, context, info): 92 | parent = input.get('parent') 93 | 94 | temp = Region() 95 | 96 | if not_none(parent): 97 | temp.parent = Region.objects.get(pk=from_global_id(parent)[1]) 98 | 99 | fields = [ 'name', 'slug' ] 100 | return NewRegion(region=set_and_save(fields, input, temp)) 101 | 102 | class UpdateRegion(ClientIDMutation): 103 | region = Field(RegionNode) 104 | class Input: 105 | id = String() 106 | parent = String() 107 | name = String() 108 | slug = String() 109 | 110 | @classmethod 111 | def mutate_and_get_payload(cls, input, context, info): 112 | temp = Region.objects.get(pk=from_global_id(input.get('id'))[1]) 113 | 114 | parent = input.get('parent') 115 | 116 | if not_none(parent): 117 | temp.parent = Region.objects.get(pk=from_global_id(parent)[1]) 118 | 119 | fields = [ 'name', 'slug' ] 120 | return UpdateRegion(region=set_and_save(fields, input, temp)) 121 | 122 | class DeleteRegion(ClientIDMutation): 123 | region = Field(RegionNode) 124 | class Input: 125 | id = String() 126 | 127 | @classmethod 128 | def mutate_and_get_payload(cls, input, context, info): 129 | temp = Region.objects.get(pk=from_global_id(input.get('id'))[1]) 130 | temp.delete() 131 | return DeleteRegion(region=temp) 132 | 133 | # Site 134 | class NewSite(ClientIDMutation): 135 | site = Field(SiteNode) 136 | class Input: 137 | name = String() 138 | slug = String() 139 | region = String(default_value=None) 140 | tenant = String(default_value=None) 141 | facility = String(default_value=None) 142 | asn = Float(default_value=None) 143 | physical_address = String(default_value=None) 144 | shipping_address = String(default_value=None) 145 | contact_name = String(default_value=None) 146 | contact_phone = String(default_value=None) 147 | contact_email = String(default_value=None) 148 | comments = String(default_value=None) 149 | 150 | @classmethod 151 | def mutate_and_get_payload(cls, input, context, info): 152 | region = input.get('region') 153 | tenant = input.get('tenant') 154 | 155 | temp = Site() 156 | 157 | if not_none(region): 158 | temp.region = Region.objects.get(pk=from_global_id(region)[1]) 159 | 160 | if not_none(tenant): 161 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 162 | 163 | fields = [ 'name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'comments' ] 164 | return NewSite(site=set_and_save(fields, input, temp)) 165 | 166 | class UpdateSite(ClientIDMutation): 167 | site = Field(SiteNode) 168 | class Input: 169 | id = String() 170 | name = String() 171 | slug = String() 172 | region = String(default_value=None) 173 | tenant = String(default_value=None) 174 | facility = String(default_value=None) 175 | asn = Float(default_value=None) 176 | physical_address = String(default_value=None) 177 | shipping_address = String(default_value=None) 178 | contact_name = String(default_value=None) 179 | contact_phone = String(default_value=None) 180 | contact_email = String(default_value=None) 181 | comments = String(default_value=None) 182 | 183 | @classmethod 184 | def mutate_and_get_payload(cls, input, context, info): 185 | temp = Site.objects.get(pk=from_global_id(input.get('id'))[1]) 186 | 187 | region = input.get('region') 188 | tenant = input.get('tenant') 189 | 190 | if not_none(region): 191 | temp.region = Region.objects.get(pk=from_global_id(region)[1]) 192 | 193 | if not_none(tenant): 194 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 195 | 196 | fields = [ 'name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'contact_name', 'contact_phone', 'contact_email', 'comments' ] 197 | 198 | return UpdateSite(site=set_and_save(fields, input, temp)) 199 | 200 | class DeleteSite(ClientIDMutation): 201 | site = Field(SiteNode) 202 | class Input: 203 | id = String() 204 | 205 | @classmethod 206 | def mutate_and_get_payload(cls, input, context, info): 207 | temp = Site.objects.get(pk=from_global_id(input.get('id'))[1]) 208 | temp.delete() 209 | return DeleteSite(site=temp) 210 | 211 | class DcimMutations(AbstractType): 212 | # Region 213 | new_region = NewRegion.Field() 214 | update_region = UpdateRegion.Field() 215 | delete_region = DeleteRegion.Field() 216 | # Site 217 | new_site = NewSite.Field() 218 | update_site = UpdateSite.Field() 219 | delete_site = DeleteSite.Field() 220 | -------------------------------------------------------------------------------- /netbox_graphql/helper_methods.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def not_none(value): 4 | return value is not None 5 | 6 | def set_and_save(fields, input, object): 7 | for field in fields: 8 | if not_none(input.get(field)): 9 | setattr(object, field, input.get(field)) 10 | object.full_clean() 11 | object.save() 12 | return object 13 | 14 | def print_result(result): 15 | print(json.dumps(result.data)) 16 | -------------------------------------------------------------------------------- /netbox_graphql/ipam_schema.py: -------------------------------------------------------------------------------- 1 | import graphene 2 | from graphene import AbstractType, Node 3 | from graphene_django.converter import convert_django_field 4 | from graphene_django.filter import DjangoFilterConnectionField 5 | from graphene_django.types import DjangoObjectType 6 | from graphene import AbstractType, Field, Node, ClientIDMutation, AbstractType 7 | from graphene import ID, Boolean, Float, Int, List, String 8 | from graphql_relay.node.node import from_global_id 9 | from .custom_filter_fields import date_types, string_types, number_types 10 | from .helper_methods import not_none, set_and_save 11 | from ipam.models import IPAddress, VLANGroup, Role, VLAN, VRF, RIR, Aggregate, IPAddress, Prefix 12 | from tenancy.models import Tenant 13 | from ipam.fields import IPNetworkField, IPAddressField 14 | from dcim.models import Site, Interface 15 | 16 | @convert_django_field.register(IPNetworkField) 17 | def iPNetworkFieldConvert(field, registry=None): 18 | return graphene.String() 19 | 20 | @convert_django_field.register(IPAddressField) 21 | def iPAddressFieldConvert(field, registry=None): 22 | return graphene.String() 23 | 24 | # Nodes 25 | class IPAddressNode(DjangoObjectType): 26 | class Meta: 27 | model = IPAddress 28 | interfaces = (Node, ) 29 | filter_fields = { 30 | 'id': ['exact'] 31 | } 32 | 33 | class RoleNode(DjangoObjectType): 34 | class Meta: 35 | model = Role 36 | interfaces = (Node, ) 37 | filter_fields = { 38 | 'id': ['exact'], 39 | 'name': string_types, 40 | 'slug': ['exact'], 41 | } 42 | 43 | class VLANGroupNode(DjangoObjectType): 44 | class Meta: 45 | model = VLANGroup 46 | interfaces = (Node, ) 47 | filter_fields = { 48 | 'id': ['exact'], 49 | 'name': string_types, 50 | 'slug': ['exact'], 51 | } 52 | 53 | class VLANNode(DjangoObjectType): 54 | class Meta: 55 | model = VLAN 56 | interfaces = (Node, ) 57 | filter_fields = { 58 | 'id': ['exact'], 59 | 'name': string_types, 60 | } 61 | 62 | class VRFNode(DjangoObjectType): 63 | class Meta: 64 | model = VRF 65 | interfaces = (Node, ) 66 | filter_fields = { 67 | 'id': ['exact'], 68 | 'name': string_types, 69 | } 70 | 71 | class RIRNode(DjangoObjectType): 72 | class Meta: 73 | model = RIR 74 | interfaces = (Node, ) 75 | filter_fields = { 76 | 'id': ['exact'], 77 | 'name': string_types, 78 | 'slug': ['exact'], 79 | } 80 | 81 | class AggregateNode(DjangoObjectType): 82 | class Meta: 83 | model = Aggregate 84 | interfaces = (Node, ) 85 | filter_fields = { 86 | 'id': ['exact'], 87 | } 88 | 89 | class PrefixNode(DjangoObjectType): 90 | class Meta: 91 | model = Prefix 92 | interfaces = (Node, ) 93 | filter_fields = { 94 | 'id': ['exact'], 95 | } 96 | 97 | # Queries 98 | class IpamQuery(AbstractType): 99 | ip_address = DjangoFilterConnectionField(IPAddressNode) 100 | vlan_roles = DjangoFilterConnectionField(RoleNode) 101 | vlan_groups = DjangoFilterConnectionField(VLANGroupNode) 102 | vlans = DjangoFilterConnectionField(VLANNode) 103 | vrfs = DjangoFilterConnectionField(VRFNode) 104 | rirs = DjangoFilterConnectionField(RIRNode) 105 | aggregates = DjangoFilterConnectionField(AggregateNode) 106 | prefixes = DjangoFilterConnectionField(PrefixNode) 107 | 108 | # Mutations 109 | class NewRole(ClientIDMutation): 110 | vlan_role = Field(RoleNode) 111 | class Input: 112 | slug = String() 113 | name = String(default_value=None) 114 | weight = Int(default_value=None) 115 | 116 | @classmethod 117 | def mutate_and_get_payload(cls, input, context, info): 118 | temp = Role() 119 | fields = ['name', 'slug', 'weight'] 120 | return NewRole(vlan_role=set_and_save(fields, input, temp)) 121 | 122 | class UpdateRole(ClientIDMutation): 123 | vlan_role = Field(RoleNode) 124 | class Input: 125 | id = String() 126 | slug = String(default_value=None) 127 | name = String(default_value=None) 128 | weight = Int(default_value=None) 129 | 130 | @classmethod 131 | def mutate_and_get_payload(cls, input, context, info): 132 | temp = Role.objects.get(pk=from_global_id(input.get('id'))[1]) 133 | fields = [ 'name', 'slug', 'weight' ] 134 | return UpdateRole(vlan_role=set_and_save(fields, input, temp)) 135 | 136 | class DeleteRole(ClientIDMutation): 137 | vlan_role = Field(RoleNode) 138 | class Input: 139 | id = String() 140 | 141 | @classmethod 142 | def mutate_and_get_payload(cls, input, context, info): 143 | temp = Role.objects.get(pk=from_global_id(input.get('id'))[1]) 144 | temp.delete() 145 | return DeleteRole(vlan_role=temp) 146 | 147 | class NewVLANGroup(ClientIDMutation): 148 | vlan_group = Field(VLANGroupNode) 149 | class Input: 150 | name = String(default_value=None) 151 | slug = String(default_value=None) 152 | site = String(default_value=None) 153 | 154 | @classmethod 155 | def mutate_and_get_payload(cls, input, context, info): 156 | site = input.get('site') 157 | 158 | temp = VLANGroup() 159 | 160 | if not_none(site): 161 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 162 | 163 | fields = [ 'name', 'slug' ] 164 | return NewVLANGroup(vlan_group=set_and_save(fields, input, temp)) 165 | 166 | class UpdateVLANGroup(ClientIDMutation): 167 | vlan_group = Field(VLANGroupNode) 168 | class Input: 169 | id = String() 170 | name = String(default_value=None) 171 | slug = String(default_value=None) 172 | site = String(default_value=None) 173 | 174 | @classmethod 175 | def mutate_and_get_payload(cls, input, context, info): 176 | temp = VLANGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 177 | 178 | site = input.get('site') 179 | 180 | if not_none(site): 181 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 182 | 183 | fields = [ 'name', 'slug' ] 184 | return UpdateVLANGroup(vlan_group=set_and_save(fields, input, temp)) 185 | 186 | class DeleteVLANGroup(ClientIDMutation): 187 | vlan_group = Field(VLANGroupNode) 188 | class Input: 189 | id = String() 190 | 191 | @classmethod 192 | def mutate_and_get_payload(cls, input, context, info): 193 | temp = VLANGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 194 | temp.delete() 195 | return DeleteVLANGroup(vlan_group=temp) 196 | 197 | class NewVLAN(ClientIDMutation): 198 | vlan = Field(VLANNode) 199 | class Input: 200 | site = String(default_value=None) 201 | group = String(default_value=None) 202 | vid = Int(default_value=None) 203 | name = String(default_value=None) 204 | tenant = String(default_value=None) 205 | status = Int(default_value=None) 206 | role = String(default_value=None) 207 | description = String(default_value=None) 208 | 209 | @classmethod 210 | def mutate_and_get_payload(cls, input, context, info): 211 | site = input.get('site') 212 | group = input.get('group') 213 | tenant = input.get('tenant') 214 | role = input.get('role') 215 | 216 | temp = VLAN() 217 | 218 | if not_none(site): 219 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 220 | 221 | if not_none(group): 222 | temp.group = VLANGroup.objects.get(pk=from_global_id(group)[1]) 223 | 224 | if not_none(tenant): 225 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 226 | 227 | if not_none(role): 228 | temp.role = Role.objects.get(pk=from_global_id(role)[1]) 229 | 230 | fields = [ 'name', 'vid', 'name', 'description' ] 231 | return NewVLAN(vlan=set_and_save(fields, input, temp)) 232 | 233 | class UpdateVLAN(ClientIDMutation): 234 | vlan = Field(VLANNode) 235 | class Input: 236 | id = String() 237 | site = String(default_value=None) 238 | group = String(default_value=None) 239 | vid = Int(default_value=None) 240 | name = String(default_value=None) 241 | tenant = String(default_value=None) 242 | status = Int(default_value=None) 243 | role = String(default_value=None) 244 | description = String(default_value=None) 245 | 246 | @classmethod 247 | def mutate_and_get_payload(cls, input, context, info): 248 | temp = VLAN.objects.get(pk=from_global_id(input.get('id'))[1]) 249 | 250 | site = input.get('site') 251 | group = input.get('group') 252 | tenant = input.get('tenant') 253 | role = input.get('role') 254 | 255 | if not_none(site): 256 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 257 | 258 | if not_none(group): 259 | temp.group = VLANGroup.objects.get(pk=from_global_id(group)[1]) 260 | 261 | if not_none(tenant): 262 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 263 | 264 | if not_none(role): 265 | temp.role = Role.objects.get(pk=from_global_id(role)[1]) 266 | 267 | fields = [ 'name', 'vid', 'name', 'description' ] 268 | return UpdateVLAN(vlan=set_and_save(fields, input, temp)) 269 | 270 | class DeleteVLAN(ClientIDMutation): 271 | vlan = Field(VLANNode) 272 | class Input: 273 | id = String() 274 | 275 | @classmethod 276 | def mutate_and_get_payload(cls, input, context, info): 277 | temp = VLAN.objects.get(pk=from_global_id(input.get('id'))[1]) 278 | temp.delete() 279 | return DeleteVLAN(vlan=temp) 280 | 281 | # VRF 282 | class NewVRF(ClientIDMutation): 283 | vrf = Field(VRFNode) 284 | class Input: 285 | name = String(default_value=None) 286 | rd = String(default_value=None) 287 | tenant = String(default_value=None) 288 | enforce_unique = Boolean(default_value=None) 289 | description = String(default_value=None) 290 | 291 | @classmethod 292 | def mutate_and_get_payload(cls, input, context, info): 293 | tenant = input.get('tenant') 294 | 295 | temp = VRF() 296 | 297 | if not_none(tenant): 298 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 299 | 300 | fields = ['name', 'rd', 'enforce_unique', 'description'] 301 | return NewVRF(vrf=set_and_save(fields, input, temp)) 302 | 303 | class UpdateVRF(ClientIDMutation): 304 | vrf = Field(VRFNode) 305 | class Input: 306 | id = String() 307 | name = String(default_value=None) 308 | rd = String(default_value=None) 309 | tenant = String(default_value=None) 310 | enforce_unique = Boolean(default_value=None) 311 | description = String(default_value=None) 312 | 313 | @classmethod 314 | def mutate_and_get_payload(cls, input, context, info): 315 | temp = VRF.objects.get(pk=from_global_id(input.get('id'))[1]) 316 | 317 | tenant = input.get('tenant') 318 | 319 | if not_none(tenant): 320 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 321 | 322 | fields = ['name', 'rd', 'enforce_unique', 'description'] 323 | return UpdateVRF(vrf=set_and_save(fields, input, temp)) 324 | 325 | class DeleteVRF(ClientIDMutation): 326 | vrf = Field(VRFNode) 327 | class Input: 328 | id = String() 329 | 330 | @classmethod 331 | def mutate_and_get_payload(cls, input, context, info): 332 | temp = VRF.objects.get(pk=from_global_id(input.get('id'))[1]) 333 | temp.delete() 334 | return DeleteVRF(vrf=temp) 335 | 336 | # RIR 337 | class NewRIR(ClientIDMutation): 338 | rir = Field(RIRNode) 339 | class Input: 340 | name = String(default_value=None) 341 | slug = String(default_value=None) 342 | is_private = Boolean(default_value=None) 343 | 344 | @classmethod 345 | def mutate_and_get_payload(cls, input, context, info): 346 | 347 | temp = RIR() 348 | 349 | fields = ['name', 'slug', 'is_private'] 350 | return NewRIR(rir=set_and_save(fields, input, temp)) 351 | 352 | class UpdateRIR(ClientIDMutation): 353 | rir = Field(RIRNode) 354 | class Input: 355 | id = String() 356 | name = String(default_value=None) 357 | slug = String(default_value=None) 358 | is_private = Boolean(default_value=None) 359 | 360 | @classmethod 361 | def mutate_and_get_payload(cls, input, context, info): 362 | temp = RIR.objects.get(pk=from_global_id(input.get('id'))[1]) 363 | 364 | fields = ['name', 'slug', 'is_private'] 365 | return UpdateRIR(rir=set_and_save(fields, input, temp)) 366 | 367 | class DeleteRIR(ClientIDMutation): 368 | rir = Field(RIRNode) 369 | class Input: 370 | id = String() 371 | 372 | @classmethod 373 | def mutate_and_get_payload(cls, input, context, info): 374 | temp = RIR.objects.get(pk=from_global_id(input.get('id'))[1]) 375 | temp.delete() 376 | return DeleteRIR(rir=temp) 377 | 378 | # Aggregate 379 | class NewAggregate(ClientIDMutation): 380 | aggregate = Field(AggregateNode) 381 | class Input: 382 | family = Int(default_value=None) 383 | prefix = String(default_value=None) 384 | rir = String(default_value=None) 385 | date_added = String(default_value=None) 386 | description = String(default_value=None) 387 | 388 | @classmethod 389 | def mutate_and_get_payload(cls, input, context, info): 390 | rir = input.get('rir') 391 | 392 | temp = Aggregate() 393 | 394 | if not_none(rir): 395 | temp.rir = RIR.objects.get(pk=from_global_id(rir)[1]) 396 | 397 | fields = ['family', 'prefix', 'date_added', 'description'] 398 | return NewAggregate(aggregate=set_and_save(fields, input, temp)) 399 | 400 | class UpdateAggregate(ClientIDMutation): 401 | aggregate = Field(AggregateNode) 402 | class Input: 403 | id = String() 404 | family = Int(default_value=None) 405 | prefix = String(default_value=None) 406 | rir = String(default_value=None) 407 | date_added = String(default_value=None) 408 | description = String(default_value=None) 409 | 410 | @classmethod 411 | def mutate_and_get_payload(cls, input, context, info): 412 | rir = input.get('rir') 413 | temp = Aggregate.objects.get(pk=from_global_id(input.get('id'))[1]) 414 | 415 | if not_none(rir): 416 | temp.rir = RIR.objects.get(pk=from_global_id(rir)[1]) 417 | 418 | fields = ['family', 'prefix', 'date_added', 'description'] 419 | 420 | return UpdateAggregate(aggregate=set_and_save(fields, input, temp)) 421 | 422 | class DeleteAggregate(ClientIDMutation): 423 | aggregate = Field(AggregateNode) 424 | class Input: 425 | id = String() 426 | 427 | @classmethod 428 | def mutate_and_get_payload(cls, input, context, info): 429 | temp = Aggregate.objects.get(pk=from_global_id(input.get('id'))[1]) 430 | temp.delete() 431 | return DeleteAggregate(aggregate=temp) 432 | 433 | # IPAddress 434 | class NewIPAddress(ClientIDMutation): 435 | ip_address = Field(IPAddressNode) 436 | 437 | class Input: 438 | family = Int(default_value=None) 439 | address = String(default_value=None) 440 | vrf = String(default_value=None) 441 | tenant = String(default_value=None) 442 | status = Int(default_value=None) 443 | interface = String(default_value=None) 444 | nat_inside = String(default_value=None) 445 | description = String(default_value=None) 446 | 447 | @classmethod 448 | def mutate_and_get_payload(cls, input, context, info): 449 | temp = IPAddress() 450 | 451 | vrf = input.get('vrf') 452 | tenant = input.get('tenant') 453 | interface = input.get('interface') 454 | nat_inside = input.get('nat_inside') 455 | 456 | if not_none(vrf): 457 | temp.vrf = VRF.objects.get(pk=from_global_id(vrf)[1]) 458 | 459 | if not_none(tenant): 460 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 461 | 462 | if not_none(interface): 463 | temp.interface = Interface.objects.get(pk=from_global_id(interface)[1]) 464 | 465 | if not_none(nat_inside): 466 | temp.nat_inside = IPAddress.objects.get(pk=from_global_id(nat_inside)[1]) 467 | 468 | fields = ['family', 'address', 'status', 'description'] 469 | 470 | return NewIPAddress(ip_address=set_and_save(fields, input, temp)) 471 | 472 | class UpdateIPAddress(ClientIDMutation): 473 | ip_address = Field(IPAddressNode) 474 | 475 | class Input: 476 | id = String() 477 | family = Int(default_value=None) 478 | address = String(default_value=None) 479 | vrf = String(default_value=None) 480 | tenant = String(default_value=None) 481 | status = Int(default_value=None) 482 | interface = String(default_value=None) 483 | nat_inside = String(default_value=None) 484 | description = String(default_value=None) 485 | 486 | @classmethod 487 | def mutate_and_get_payload(cls, input, context, info): 488 | temp = IPAddress.objects.get(pk=from_global_id(input.get('id'))[1]) 489 | 490 | vrf = input.get('vrf') 491 | tenant = input.get('tenant') 492 | interface = input.get('interface') 493 | nat_inside = input.get('nat_inside') 494 | 495 | if not_none(vrf): 496 | temp.vrf = VRF.objects.get(pk=from_global_id(vrf)[1]) 497 | 498 | if not_none(tenant): 499 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 500 | 501 | if not_none(interface): 502 | temp.interface = Interface.objects.get(pk=from_global_id(interface)[1]) 503 | 504 | if not_none(nat_inside): 505 | temp.nat_inside = IPAddress.objects.get(pk=from_global_id(nat_inside)[1]) 506 | 507 | fields = ['family', 'address', 'status', 'description'] 508 | 509 | return UpdateIPAddress(ip_address=set_and_save(fields, input, temp)) 510 | 511 | class DeleteIPAddress(ClientIDMutation): 512 | ip_address = Field(IPAddressNode) 513 | class Input: 514 | id = String() 515 | 516 | @classmethod 517 | def mutate_and_get_payload(cls, input, context, info): 518 | temp = IPAddress.objects.get(pk=from_global_id(input.get('id'))[1]) 519 | temp.delete() 520 | return DeleteIPAddress(ip_address=temp) 521 | 522 | # Prefix 523 | class NewPrefix(ClientIDMutation): 524 | prefix = Field(PrefixNode) 525 | 526 | class Input: 527 | family = Int(default_value=None) 528 | prefix = String(default_value=None) 529 | site = String(default_value=None) 530 | vrf = String(default_value=None) 531 | tenant = String(default_value=None) 532 | vlan = String(default_value=None) 533 | status = Int(default_value=None) 534 | role = String(default_value=None) 535 | description = String(default_value=None) 536 | is_pool = Boolean(default_value=None) 537 | 538 | @classmethod 539 | def mutate_and_get_payload(cls, input, context, info): 540 | temp = Prefix() 541 | 542 | site = input.get('site') 543 | vrf = input.get('vrf') 544 | tenant = input.get('tenant') 545 | vlan = input.get('vlan') 546 | role = input.get('role') 547 | 548 | if not_none(vrf): 549 | temp.vrf = VRF.objects.get(pk=from_global_id(vrf)[1]) 550 | 551 | if not_none(tenant): 552 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 553 | 554 | if not_none(site): 555 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 556 | 557 | if not_none(vlan): 558 | temp.vlan = VLAN.objects.get(pk=from_global_id(vlan)[1]) 559 | 560 | if not_none(role): 561 | temp.role = Role.objects.get(pk=from_global_id(role)[1]) 562 | 563 | fields = ['family', 'prefix', 'status', 'is_pool', 'description'] 564 | 565 | return NewPrefix(prefix=set_and_save(fields, input, temp)) 566 | 567 | class UpdatePrefix(ClientIDMutation): 568 | prefix = Field(PrefixNode) 569 | 570 | class Input: 571 | id = String() 572 | family = Int(default_value=None) 573 | prefix = String(default_value=None) 574 | site = String(default_value=None) 575 | vrf = String(default_value=None) 576 | tenant = String(default_value=None) 577 | vlan = String(default_value=None) 578 | status = Int(default_value=None) 579 | role = String(default_value=None) 580 | is_pool = Boolean(default_value=None) 581 | description = String(default_value=None) 582 | 583 | @classmethod 584 | def mutate_and_get_payload(cls, input, context, info): 585 | temp = Prefix.objects.get(pk=from_global_id(input.get('id'))[1]) 586 | 587 | site = input.get('site') 588 | vrf = input.get('vrf') 589 | tenant = input.get('tenant') 590 | vlan = input.get('vlan') 591 | role = input.get('role') 592 | 593 | if not_none(vrf): 594 | temp.vrf = VRF.objects.get(pk=from_global_id(vrf)[1]) 595 | 596 | if not_none(tenant): 597 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 598 | 599 | if not_none(site): 600 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 601 | 602 | if not_none(vlan): 603 | temp.vlan = VLAN.objects.get(pk=from_global_id(vlan)[1]) 604 | 605 | if not_none(role): 606 | temp.role = Role.objects.get(pk=from_global_id(role)[1]) 607 | 608 | fields = ['family', 'prefix', 'status', 'is_pool', 'description'] 609 | 610 | return UpdatePrefix(prefix=set_and_save(fields, input, temp)) 611 | 612 | class DeletePrefix(ClientIDMutation): 613 | prefix = Field(PrefixNode) 614 | class Input: 615 | id = String() 616 | 617 | @classmethod 618 | def mutate_and_get_payload(cls, input, context, info): 619 | temp = Prefix.objects.get(pk=from_global_id(input.get('id'))[1]) 620 | temp.delete() 621 | return DeletePrefix(prefix=temp) 622 | 623 | class IpamMutations(AbstractType): 624 | # Roles 625 | new_vlan_role = NewRole.Field() 626 | update_vlan_role = UpdateRole.Field() 627 | delete_vlan_role = DeleteRole.Field() 628 | # VLAN Group 629 | new_vlan_group = NewVLANGroup.Field() 630 | update_vlan_group = UpdateVLANGroup.Field() 631 | delete_vlan_group = DeleteVLANGroup.Field() 632 | # VLAN 633 | new_vlan = NewVLAN.Field() 634 | update_vlan = UpdateVLAN.Field() 635 | delete_vlan = DeleteVLAN.Field() 636 | # VRF 637 | new_vrf = NewVRF.Field() 638 | update_vrf = UpdateVRF.Field() 639 | delete_vrf = DeleteVRF.Field() 640 | # RIR 641 | new_rir = NewRIR.Field() 642 | update_rir = UpdateRIR.Field() 643 | delete_rir = DeleteRIR.Field() 644 | # Aggregate 645 | new_aggregate = NewAggregate.Field() 646 | update_aggregate = UpdateAggregate.Field() 647 | delete_aggregate = DeleteAggregate.Field() 648 | # IPAddress 649 | new_ip_address = NewIPAddress.Field() 650 | update_ip_address = UpdateIPAddress.Field() 651 | delete_ip_address = DeleteIPAddress.Field() 652 | # Prefixes 653 | new_prefix = NewPrefix.Field() 654 | update_prefix = UpdatePrefix.Field() 655 | delete_prefix = DeletePrefix.Field() 656 | 657 | -------------------------------------------------------------------------------- /netbox_graphql/schema.py: -------------------------------------------------------------------------------- 1 | import graphene 2 | from .circuits_schema import CircuitsQuery, CircuitsMutations 3 | from .tenancy_schema import TenancyQuery, TenancyMutations 4 | from .dcim_schema import DcimQuery, DcimMutations 5 | from .ipam_schema import IpamQuery, IpamMutations 6 | from .virtualization_schema import VirtualizationQuery, VirtualizationMutations 7 | 8 | # Root 9 | class RootQuery( 10 | CircuitsQuery 11 | , TenancyQuery 12 | , DcimQuery 13 | , IpamQuery 14 | , VirtualizationQuery 15 | , graphene.ObjectType): 16 | pass 17 | 18 | class RootMutation( 19 | CircuitsMutations 20 | , TenancyMutations 21 | , DcimMutations 22 | , IpamMutations 23 | , VirtualizationMutations 24 | , graphene.ObjectType): 25 | pass 26 | 27 | schema = graphene.Schema(query=RootQuery, mutation=RootMutation) 28 | -------------------------------------------------------------------------------- /netbox_graphql/tenancy_schema.py: -------------------------------------------------------------------------------- 1 | from graphene import AbstractType, Node 2 | from graphene_django.filter import DjangoFilterConnectionField 3 | from graphene_django.types import DjangoObjectType 4 | from graphene import ID, Boolean, Float, Int, List, String 5 | from graphene import AbstractType, Field, Node, ClientIDMutation, AbstractType 6 | from graphql_relay.node.node import from_global_id 7 | 8 | from .custom_filter_fields import date_types, string_types, number_types 9 | from tenancy.models import Tenant, TenantGroup 10 | from .helper_methods import not_none, set_and_save 11 | 12 | # Nodes 13 | class TenantGroupNode(DjangoObjectType): 14 | class Meta: 15 | model = TenantGroup 16 | interfaces = (Node, ) 17 | filter_fields = { 18 | 'id': ['exact'], 19 | 'name': string_types, 20 | 'slug': string_types, 21 | } 22 | 23 | class TenantNode(DjangoObjectType): 24 | class Meta: 25 | model = Tenant 26 | interfaces = (Node, ) 27 | filter_fields = { 28 | 'id': ['exact'], 29 | 'name': string_types, 30 | 'description': string_types, 31 | 'comments': string_types, 32 | } 33 | 34 | # Queries 35 | class TenancyQuery(AbstractType): 36 | tenant_groups = DjangoFilterConnectionField(TenantGroupNode) 37 | tenants = DjangoFilterConnectionField(TenantNode) 38 | 39 | # Mutations 40 | class NewTenantGroup(ClientIDMutation): 41 | tenant_group = Field(TenantGroupNode) 42 | class Input: 43 | name = String() 44 | slug = String() 45 | 46 | @classmethod 47 | def mutate_and_get_payload(cls, input, context, info): 48 | fields = [ 'name', 'slug' ] 49 | return NewTenantGroup(tenant_group=set_and_save(fields, input, TenantGroup())) 50 | 51 | class UpdateTenantGroup(ClientIDMutation): 52 | tenant_group = Field(TenantGroupNode) 53 | class Input: 54 | id = String() 55 | name = String() 56 | slug = String() 57 | 58 | @classmethod 59 | def mutate_and_get_payload(cls, input, context, info): 60 | temp = TenantGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 61 | fields = [ 'name', 'slug' ] 62 | return UpdateTenantGroup(tenant_group=set_and_save(fields, input, temp)) 63 | 64 | class DeleteTenantGroup(ClientIDMutation): 65 | tenant_group = Field(TenantGroupNode) 66 | class Input: 67 | id = String() 68 | 69 | @classmethod 70 | def mutate_and_get_payload(cls, input, context, info): 71 | temp = TenantGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 72 | temp.delete() 73 | return DeleteTenantGroup(tenant_group=temp) 74 | 75 | class NewTenant(ClientIDMutation): 76 | tenant = Field(TenantNode) 77 | class Input: 78 | name = String() 79 | slug = String() 80 | group = String(default_value=None) 81 | description = String(default_value=None) 82 | comments = String(default_value=None) 83 | custom_field_values = String(default_value=None) 84 | 85 | @classmethod 86 | def mutate_and_get_payload(cls, input, context, info): 87 | fields = [ 'name', 'slug', 'description', 'comments', 'custom_field_values' ] 88 | group = input.get('group') 89 | 90 | temp = Tenant() 91 | 92 | if not_none(group): 93 | temp.group = TenantGroup.objects.get(pk=from_global_id(group)[1]) 94 | 95 | return NewTenant(tenant=set_and_save(fields, input, temp)) 96 | 97 | class UpdateTenant(ClientIDMutation): 98 | tenant = Field(TenantNode) 99 | class Input: 100 | id = String(default_value=None) 101 | name = String(default_value=None) 102 | slug = String(default_value=None) 103 | group = String(default_value=None) 104 | description = String(default_value=None) 105 | comments = String(default_value=None) 106 | custom_field_values = String(default_value=None) 107 | 108 | @classmethod 109 | def mutate_and_get_payload(cls, input, context, info): 110 | group = input.get('group') 111 | 112 | temp = Tenant.objects.get(pk=from_global_id(input.get('id'))[1]) 113 | 114 | if not_none(group): 115 | temp.group = TenantGroup.objects.get(pk=from_global_id(group)[1]) 116 | 117 | fields = [ 'name', 'slug', 'description', 'comments', 'custom_field_values' ] 118 | return UpdateTenant(tenant=set_and_save(fields, input, temp)) 119 | 120 | class DeleteTenant(ClientIDMutation): 121 | tenant = Field(TenantNode) 122 | class Input: 123 | id = String() 124 | 125 | @classmethod 126 | def mutate_and_get_payload(cls, input, context, info): 127 | temp = Tenant.objects.get(pk=from_global_id(input.get('id'))[1]) 128 | temp.delete() 129 | return DeleteTenant(tenant=temp) 130 | 131 | class TenancyMutations(AbstractType): 132 | # Tenant Group 133 | new_tenant_group = NewTenantGroup.Field() 134 | update_tenant_group = UpdateTenantGroup.Field() 135 | delete_tenant_group = DeleteTenantGroup.Field() 136 | # Tenant 137 | new_tenant = NewTenant.Field() 138 | update_tenant = UpdateTenant.Field() 139 | delete_tenant = DeleteTenant.Field() 140 | -------------------------------------------------------------------------------- /netbox_graphql/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/circuits/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/circuits/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/circuits/tests_circuits.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from netbox_graphql.schema import schema 7 | from netbox_graphql.tests.utils import obj_to_global_id 8 | from netbox_graphql.tests.factories.circuit_factories import CircuitFactory, ProviderFactory, CircuitTypeFactory 9 | 10 | from circuits.models import Circuit 11 | 12 | 13 | class CreateTestCase(TestCase): 14 | @classmethod 15 | def setUpTestData(cls): 16 | cls.provider = ProviderFactory() 17 | cls.circuit_type = CircuitTypeFactory() 18 | cls.circuit = CircuitFactory.build() 19 | cls.query = Template(''' 20 | mutation { 21 | newCircuit(input: {cid: "$cid", provider:"$providerId", type:"$typeId", 22 | installDate:"2017-10-12", commitRate: 12, description:"desc", comments:"Awesome Comment!" }) { 23 | circuit { 24 | cid 25 | provider { 26 | name 27 | } 28 | type { 29 | name 30 | } 31 | installDate 32 | commitRate 33 | description 34 | comments 35 | } 36 | } 37 | } 38 | ''').substitute(cid=cls.circuit.cid, 39 | providerId=obj_to_global_id(cls.provider), 40 | typeId=obj_to_global_id(cls.circuit_type)) 41 | 42 | def test_creating_provider_returns_no_error(self): 43 | result = schema.execute(self.query) 44 | assert not result.errors 45 | 46 | def test_creating_provider_returns_data(self): 47 | expected = {'newCircuit': {'circuit': {'cid': self.circuit.cid, 48 | 'provider': {'name': self.provider.name}, 49 | 'type': {'name': self.circuit_type.name}, 50 | 'installDate': '2017-10-12', 51 | 'commitRate': 12, 52 | 'description': 'desc', 53 | 'comments': 'Awesome Comment!'}}} 54 | 55 | result = schema.execute(self.query) 56 | self.assertEquals(result.data, expected) 57 | 58 | def test_creating_provider_creates_it(self): 59 | oldCount = Circuit.objects.all().count() 60 | schema.execute(self.query) 61 | self.assertEquals(Circuit.objects.all().count(), oldCount + 1) 62 | 63 | 64 | class QueryMultipleTestCase(TestCase): 65 | @classmethod 66 | def setUpTestData(cls): 67 | cls.first = CircuitFactory() 68 | cls.second = CircuitFactory(provider=cls.first.provider, 69 | type=cls.first.type) 70 | cls.query = ''' 71 | query {circuits { 72 | edges { 73 | node { 74 | id 75 | cid 76 | provider { 77 | id 78 | } 79 | type { 80 | id 81 | } 82 | } 83 | } 84 | }} 85 | ''' 86 | 87 | def test_querying_all_returns_no_error(self): 88 | result = schema.execute(self.query) 89 | assert not result.errors 90 | 91 | def test_querying_all_returns_two_results(self): 92 | result = schema.execute(self.query) 93 | self.assertEquals(len(result.data['circuits']['edges']), 2) 94 | 95 | 96 | class QuerySingleTestCase(TestCase): 97 | @classmethod 98 | def setUpTestData(cls): 99 | cls.first = CircuitFactory() 100 | cls.second = CircuitFactory(provider=cls.first.provider, 101 | type=cls.first.type) 102 | cls.query = Template(''' 103 | { 104 | circuits(id: "$id") { 105 | edges { 106 | node { 107 | cid 108 | provider { 109 | name 110 | } 111 | type { 112 | name 113 | } 114 | } 115 | } 116 | } 117 | } 118 | ''').substitute(id=obj_to_global_id(cls.second)) 119 | 120 | def test_querying_single_provider_returns_no_error(self): 121 | result = schema.execute(self.query) 122 | assert not result.errors 123 | 124 | def test_querying_single_provider_returns_result(self): 125 | result = schema.execute(self.query) 126 | self.assertEquals(len(result.data['circuits']['edges']), 1) 127 | 128 | def test_querying_single_provider_returns_expected_result(self): 129 | result = schema.execute(self.query) 130 | expected = {'circuits': 131 | {'edges': [ 132 | {'node': {'cid': self.second.cid, 133 | 'provider': {'name': self.second.provider.name}, 134 | 'type': {'name': self.second.type.name}, 135 | }} 136 | ]}} 137 | self.assertEquals(result.data, expected) 138 | 139 | 140 | class UpdateTestCase(TestCase): 141 | @classmethod 142 | def setUpTestData(cls): 143 | cls.first = CircuitFactory() 144 | cls.query = Template(''' 145 | mutation { 146 | updateCircuit(input:{id: "$id", cid: "117", comments: "New Awesome Comment!" }) { 147 | circuit { 148 | cid 149 | comments 150 | } 151 | } 152 | } 153 | ''').substitute(id=obj_to_global_id(cls.first)) 154 | 155 | def test_updating_returns_no_error(self): 156 | result = schema.execute(self.query) 157 | assert not result.errors 158 | 159 | def test_updating_doesnt_change_count(self): 160 | oldCount = Circuit.objects.all().count() 161 | schema.execute(self.query) 162 | self.assertEquals(Circuit.objects.all().count(), oldCount) 163 | 164 | def test_updating_returns_updated_data(self): 165 | expected = {'updateCircuit': 166 | {'circuit': {'cid': '117', 'comments': 'New Awesome Comment!'}}} 167 | result = schema.execute(self.query) 168 | self.assertEquals(result.data, expected) 169 | 170 | def test_updating_alters_data(self): 171 | schema.execute(self.query) 172 | circuit = Circuit.objects.get(id=self.first.id) 173 | self.assertEquals(circuit.cid, '117') 174 | self.assertEquals(circuit.comments, 'New Awesome Comment!') 175 | 176 | 177 | class DeleteTestCase(TestCase): 178 | @classmethod 179 | def setUpTestData(cls): 180 | cls.first = CircuitFactory() 181 | cls.query = Template(''' 182 | mutation { 183 | deleteCircuit(input: {id: "$id"}) { 184 | circuit { 185 | id 186 | cid 187 | } 188 | } 189 | } 190 | ''').substitute(id=obj_to_global_id(cls.first)) 191 | 192 | def test_deleting_returns_no_error(self): 193 | result = schema.execute(self.query) 194 | assert not result.errors 195 | 196 | def test_deleting_removes_a_type(self): 197 | oldCount = Circuit.objects.all().count() 198 | schema.execute(self.query) 199 | self.assertEquals(Circuit.objects.all().count(), oldCount - 1) 200 | -------------------------------------------------------------------------------- /netbox_graphql/tests/circuits/tests_providers.py: -------------------------------------------------------------------------------- 1 | 2 | from string import Template 3 | 4 | from graphene.test import Client 5 | from django.test import TestCase 6 | 7 | from netbox_graphql.tests.utils import obj_to_global_id 8 | from netbox_graphql.tests.factories.circuit_factories import ProviderFactory 9 | 10 | from netbox_graphql.schema import schema 11 | 12 | from graphql_relay.node.node import from_global_id, to_global_id 13 | 14 | from circuits.models import Provider 15 | 16 | 17 | class CreateTestCase(TestCase): 18 | @classmethod 19 | def setUpTestData(cls): 20 | cls.query = ''' 21 | mutation { 22 | newProvider(input: {name: "Provider123", slug: "provider123", asn: 256, account: "account", 23 | portalUrl: "http://github.com/", nocContact:"noc", comments: "my comment"}) { 24 | provider { 25 | slug 26 | name 27 | asn 28 | account 29 | portalUrl 30 | nocContact 31 | comments 32 | } 33 | } 34 | } 35 | ''' 36 | 37 | def test_creating_provider_returns_no_error(self): 38 | result = schema.execute(self.query) 39 | assert not result.errors 40 | 41 | def test_creating_provider_returns_data(self): 42 | expected = {'newProvider': 43 | {'provider': {'slug': 'provider123', 'name': 'Provider123', 44 | 'asn': 256.0, 'account': 'account', 'portalUrl': 'http://github.com/', 45 | 'nocContact': 'noc', 'comments': 'my comment'}}} 46 | 47 | result = schema.execute(self.query) 48 | self.assertEquals(result.data, expected) 49 | 50 | def test_creating_provider_creates_it(self): 51 | oldCount = Provider.objects.all().count() 52 | schema.execute(self.query) 53 | self.assertEquals(Provider.objects.all().count(), oldCount + 1) 54 | 55 | 56 | class QueryMultipleTestCase(TestCase): 57 | @classmethod 58 | def setUpTestData(cls): 59 | cls.first = ProviderFactory() 60 | cls.second = ProviderFactory() 61 | cls.query = ''' 62 | query {providers { 63 | edges { 64 | node { 65 | id 66 | name 67 | slug 68 | } 69 | } 70 | }} 71 | ''' 72 | 73 | def test_querying_all_returns_no_error(self): 74 | result = schema.execute(self.query) 75 | assert not result.errors 76 | 77 | def test_querying_all_returns_two_results(self): 78 | result = schema.execute(self.query) 79 | self.assertEquals(len(result.data['providers']['edges']), 2) 80 | 81 | 82 | class QuerySingleTestCase(TestCase): 83 | @classmethod 84 | def setUpTestData(cls): 85 | cls.first = ProviderFactory() 86 | cls.second = ProviderFactory() 87 | 88 | cls.query = Template(''' 89 | { 90 | providers(id: "$id") { 91 | edges { 92 | node { 93 | name 94 | slug 95 | asn 96 | account 97 | portalUrl 98 | nocContact 99 | } 100 | } 101 | } 102 | } 103 | ''').substitute(id=obj_to_global_id(cls.second)) 104 | 105 | def test_querying_single_provider_returns_no_error(self): 106 | result = schema.execute(self.query) 107 | assert not result.errors 108 | 109 | def test_querying_single_provider_returns_result(self): 110 | result = schema.execute(self.query) 111 | self.assertEquals(len(result.data['providers']['edges']), 1) 112 | 113 | def test_querying_single_provider_returns_expected_result(self): 114 | result = schema.execute(self.query) 115 | expected = {'providers': 116 | {'edges': [ 117 | {'node': {'name': self.second.name, 118 | 'slug': self.second.slug, 119 | 'asn': self.second.asn, 120 | 'account': self.second.account, 121 | 'portalUrl': self.second.portal_url, 122 | 'nocContact': self.second.noc_contact, 123 | }} 124 | ]}} 125 | self.assertEquals(result.data, expected) 126 | 127 | 128 | class UpdateTestCase(TestCase): 129 | @classmethod 130 | def setUpTestData(cls): 131 | cls.first = ProviderFactory() 132 | cls.query = Template(''' 133 | mutation { 134 | updateProvider(input: {id:"$id", name: "New Name", slug: "psl1", 135 | portalUrl: "http://github.com/", comments: "my comment"}) { 136 | provider { 137 | name 138 | slug 139 | } 140 | } 141 | } 142 | ''').substitute(id=obj_to_global_id(cls.first)) 143 | 144 | def test_updating_returns_no_error(self): 145 | result = schema.execute(self.query) 146 | assert not result.errors 147 | 148 | def test_updating_doesnt_change_count(self): 149 | oldCount = Provider.objects.all().count() 150 | schema.execute(self.query) 151 | self.assertEquals(Provider.objects.all().count(), oldCount) 152 | 153 | def test_updating_returns_updated_data(self): 154 | expected = {'updateProvider': 155 | {'provider': {'name': 'New Name', 'slug': 'psl1'}}} 156 | result = schema.execute(self.query) 157 | self.assertEquals(result.data, expected) 158 | 159 | def test_updating_alters_data(self): 160 | schema.execute(self.query) 161 | provider = Provider.objects.get(id=self.first.id) 162 | self.assertEquals(provider.name, 'New Name') 163 | self.assertEquals(provider.slug, 'psl1') 164 | self.assertEquals(provider.portal_url, 'http://github.com/') 165 | 166 | 167 | class DeleteTestCase(TestCase): 168 | @classmethod 169 | def setUpTestData(cls): 170 | cls.first = ProviderFactory() 171 | cls.query = Template(''' 172 | mutation { 173 | deleteProvider(input: {id:"$id"}) { 174 | provider { 175 | id 176 | } 177 | } 178 | } 179 | ''').substitute(id=obj_to_global_id(cls.first)) 180 | 181 | def test_deleting_returns_no_error(self): 182 | result = schema.execute(self.query) 183 | assert not result.errors 184 | 185 | def test_deleting_removes_a_type(self): 186 | oldCount = Provider.objects.all().count() 187 | schema.execute(self.query) 188 | self.assertEquals(Provider.objects.all().count(), oldCount - 1) 189 | -------------------------------------------------------------------------------- /netbox_graphql/tests/circuits/tests_terminations.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from netbox_graphql.schema import schema 7 | from netbox_graphql.tests.utils import obj_to_global_id 8 | from netbox_graphql.tests.factories.circuit_factories import CircuitTerminationFactory, CircuitFactory 9 | from netbox_graphql.tests.factories.dcim_factories import SiteFactory 10 | 11 | from circuits.models import CircuitTermination 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.circuit = CircuitFactory() 18 | cls.site = SiteFactory() 19 | 20 | cls.query = Template(''' 21 | mutation { 22 | newCircuitTermination(input: {circuit: "$circuitId", portSpeed: 128, 23 | termSide:"A", upstreamSpeed: 128, site:"$siteId" }) { 24 | circuitTermination { 25 | circuit { 26 | cid 27 | } 28 | portSpeed 29 | termSide 30 | upstreamSpeed 31 | site { 32 | name 33 | } 34 | } 35 | } 36 | } 37 | ''').substitute(circuitId=obj_to_global_id(cls.circuit), 38 | siteId=obj_to_global_id(cls.site)) 39 | 40 | def test_creating_returns_no_error(self): 41 | result = schema.execute(self.query) 42 | assert not result.errors 43 | 44 | def test_creating_returns_data(self): 45 | expected = {'newCircuitTermination': 46 | {'circuitTermination': {'circuit': {'cid': self.circuit.cid}, 47 | 'portSpeed': 128, 48 | 'termSide': 'A', 49 | 'upstreamSpeed': 128, 50 | 'site': {'name': self.site.name} 51 | } 52 | }} 53 | result = schema.execute(self.query) 54 | self.assertEquals(result.data, expected) 55 | 56 | def test_creating_creates_it(self): 57 | oldCount = CircuitTermination.objects.all().count() 58 | schema.execute(self.query) 59 | self.assertEquals( 60 | CircuitTermination.objects.all().count(), oldCount + 1) 61 | 62 | 63 | class QueryMultipleTestCase(TestCase): 64 | @classmethod 65 | def setUpTestData(cls): 66 | cls.first = CircuitTerminationFactory() 67 | cls.second = CircuitTerminationFactory(site=cls.first.site) 68 | cls.query = ''' 69 | { 70 | circuitTerminations { 71 | edges { 72 | node { 73 | id 74 | site { 75 | id 76 | } 77 | circuit { 78 | id 79 | } 80 | } 81 | } 82 | } 83 | } 84 | ''' 85 | 86 | def test_querying_all_returns_no_error(self): 87 | result = schema.execute(self.query) 88 | assert not result.errors 89 | 90 | def test_querying_all_returns_two_results(self): 91 | result = schema.execute(self.query) 92 | self.assertEquals(len(result.data['circuitTerminations']['edges']), 2) 93 | 94 | 95 | class QuerySingleTestCase(TestCase): 96 | @classmethod 97 | def setUpTestData(cls): 98 | cls.first = CircuitTerminationFactory() 99 | cls.query = Template(''' 100 | { 101 | circuitTerminations(id: "$id") { 102 | edges { 103 | node { 104 | site { 105 | name 106 | } 107 | circuit { 108 | cid 109 | } 110 | } 111 | } 112 | } 113 | } 114 | ''').substitute(id=obj_to_global_id(cls.first)) 115 | 116 | def test_querying_single_provider_returns_no_error(self): 117 | result = schema.execute(self.query) 118 | assert not result.errors 119 | 120 | def test_querying_single_provider_returns_result(self): 121 | result = schema.execute(self.query) 122 | self.assertEquals(len(result.data['circuitTerminations']['edges']), 1) 123 | 124 | def test_querying_single_provider_returns_expected_result(self): 125 | result = schema.execute(self.query) 126 | expected = {'circuitTerminations': 127 | {'edges': [ 128 | {'node': {'site': {'name': self.first.site.name}, 129 | 'circuit': {'cid': self.first.circuit.cid}, 130 | }} 131 | ]}} 132 | self.assertEquals(result.data, expected) 133 | 134 | 135 | class UpdateTestCase(TestCase): 136 | @classmethod 137 | def setUpTestData(cls): 138 | cls.first = CircuitTerminationFactory() 139 | cls.query = Template(''' 140 | mutation { 141 | updateCircuitTermination(input: {id: "$id", portSpeed: 512, termSide: "Z", upstreamSpeed: 512}) { 142 | circuitTermination { 143 | termSide 144 | portSpeed 145 | upstreamSpeed 146 | } 147 | } 148 | } 149 | ''').substitute(id=obj_to_global_id(cls.first)) 150 | 151 | def test_updating_returns_no_error(self): 152 | result = schema.execute(self.query) 153 | assert not result.errors 154 | 155 | def test_updating_doesnt_change_count(self): 156 | oldCount = CircuitTermination.objects.all().count() 157 | schema.execute(self.query) 158 | self.assertEquals(CircuitTermination.objects.all().count(), oldCount) 159 | 160 | def test_updating_returns_updated_data(self): 161 | expected = {'updateCircuitTermination': 162 | {'circuitTermination': 163 | {'termSide': 'Z', 164 | 'portSpeed': 512, 165 | 'upstreamSpeed': 512} 166 | }} 167 | result = schema.execute(self.query) 168 | self.assertEquals(result.data, expected) 169 | 170 | def test_updating_alters_data(self): 171 | schema.execute(self.query) 172 | circuit_termination = CircuitTermination.objects.get(id=self.first.id) 173 | self.assertEquals(circuit_termination.term_side, 'Z') 174 | self.assertEquals(circuit_termination.upstream_speed, 512) 175 | 176 | 177 | class DeleteTestCase(TestCase): 178 | @classmethod 179 | def setUpTestData(cls): 180 | cls.first = CircuitTerminationFactory() 181 | cls.query = Template(''' 182 | mutation { 183 | deleteCircuitTermination(input: {id: "$id" }) { 184 | circuitTermination { 185 | id 186 | } 187 | } 188 | } 189 | ''').substitute(id=obj_to_global_id(cls.first)) 190 | 191 | def test_deleting_returns_no_error(self): 192 | result = schema.execute(self.query) 193 | assert not result.errors 194 | 195 | def test_deleting_removes_a_type(self): 196 | oldCount = CircuitTermination.objects.all().count() 197 | schema.execute(self.query) 198 | self.assertEquals( 199 | CircuitTermination.objects.all().count(), oldCount - 1) 200 | -------------------------------------------------------------------------------- /netbox_graphql/tests/circuits/tests_types.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from circuits.models import CircuitType 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.circuit_factories import CircuitTypeFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.query = ''' 18 | mutation { 19 | newCircuitType(input: {name: "Typename", slug: "typeslug"}) { 20 | circuitType { 21 | name 22 | slug 23 | } 24 | } 25 | } 26 | ''' 27 | 28 | def test_creating_circuit_type_returns_no_error(self): 29 | result = schema.execute(self.query) 30 | assert not result.errors 31 | 32 | def test_creating_circuit_type_returns_data(self): 33 | expected = {'newCircuitType': 34 | {'circuitType': {'name': 'Typename', 'slug': 'typeslug'}}} 35 | 36 | result = schema.execute(self.query) 37 | self.assertEquals(result.data, expected) 38 | 39 | def test_creating_circut_type_creates_it(self): 40 | oldCount = CircuitType.objects.all().count() 41 | schema.execute(self.query) 42 | self.assertEquals(CircuitType.objects.all().count(), oldCount + 1) 43 | 44 | 45 | class QueryMultipleTestCase(TestCase): 46 | @classmethod 47 | def setUpTestData(cls): 48 | cls.first = CircuitTypeFactory() 49 | cls.second = CircuitTypeFactory() 50 | cls.query = ''' 51 | query {circuitTypes { 52 | edges { 53 | node { 54 | id 55 | name 56 | slug 57 | } 58 | } 59 | }} 60 | ''' 61 | 62 | def test_querying_all_returns_no_error(self): 63 | result = schema.execute(self.query) 64 | assert not result.errors 65 | 66 | def test_querying_all_returns_two_results(self): 67 | result = schema.execute(self.query) 68 | self.assertEquals(len(result.data['circuitTypes']['edges']), 2) 69 | 70 | 71 | class QuerySingleTestCase(TestCase): 72 | @classmethod 73 | def setUpTestData(cls): 74 | cls.first = CircuitTypeFactory() 75 | cls.second = CircuitTypeFactory() 76 | 77 | cls.query = Template(''' 78 | { 79 | circuitTypes(id: "$id") { 80 | edges { 81 | node { 82 | name 83 | slug 84 | } 85 | } 86 | } 87 | } 88 | ''').substitute(id=obj_to_global_id(cls.first)) 89 | 90 | def test_querying_single_returns_no_error(self): 91 | result = schema.execute(self.query) 92 | assert not result.errors 93 | 94 | def test_querying_single_returns_result(self): 95 | result = schema.execute(self.query) 96 | self.assertEquals(len(result.data['circuitTypes']['edges']), 1) 97 | 98 | def test_querying_single_returns_expected_result(self): 99 | result = schema.execute(self.query) 100 | expected = {'circuitTypes': 101 | {'edges': [ 102 | {'node': {'name': self.first.name, 'slug': self.first.slug}} 103 | ]} 104 | } 105 | self.assertEquals(result.data, expected) 106 | 107 | 108 | class UpdateTestCase(TestCase): 109 | @classmethod 110 | def setUpTestData(cls): 111 | cls.first = CircuitTypeFactory() 112 | cls.query = Template(''' 113 | mutation { 114 | updateCircuitType(input: {id:"$id", name: "New Name", slug: "nsl1"}) { 115 | circuitType { 116 | name 117 | slug 118 | } 119 | } 120 | } 121 | ''').substitute(id=obj_to_global_id(cls.first)) 122 | 123 | def test_updating_returns_no_error(self): 124 | result = schema.execute(self.query) 125 | assert not result.errors 126 | 127 | def test_updating_doesnt_change_count(self): 128 | oldCount = CircuitType.objects.all().count() 129 | schema.execute(self.query) 130 | self.assertEquals(CircuitType.objects.all().count(), oldCount) 131 | 132 | def test_updating_returns_updated_data(self): 133 | expected = {'updateCircuitType': 134 | {'circuitType': {'name': 'New Name', 'slug': 'nsl1'}}} 135 | result = schema.execute(self.query) 136 | self.assertEquals(result.data, expected) 137 | 138 | def test_updating_alters_data(self): 139 | schema.execute(self.query) 140 | circuit_type = CircuitType.objects.get(id=self.first.id) 141 | self.assertEquals(circuit_type.name, 'New Name') 142 | self.assertEquals(circuit_type.slug, 'nsl1') 143 | 144 | 145 | class DeleteTestCase(TestCase): 146 | @classmethod 147 | def setUpTestData(cls): 148 | cls.first = CircuitTypeFactory() 149 | cls.query = Template(''' 150 | mutation { 151 | deleteCircuitType(input: {id:"$id"}) { 152 | circuitType { 153 | name 154 | slug 155 | } 156 | } 157 | } 158 | ''').substitute(id=obj_to_global_id(cls.first)) 159 | 160 | def test_deleting_returns_no_error(self): 161 | result = schema.execute(self.query) 162 | assert not result.errors 163 | 164 | def test_deleting_removes_a_type(self): 165 | oldCount = CircuitType.objects.all().count() 166 | schema.execute(self.query) 167 | self.assertEquals(CircuitType.objects.all().count(), oldCount - 1) 168 | -------------------------------------------------------------------------------- /netbox_graphql/tests/dcim/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/dcim/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/dcim/tests_regions.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from dcim.models import Region 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.dcim_factories import RegionFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.parent = RegionFactory() 18 | cls.query = Template(''' 19 | mutation{ 20 | newRegion(input: { parent:"$parentId", name: "New Name", slug: "nsl1"}) { 21 | region{ 22 | name 23 | slug 24 | parent{ 25 | name 26 | } 27 | } 28 | } 29 | } 30 | ''').substitute(parentId=obj_to_global_id(cls.parent)) 31 | 32 | def test_creating_returns_no_error(self): 33 | result = schema.execute(self.query) 34 | assert not result.errors 35 | 36 | def test_creating_returns_data(self): 37 | expected = {'newRegion': 38 | {'region': {'name': 'New Name', 39 | 'slug': "nsl1", 40 | 'parent': {'name': self.parent.name}}}} 41 | 42 | result = schema.execute(self.query) 43 | self.assertEquals(result.data, expected) 44 | 45 | def test_creating_creates_it(self): 46 | oldCount = Region.objects.all().count() 47 | schema.execute(self.query) 48 | self.assertEquals(Region.objects.all().count(), oldCount + 1) 49 | 50 | 51 | class QueryMultipleTestCase(TestCase): 52 | @classmethod 53 | def setUpTestData(cls): 54 | cls.first = RegionFactory() 55 | cls.second = RegionFactory() 56 | cls.query = ''' 57 | { 58 | regions { 59 | edges { 60 | node { 61 | id 62 | } 63 | } 64 | } 65 | } 66 | ''' 67 | 68 | def test_querying_all_returns_no_error(self): 69 | result = schema.execute(self.query) 70 | assert not result.errors 71 | 72 | def test_querying_all_returns_two_results(self): 73 | result = schema.execute(self.query) 74 | self.assertEquals(len(result.data['regions']['edges']), 2) 75 | 76 | 77 | class QuerySingleTestCase(TestCase): 78 | @classmethod 79 | def setUpTestData(cls): 80 | cls.first = RegionFactory() 81 | cls.second = RegionFactory() 82 | cls.query = Template(''' 83 | { 84 | regions(id: "$id") { 85 | edges { 86 | node { 87 | name 88 | slug 89 | } 90 | } 91 | } 92 | } 93 | ''').substitute(id=obj_to_global_id(cls.first)) 94 | 95 | def test_querying_single_returns_no_error(self): 96 | result = schema.execute(self.query) 97 | assert not result.errors 98 | 99 | def test_querying_single_returns_result(self): 100 | result = schema.execute(self.query) 101 | self.assertEquals(len(result.data['regions']['edges']), 1) 102 | 103 | def test_querying_single_returns_expected_result(self): 104 | result = schema.execute(self.query) 105 | expected = {'regions': 106 | {'edges': [ 107 | {'node': {'name': self.first.name, 108 | 'slug': self.first.slug}} 109 | ]}} 110 | self.assertEquals(result.data, expected) 111 | 112 | 113 | class UpdateTestCase(TestCase): 114 | @classmethod 115 | def setUpTestData(cls): 116 | cls.first = RegionFactory() 117 | cls.parent = RegionFactory() 118 | cls.query = Template(''' 119 | mutation{ 120 | updateRegion(input: { id:"$id", parent:"$parentId", slug: "nsl1"}) { 121 | region{ 122 | slug 123 | parent{ 124 | name 125 | } 126 | } 127 | } 128 | } 129 | ''').substitute(id=obj_to_global_id(cls.first), 130 | parentId=obj_to_global_id(cls.parent)) 131 | 132 | def test_updating_returns_no_error(self): 133 | result = schema.execute(self.query) 134 | assert not result.errors 135 | 136 | def test_updating_doesnt_change_count(self): 137 | oldCount = Region.objects.all().count() 138 | schema.execute(self.query) 139 | self.assertEquals(Region.objects.all().count(), oldCount) 140 | 141 | def test_updating_returns_updated_data(self): 142 | expected = {'updateRegion': 143 | {'region': {'slug': 'nsl1', 144 | 'parent': {'name': self.parent.name}}}} 145 | result = schema.execute(self.query) 146 | self.assertEquals(result.data, expected) 147 | 148 | def test_updating_alters_data(self): 149 | schema.execute(self.query) 150 | region = Region.objects.get(id=self.first.id) 151 | self.assertEquals(region.slug, 'nsl1') 152 | self.assertEquals(region.parent.name, self.parent.name) 153 | 154 | 155 | class DeleteTestCase(TestCase): 156 | @classmethod 157 | def setUpTestData(cls): 158 | cls.first = RegionFactory() 159 | cls.query = Template(''' 160 | mutation{ 161 | deleteRegion(input: { id:"$id"}) { 162 | region{ 163 | id 164 | } 165 | } 166 | } 167 | ''').substitute(id=obj_to_global_id(cls.first)) 168 | 169 | def test_deleting_returns_no_error(self): 170 | result = schema.execute(self.query) 171 | assert not result.errors 172 | 173 | def test_deleting_removes_a_type(self): 174 | oldCount = Region.objects.all().count() 175 | schema.execute(self.query) 176 | self.assertEquals(Region.objects.all().count(), oldCount - 1) 177 | -------------------------------------------------------------------------------- /netbox_graphql/tests/dcim/tests_sites.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from dcim.models import Site 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.dcim_factories import SiteFactory, RegionFactory 12 | from netbox_graphql.tests.factories.tenant_factories import TenantFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.region = RegionFactory() 19 | cls.tenant = TenantFactory() 20 | cls.query = Template(''' 21 | mutation{ 22 | newSite(input: { name:"New Name", slug: "nsl1", region:"$regionId", tenant: "$tenantId"}) { 23 | site { 24 | name 25 | slug 26 | region { 27 | name 28 | } 29 | tenant { 30 | name 31 | } 32 | } 33 | } 34 | } 35 | ''').substitute(regionId=obj_to_global_id(cls.region), 36 | tenantId=obj_to_global_id(cls.tenant)) 37 | 38 | def test_creating_returns_no_error(self): 39 | result = schema.execute(self.query) 40 | assert not result.errors 41 | 42 | def test_creating_returns_data(self): 43 | expected = {'newSite': 44 | {'site': {'name': 'New Name', 45 | 'slug': "nsl1", 46 | 'region': {'name': self.region.name}, 47 | 'tenant': {'name': self.tenant.name}}}} 48 | 49 | result = schema.execute(self.query) 50 | self.assertEquals(result.data, expected) 51 | 52 | def test_creating_creates_it(self): 53 | oldCount = Site.objects.all().count() 54 | schema.execute(self.query) 55 | self.assertEquals(Site.objects.all().count(), oldCount + 1) 56 | 57 | 58 | class QueryMultipleTestCase(TestCase): 59 | @classmethod 60 | def setUpTestData(cls): 61 | cls.first = SiteFactory() 62 | cls.second = SiteFactory() 63 | cls.query = ''' 64 | { 65 | sites { 66 | edges { 67 | node { 68 | id 69 | } 70 | } 71 | } 72 | } 73 | ''' 74 | 75 | def test_querying_all_returns_no_error(self): 76 | result = schema.execute(self.query) 77 | assert not result.errors 78 | 79 | def test_querying_all_returns_two_results(self): 80 | result = schema.execute(self.query) 81 | self.assertEquals(len(result.data['sites']['edges']), 2) 82 | 83 | 84 | class QuerySingleTestCase(TestCase): 85 | @classmethod 86 | def setUpTestData(cls): 87 | cls.first = SiteFactory() 88 | cls.second = SiteFactory() 89 | cls.query = Template(''' 90 | { 91 | sites(id: "$id") { 92 | edges { 93 | node { 94 | name 95 | region { 96 | name 97 | } 98 | } 99 | } 100 | } 101 | } 102 | ''').substitute(id=obj_to_global_id(cls.first)) 103 | 104 | def test_querying_single_returns_no_error(self): 105 | result = schema.execute(self.query) 106 | assert not result.errors 107 | 108 | def test_querying_single_returns_result(self): 109 | result = schema.execute(self.query) 110 | self.assertEquals(len(result.data['sites']['edges']), 1) 111 | 112 | def test_querying_single_returns_expected_result(self): 113 | result = schema.execute(self.query) 114 | expected = {'sites': 115 | {'edges': [ 116 | {'node': {'name': self.first.name, 117 | 'region': {'name': self.first.region.name}}} 118 | ]}} 119 | self.assertEquals(result.data, expected) 120 | 121 | 122 | class UpdateTestCase(TestCase): 123 | @classmethod 124 | def setUpTestData(cls): 125 | cls.first = SiteFactory() 126 | cls.tenant = TenantFactory() 127 | cls.query = Template(''' 128 | mutation{ 129 | updateSite(input: { id: "$id" name:"New Name", tenant: "$tenantId"}) { 130 | site { 131 | name 132 | tenant { 133 | name 134 | } 135 | } 136 | } 137 | } 138 | ''').substitute(id=obj_to_global_id(cls.first), 139 | tenantId=obj_to_global_id(cls.tenant)) 140 | 141 | def test_updating_returns_no_error(self): 142 | result = schema.execute(self.query) 143 | assert not result.errors 144 | 145 | def test_updating_doesnt_change_count(self): 146 | oldCount = Site.objects.all().count() 147 | schema.execute(self.query) 148 | self.assertEquals(Site.objects.all().count(), oldCount) 149 | 150 | def test_updating_returns_updated_data(self): 151 | expected = {'updateSite': 152 | {'site': {'name': 'New Name', 153 | 'tenant': {'name': self.tenant.name}}}} 154 | result = schema.execute(self.query) 155 | self.assertEquals(result.data, expected) 156 | 157 | def test_updating_alters_data(self): 158 | schema.execute(self.query) 159 | site = Site.objects.get(id=self.first.id) 160 | self.assertEquals(site.name, 'New Name') 161 | self.assertEquals(site.tenant.name, self.tenant.name) 162 | 163 | 164 | class DeleteTestCase(TestCase): 165 | @classmethod 166 | def setUpTestData(cls): 167 | cls.first = SiteFactory() 168 | cls.query = Template(''' 169 | mutation{ 170 | deleteSite(input: { id:"$id" }) { 171 | site { 172 | id 173 | } 174 | } 175 | } 176 | ''').substitute(id=obj_to_global_id(cls.first)) 177 | 178 | def test_deleting_returns_no_error(self): 179 | result = schema.execute(self.query) 180 | assert not result.errors 181 | 182 | def test_deleting_removes_a_type(self): 183 | oldCount = Site.objects.all().count() 184 | schema.execute(self.query) 185 | self.assertEquals(Site.objects.all().count(), oldCount - 1) 186 | -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/factories/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/circuit_factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | import datetime 3 | 4 | from . import tenant_factories, dcim_factories 5 | from circuits.models import CircuitType, Circuit, Provider, CircuitTermination 6 | 7 | 8 | class ProviderFactory(factory.django.DjangoModelFactory): 9 | class Meta: 10 | model = Provider 11 | 12 | id = factory.Sequence(lambda n: n) 13 | name = factory.LazyAttribute(lambda o: 'Provider %i' % o.id) 14 | slug = factory.LazyAttribute(lambda o: 'p%i' % o.id) 15 | asn = 29691.0 16 | account = '12345' 17 | portal_url = 'https://nine.ch' 18 | noc_contact = 'noc@postmaster.com' 19 | admin_contact = 'admin@postmaster.com' 20 | comments = 'Awesome Comment!' 21 | 22 | 23 | class CircuitTypeFactory(factory.django.DjangoModelFactory): 24 | class Meta: 25 | model = CircuitType 26 | 27 | id = factory.Sequence(lambda n: n) 28 | name = factory.LazyAttribute(lambda o: 'Type %i' % o.id) 29 | slug = factory.LazyAttribute(lambda o: 'ct%i' % o.id) 30 | 31 | 32 | class CircuitFactory(factory.django.DjangoModelFactory): 33 | class Meta: 34 | model = Circuit 35 | 36 | id = factory.Sequence(lambda n: n) 37 | cid = factory.LazyAttribute(lambda o: 'cid%i' % o.id) 38 | provider = factory.SubFactory(ProviderFactory) 39 | type = factory.SubFactory(CircuitTypeFactory) 40 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 41 | install_date = datetime.date(2008, 1, 1) 42 | commit_rate = 1024 43 | description = "I'm an awesome circuit!" 44 | comments = "This is an awesome comment :)" 45 | 46 | 47 | class CircuitTerminationFactory(factory.django.DjangoModelFactory): 48 | class Meta: 49 | model = CircuitTermination 50 | 51 | id = factory.Sequence(lambda n: n) 52 | circuit = factory.SubFactory(CircuitFactory) 53 | term_side = 'A' 54 | site = factory.SubFactory(dcim_factories.SiteFactory) 55 | interface = factory.SubFactory(dcim_factories.InterfaceFactory) 56 | port_speed = 128 57 | upstream_speed = 64 58 | xconnect_id = 1 59 | pp_info = "Patchy, patchy" 60 | -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/dcim_factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from . import tenant_factories 3 | from dcim.models import Region, Site, Interface, DeviceRole, Platform 4 | 5 | 6 | class RegionFactory(factory.django.DjangoModelFactory): 7 | class Meta: 8 | model = Region 9 | 10 | id = factory.Sequence(lambda n: n) 11 | name = factory.LazyAttribute(lambda o: 'Region %i' % o.id) 12 | slug = factory.LazyAttribute(lambda o: 'r%i' % o.id) 13 | 14 | 15 | class SiteFactory(factory.django.DjangoModelFactory): 16 | class Meta: 17 | model = Site 18 | 19 | id = factory.Sequence(lambda n: n) 20 | name = factory.LazyAttribute(lambda o: 'Site %i' % o.id) 21 | slug = factory.LazyAttribute(lambda o: 's%i' % o.id) 22 | region = factory.SubFactory(RegionFactory) 23 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 24 | facility = "DC" 25 | asn = 10.0 26 | physical_address = "Planet Nano" 27 | shipping_address = "Skywalker Corp." 28 | contact_name = "Luke Skywalker" 29 | contact_phone = "+00" 30 | contact_email = "luke@skywalkerink.com" 31 | comments = "Awesome Comment!" 32 | 33 | 34 | class InterfaceFactory(factory.django.DjangoModelFactory): 35 | class Meta: 36 | model = Interface 37 | 38 | id = factory.Sequence(lambda n: n) 39 | # device = 40 | # virtual_machine = # http://factoryboy.readthedocs.io/en/latest/reference.html#circular-imports 41 | # lag = 42 | name = factory.LazyAttribute(lambda o: 'Interface %i' % o.id) 43 | # mac_address = 44 | # mtu = 45 | # mtu = 46 | description = "I'm an awesome interface!" 47 | 48 | 49 | class DeviceRoleFactory(factory.django.DjangoModelFactory): 50 | class Meta: 51 | model = DeviceRole 52 | 53 | id = factory.Sequence(lambda n: n) 54 | name = factory.LazyAttribute(lambda o: 'DeviceRole %i' % o.id) 55 | slug = factory.LazyAttribute(lambda o: 'dr%i' % o.id) 56 | vm_role = False 57 | 58 | 59 | class PlatformFactory(factory.django.DjangoModelFactory): 60 | class Meta: 61 | model = Platform 62 | 63 | id = factory.Sequence(lambda n: n) 64 | name = factory.LazyAttribute(lambda o: 'Platform %i' % o.id) 65 | slug = factory.LazyAttribute(lambda o: 'p%i' % o.id) 66 | napalm_driver = 'ABCX13' 67 | # rpc_client = 68 | -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/ipam_factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | import datetime 3 | 4 | import netaddr 5 | 6 | from . import tenant_factories, dcim_factories 7 | from ipam.models import VRF, RIR, Aggregate, Role, IPAddress, VLANGroup, VLAN, Prefix 8 | from ipam.fields import IPAddressField 9 | 10 | 11 | class VRFFactory(factory.django.DjangoModelFactory): 12 | class Meta: 13 | model = VRF 14 | 15 | id = factory.Sequence(lambda n: n) 16 | name = factory.LazyAttribute(lambda o: 'VRF %i' % o.id) 17 | rd = factory.LazyAttribute(lambda o: 'rd%i' % o.id) 18 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 19 | enforce_unique = True 20 | description = "This is a VRF!" 21 | 22 | 23 | class RIRFactory(factory.django.DjangoModelFactory): 24 | class Meta: 25 | model = RIR 26 | 27 | id = factory.Sequence(lambda n: n) 28 | name = factory.LazyAttribute(lambda o: 'RIR %i' % o.id) 29 | slug = factory.LazyAttribute(lambda o: 'rir%i' % o.id) 30 | is_private = False 31 | 32 | 33 | class AggreagateFactory(factory.django.DjangoModelFactory): 34 | class Meta: 35 | model = Aggregate 36 | 37 | family = 4 38 | prefix = netaddr.IPNetwork('10.0.0.0/12') 39 | rir = factory.SubFactory(RIRFactory) 40 | date_added = datetime.date(2008, 1, 1) 41 | description = "I'm an Aggregate!" 42 | 43 | 44 | class RoleFactory(factory.django.DjangoModelFactory): 45 | class Meta: 46 | model = Role 47 | 48 | id = factory.Sequence(lambda n: n) 49 | name = factory.LazyAttribute(lambda o: 'Role %i' % o.id) 50 | slug = factory.LazyAttribute(lambda o: 'r%i' % o.id) 51 | weight = 1000 52 | 53 | 54 | class IPAddressFactory(factory.django.DjangoModelFactory): 55 | class Meta: 56 | model = IPAddress 57 | 58 | family = 4 59 | address = netaddr.IPAddress('127.0.0.1') 60 | vrf = factory.SubFactory(VRFFactory) 61 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 62 | # status = 63 | # role = 64 | # interface = 65 | # nat_inside = 66 | description = "I'm an IPAddress!" 67 | 68 | 69 | class VLANGroupFactory(factory.django.DjangoModelFactory): 70 | class Meta: 71 | model = VLANGroup 72 | 73 | id = factory.Sequence(lambda n: n) 74 | name = factory.LazyAttribute(lambda o: 'VLANGroup %i' % o.id) 75 | slug = factory.LazyAttribute(lambda o: 'vg%i' % o.id) 76 | site = factory.SubFactory(dcim_factories.SiteFactory) 77 | 78 | 79 | class VLANFactory(factory.django.DjangoModelFactory): 80 | class Meta: 81 | model = VLAN 82 | 83 | id = factory.Sequence(lambda n: n) 84 | site = factory.SubFactory(dcim_factories.SiteFactory) 85 | group = factory.SubFactory(VLANGroupFactory) 86 | site = factory.LazyAttribute(lambda o: o.group.site) 87 | vid = 1 88 | name = factory.LazyAttribute(lambda o: 'VLAN %i' % o.id) 89 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 90 | # status = 91 | role = factory.SubFactory(RoleFactory) 92 | description = "I'm a VLAN!" 93 | 94 | 95 | class PrefixFactory(factory.django.DjangoModelFactory): 96 | class Meta: 97 | model = Prefix 98 | 99 | # family = 100 | prefix = netaddr.IPNetwork('192.0.2.0/24') 101 | site = factory.SubFactory(dcim_factories.SiteFactory) 102 | vrf = factory.SubFactory(VRFFactory) 103 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 104 | # vlan = 105 | # status = 106 | role = factory.SubFactory(RoleFactory) 107 | is_pool = False 108 | description = "I'm a Prefix!" 109 | -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/tenant_factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from tenancy.models import Tenant, TenantGroup 3 | 4 | 5 | class TenantGroupFactory(factory.django.DjangoModelFactory): 6 | class Meta: 7 | model = TenantGroup 8 | 9 | id = factory.Sequence(lambda n: n) 10 | name = factory.LazyAttribute(lambda o: 'Tenant Group %i' % o.id) 11 | slug = factory.LazyAttribute(lambda o: 'tg%i' % o.id) 12 | 13 | 14 | class TenantFactory(factory.django.DjangoModelFactory): 15 | class Meta: 16 | model = Tenant 17 | 18 | id = factory.Sequence(lambda n: n) 19 | name = factory.LazyAttribute(lambda o: 'Tenant %i' % o.id) 20 | slug = factory.LazyAttribute(lambda o: 't%i' % o.id) 21 | group = factory.SubFactory(TenantGroupFactory) 22 | description = "Tenant description!!" 23 | comments = "Tenant comment!!" 24 | -------------------------------------------------------------------------------- /netbox_graphql/tests/factories/virtualization_factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | 3 | from . import dcim_factories, tenant_factories, ipam_factories 4 | from virtualization.models import ClusterType, ClusterGroup, Cluster, VirtualMachine 5 | 6 | 7 | class ClusterTypeFactory(factory.django.DjangoModelFactory): 8 | class Meta: 9 | model = ClusterType 10 | 11 | id = factory.Sequence(lambda n: n) 12 | name = factory.LazyAttribute(lambda o: 'ClusterType %i' % o.id) 13 | slug = factory.LazyAttribute(lambda o: 'ct%i' % o.id) 14 | 15 | 16 | class ClusterGroupFactory(factory.django.DjangoModelFactory): 17 | class Meta: 18 | model = ClusterGroup 19 | 20 | id = factory.Sequence(lambda n: n) 21 | name = factory.LazyAttribute(lambda o: 'ClusterGroup %i' % o.id) 22 | slug = factory.LazyAttribute(lambda o: 'cg%i' % o.id) 23 | 24 | 25 | class ClusterFactory(factory.django.DjangoModelFactory): 26 | class Meta: 27 | model = Cluster 28 | 29 | id = factory.Sequence(lambda n: n) 30 | name = factory.LazyAttribute(lambda o: 'Cluster %i' % o.id) 31 | type = factory.SubFactory(ClusterTypeFactory) 32 | group = factory.SubFactory(ClusterGroupFactory) 33 | site = factory.SubFactory(dcim_factories.SiteFactory) 34 | comments = "This is a cluster comment!" 35 | 36 | 37 | class VirtualMachineFactory(factory.django.DjangoModelFactory): 38 | class Meta: 39 | model = VirtualMachine 40 | 41 | id = factory.Sequence(lambda n: n) 42 | cluster = factory.SubFactory(ClusterFactory) 43 | tenant = factory.SubFactory(tenant_factories.TenantFactory) 44 | platform = factory.SubFactory(dcim_factories.PlatformFactory) 45 | name = factory.LazyAttribute(lambda o: 'VM %i' % o.id) 46 | # status = 47 | role = factory.SubFactory(dcim_factories.DeviceRoleFactory, vm_role=True) 48 | primary_ip4 = factory.SubFactory(ipam_factories.IPAddressFactory) 49 | primary_ip6 = factory.SubFactory(ipam_factories.IPAddressFactory) 50 | vcpus = 4 51 | memory = 4096 52 | disk = 40 53 | comments = "I'm a VM comment!" 54 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/ipam/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_aggregates.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | import datetime 3 | import netaddr 4 | 5 | from graphene.test import Client 6 | from django.test import TestCase 7 | 8 | from ipam.models import Aggregate 9 | 10 | from netbox_graphql.schema import schema 11 | 12 | from netbox_graphql.tests.utils import obj_to_global_id 13 | from netbox_graphql.tests.factories.ipam_factories import AggreagateFactory, RIRFactory 14 | 15 | 16 | class CreateTestCase(TestCase): 17 | @classmethod 18 | def setUpTestData(cls): 19 | cls.rir = RIRFactory() 20 | cls.query = Template(''' 21 | mutation { 22 | newAggregate(input: { family: 4, rir: "$rirId", prefix: "192.0.0.0/12" }) { 23 | aggregate{ 24 | family 25 | prefix 26 | rir { 27 | name 28 | } 29 | } 30 | } 31 | } 32 | ''').substitute(rirId=obj_to_global_id(cls.rir)) 33 | 34 | def test_creating_returns_no_error(self): 35 | result = schema.execute(self.query) 36 | assert not result.errors 37 | 38 | def test_creating_returns_data(self): 39 | expected = {'newAggregate': 40 | {'aggregate': {'family': 'A_4', 41 | 'prefix': '192.0.0.0/12', 42 | 'rir': {'name': self.rir.name}}}} 43 | 44 | result = schema.execute(self.query) 45 | self.assertEquals(result.data, expected) 46 | 47 | def test_creating_creates_it(self): 48 | oldCount = Aggregate.objects.all().count() 49 | schema.execute(self.query) 50 | self.assertEquals(Aggregate.objects.all().count(), oldCount + 1) 51 | 52 | 53 | class QueryMultipleTestCase(TestCase): 54 | @classmethod 55 | def setUpTestData(cls): 56 | cls.first = AggreagateFactory() 57 | cls.second = AggreagateFactory() 58 | cls.query = ''' 59 | { 60 | aggregates { 61 | edges { 62 | node { 63 | id 64 | } 65 | } 66 | } 67 | } 68 | ''' 69 | 70 | def test_querying_all_returns_no_error(self): 71 | result = schema.execute(self.query) 72 | assert not result.errors 73 | 74 | def test_querying_all_returns_two_results(self): 75 | result = schema.execute(self.query) 76 | self.assertEquals(len(result.data['aggregates']['edges']), 2) 77 | 78 | 79 | class QuerySingleTestCase(TestCase): 80 | @classmethod 81 | def setUpTestData(cls): 82 | cls.first = AggreagateFactory() 83 | cls.second = AggreagateFactory() 84 | cls.query = Template(''' 85 | { 86 | aggregates(id: "$id") { 87 | edges { 88 | node { 89 | family 90 | prefix 91 | rir { 92 | name 93 | } 94 | } 95 | } 96 | } 97 | } 98 | ''').substitute(id=obj_to_global_id(cls.first)) 99 | 100 | def test_querying_single_returns_no_error(self): 101 | result = schema.execute(self.query) 102 | assert not result.errors 103 | 104 | def test_querying_single_returns_result(self): 105 | result = schema.execute(self.query) 106 | self.assertEquals(len(result.data['aggregates']['edges']), 1) 107 | 108 | def test_querying_single_returns_expected_result(self): 109 | result = schema.execute(self.query) 110 | expected = {'aggregates': 111 | {'edges': [ 112 | {'node': {'family': 'A_4', 113 | 'prefix': str(self.first.prefix), 114 | 'rir': {'name': self.first.rir.name}}} 115 | ]}} 116 | self.assertEquals(result.data, expected) 117 | 118 | 119 | class UpdateTestCase(TestCase): 120 | @classmethod 121 | def setUpTestData(cls): 122 | cls.first = AggreagateFactory() 123 | cls.query = Template(''' 124 | mutation{ 125 | updateAggregate(input: { id: "$id", dateAdded: "2017-01-01", prefix: "54.0.0.0/8"}) { 126 | aggregate{ 127 | prefix 128 | dateAdded 129 | } 130 | } 131 | } 132 | ''').substitute(id=obj_to_global_id(cls.first)) 133 | 134 | def test_updating_returns_no_error(self): 135 | result = schema.execute(self.query) 136 | assert not result.errors 137 | 138 | def test_updating_doesnt_change_count(self): 139 | oldCount = Aggregate.objects.all().count() 140 | schema.execute(self.query) 141 | self.assertEquals(Aggregate.objects.all().count(), oldCount) 142 | 143 | def test_updating_returns_updated_data(self): 144 | expected = {'updateAggregate': 145 | {'aggregate': {'prefix': '54.0.0.0/8', 146 | 'dateAdded': '2017-01-01'}}} 147 | result = schema.execute(self.query) 148 | self.assertEquals(result.data, expected) 149 | 150 | def test_updating_alters_data(self): 151 | schema.execute(self.query) 152 | aggregate = Aggregate.objects.get(id=self.first.id) 153 | self.assertEquals(aggregate.prefix, netaddr.IPNetwork('54.0.0.0/8')) 154 | self.assertEquals(aggregate.date_added, datetime.date(2017, 1, 1)) 155 | 156 | 157 | class DeleteTestCase(TestCase): 158 | @classmethod 159 | def setUpTestData(cls): 160 | cls.first = AggreagateFactory() 161 | cls.query = Template(''' 162 | mutation{ 163 | deleteAggregate(input: { id: "$id"}) { 164 | aggregate{ 165 | id 166 | } 167 | } 168 | } 169 | ''').substitute(id=obj_to_global_id(cls.first)) 170 | 171 | def test_deleting_returns_no_error(self): 172 | result = schema.execute(self.query) 173 | assert not result.errors 174 | 175 | def test_deleting_removes_a_type(self): 176 | oldCount = Aggregate.objects.all().count() 177 | schema.execute(self.query) 178 | self.assertEquals(Aggregate.objects.all().count(), oldCount - 1) 179 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_ip_addresses.py: -------------------------------------------------------------------------------- 1 | 2 | from string import Template 3 | import netaddr 4 | 5 | from graphene.test import Client 6 | from django.test import TestCase 7 | 8 | from ipam.models import IPAddress 9 | 10 | from netbox_graphql.schema import schema 11 | 12 | from netbox_graphql.tests.utils import obj_to_global_id 13 | from netbox_graphql.tests.factories.ipam_factories import IPAddressFactory 14 | 15 | 16 | class CreateTestCase(TestCase): 17 | @classmethod 18 | def setUpTestData(cls): 19 | cls.query = ''' 20 | mutation{ 21 | newIpAddress(input: { address: "173.16.0.0", status: 3}) { 22 | ipAddress{ 23 | family 24 | address 25 | status 26 | } 27 | } 28 | } 29 | ''' 30 | 31 | def test_creating_circuit_type_returns_no_error(self): 32 | result = schema.execute(self.query) 33 | assert not result.errors 34 | 35 | def test_creating_circuit_type_returns_data(self): 36 | expected = {'newIpAddress': 37 | {'ipAddress': {'family': 'A_4', 38 | 'address': '173.16.0.0/32', 39 | 'status': 'A_3'}}} 40 | 41 | result = schema.execute(self.query) 42 | self.assertEquals(result.data, expected) 43 | 44 | def test_creating_circut_type_creates_it(self): 45 | oldCount = IPAddress.objects.all().count() 46 | schema.execute(self.query) 47 | self.assertEquals(IPAddress.objects.all().count(), oldCount + 1) 48 | 49 | 50 | class QueryMultipleTestCase(TestCase): 51 | @classmethod 52 | def setUpTestData(cls): 53 | cls.first = IPAddressFactory() 54 | cls.second = IPAddressFactory() 55 | cls.query = ''' 56 | { ipAddress { 57 | edges { 58 | node { 59 | id 60 | } 61 | } 62 | }} 63 | ''' 64 | 65 | def test_querying_all_returns_no_error(self): 66 | result = schema.execute(self.query) 67 | assert not result.errors 68 | 69 | def test_querying_all_returns_two_results(self): 70 | result = schema.execute(self.query) 71 | self.assertEquals(len(result.data['ipAddress']['edges']), 2) 72 | 73 | 74 | class QuerySingleTestCase(TestCase): 75 | @classmethod 76 | def setUpTestData(cls): 77 | cls.first = IPAddressFactory() 78 | cls.second = IPAddressFactory() 79 | 80 | cls.query = Template(''' 81 | { ipAddress(id: "$id") { 82 | edges { 83 | node { 84 | address 85 | } 86 | } 87 | }} 88 | ''').substitute(id=obj_to_global_id(cls.first)) 89 | 90 | def test_querying_single_returns_no_error(self): 91 | result = schema.execute(self.query) 92 | assert not result.errors 93 | 94 | def test_querying_single_returns_result(self): 95 | result = schema.execute(self.query) 96 | self.assertEquals(len(result.data['ipAddress']['edges']), 1) 97 | 98 | def test_querying_single_returns_expected_result(self): 99 | result = schema.execute(self.query) 100 | expected = {'ipAddress': 101 | {'edges': [ 102 | {'node': {'address': str( 103 | netaddr.IPNetwork(self.first.address))}} 104 | ]} 105 | } 106 | self.assertEquals(result.data, expected) 107 | 108 | 109 | class UpdateTestCase(TestCase): 110 | @classmethod 111 | def setUpTestData(cls): 112 | cls.first = IPAddressFactory() 113 | cls.query = Template(''' 114 | mutation{ 115 | updateIpAddress(input: { id:"$id", address: "192.168.1.1"}) { 116 | ipAddress{ 117 | address 118 | } 119 | } 120 | } 121 | ''').substitute(id=obj_to_global_id(cls.first)) 122 | 123 | def test_updating_returns_no_error(self): 124 | result = schema.execute(self.query) 125 | assert not result.errors 126 | 127 | def test_updating_doesnt_change_count(self): 128 | oldCount = IPAddress.objects.all().count() 129 | schema.execute(self.query) 130 | self.assertEquals(IPAddress.objects.all().count(), oldCount) 131 | 132 | def test_updating_returns_updated_data(self): 133 | expected = {'updateIpAddress': 134 | {'ipAddress': {'address': str(netaddr.IPNetwork('192.168.1.1'))}}} 135 | result = schema.execute(self.query) 136 | self.assertEquals(result.data, expected) 137 | 138 | def test_updating_alters_data(self): 139 | schema.execute(self.query) 140 | ip_address = IPAddress.objects.get(id=self.first.id) 141 | self.assertEquals(ip_address.address, netaddr.IPNetwork('192.168.1.1')) 142 | 143 | 144 | class DeleteTestCase(TestCase): 145 | @classmethod 146 | def setUpTestData(cls): 147 | cls.first = IPAddressFactory() 148 | cls.query = Template(''' 149 | mutation { 150 | deleteIpAddress(input: { id:"$id"}) { 151 | ipAddress{ 152 | id 153 | } 154 | } 155 | } 156 | ''').substitute(id=obj_to_global_id(cls.first)) 157 | 158 | def test_deleting_returns_no_error(self): 159 | result = schema.execute(self.query) 160 | assert not result.errors 161 | 162 | def test_deleting_removes_a_type(self): 163 | oldCount = IPAddress.objects.all().count() 164 | schema.execute(self.query) 165 | self.assertEquals(IPAddress.objects.all().count(), oldCount - 1) 166 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_prefixes.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | import netaddr 3 | 4 | from graphene.test import Client 5 | from django.test import TestCase 6 | 7 | from ipam.models import Prefix 8 | 9 | from netbox_graphql.schema import schema 10 | 11 | from netbox_graphql.tests.utils import obj_to_global_id 12 | from netbox_graphql.tests.factories.ipam_factories import PrefixFactory, VRFFactory, RoleFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.vrf = VRFFactory() 19 | cls.role = RoleFactory() 20 | cls.query = Template(''' 21 | mutation{ 22 | newPrefix(input: { prefix: "173.16.0.0/12", vrf: "$vrfId", 23 | role: "$roleId", status: 2, isPool: false}) { 24 | prefix{ 25 | prefix 26 | status 27 | isPool 28 | vrf { 29 | name 30 | } 31 | role { 32 | name 33 | } 34 | } 35 | } 36 | } 37 | ''').substitute(roleId=obj_to_global_id(cls.role), 38 | vrfId=obj_to_global_id(cls.vrf)) 39 | 40 | def test_creating_returns_no_error(self): 41 | result = schema.execute(self.query) 42 | assert not result.errors 43 | 44 | def test_creating_returns_data(self): 45 | expected = {'newPrefix': 46 | {'prefix': {'prefix': '173.16.0.0/12', 47 | 'status': "A_2", 48 | 'isPool': False, 49 | 'vrf': {'name': self.vrf.name}, 50 | 'role': {'name': self.role.name}}}} 51 | 52 | result = schema.execute(self.query) 53 | self.assertEquals(result.data, expected) 54 | 55 | def test_creating_creates_it(self): 56 | oldCount = Prefix.objects.all().count() 57 | schema.execute(self.query) 58 | self.assertEquals(Prefix.objects.all().count(), oldCount + 1) 59 | 60 | 61 | class QueryMultipleTestCase(TestCase): 62 | @classmethod 63 | def setUpTestData(cls): 64 | cls.first = PrefixFactory() 65 | cls.second = PrefixFactory() 66 | cls.query = ''' 67 | { 68 | prefixes { 69 | edges { 70 | node { 71 | id 72 | } 73 | } 74 | } 75 | } 76 | ''' 77 | 78 | def test_querying_all_returns_no_error(self): 79 | result = schema.execute(self.query) 80 | assert not result.errors 81 | 82 | def test_querying_all_returns_two_results(self): 83 | result = schema.execute(self.query) 84 | self.assertEquals(len(result.data['prefixes']['edges']), 2) 85 | 86 | 87 | class QuerySingleTestCase(TestCase): 88 | @classmethod 89 | def setUpTestData(cls): 90 | cls.first = PrefixFactory() 91 | cls.second = PrefixFactory() 92 | cls.query = Template(''' 93 | { 94 | prefixes(id: "$id") { 95 | edges { 96 | node { 97 | prefix 98 | role { 99 | name 100 | } 101 | } 102 | } 103 | } 104 | } 105 | ''').substitute(id=obj_to_global_id(cls.first)) 106 | 107 | def test_querying_single_returns_no_error(self): 108 | result = schema.execute(self.query) 109 | assert not result.errors 110 | 111 | def test_querying_single_returns_result(self): 112 | result = schema.execute(self.query) 113 | self.assertEquals(len(result.data['prefixes']['edges']), 1) 114 | 115 | def test_querying_single_returns_expected_result(self): 116 | result = schema.execute(self.query) 117 | expected = {'prefixes': 118 | {'edges': [ 119 | {'node': {'prefix': str(self.first.prefix.cidr), 120 | 'role': {'name': self.first.role.name}}} 121 | ]}} 122 | self.assertEquals(result.data, expected) 123 | 124 | 125 | class UpdateTestCase(TestCase): 126 | @classmethod 127 | def setUpTestData(cls): 128 | cls.first = PrefixFactory() 129 | cls.query = Template(''' 130 | mutation{ 131 | updatePrefix(input: { id: "$id", prefix: "173.16.0.0/24", isPool: true}) { 132 | prefix{ 133 | prefix 134 | isPool 135 | } 136 | } 137 | } 138 | ''').substitute(id=obj_to_global_id(cls.first)) 139 | 140 | def test_updating_returns_no_error(self): 141 | result = schema.execute(self.query) 142 | assert not result.errors 143 | 144 | def test_updating_doesnt_change_count(self): 145 | oldCount = Prefix.objects.all().count() 146 | schema.execute(self.query) 147 | self.assertEquals(Prefix.objects.all().count(), oldCount) 148 | 149 | def test_updating_returns_updated_data(self): 150 | expected = {'updatePrefix': 151 | {'prefix': {'prefix': '173.16.0.0/24', 152 | 'isPool': True}}} 153 | result = schema.execute(self.query) 154 | self.assertEquals(result.data, expected) 155 | 156 | def test_updating_alters_data(self): 157 | schema.execute(self.query) 158 | prefix = Prefix.objects.get(id=self.first.id) 159 | self.assertEquals(prefix.prefix, netaddr.IPNetwork('173.16.0.0/24')) 160 | self.assertEquals(prefix.is_pool, True) 161 | 162 | 163 | class DeleteTestCase(TestCase): 164 | @classmethod 165 | def setUpTestData(cls): 166 | cls.first = PrefixFactory() 167 | cls.query = Template(''' 168 | mutation{ 169 | deletePrefix(input: {id: "$id"}) { 170 | prefix{ 171 | id 172 | } 173 | } 174 | } 175 | ''').substitute(id=obj_to_global_id(cls.first)) 176 | 177 | def test_deleting_returns_no_error(self): 178 | result = schema.execute(self.query) 179 | assert not result.errors 180 | 181 | def test_deleting_removes_a_type(self): 182 | oldCount = Prefix.objects.all().count() 183 | schema.execute(self.query) 184 | self.assertEquals(Prefix.objects.all().count(), oldCount - 1) 185 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_rirs.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from ipam.models import RIR 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.ipam_factories import RIRFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.query = ''' 18 | mutation{ 19 | newRir(input: { name: "New Name", slug: "rir", isPrivate: true }) { 20 | rir{ 21 | name 22 | slug 23 | isPrivate 24 | } 25 | } 26 | } 27 | ''' 28 | 29 | def test_creating_returns_no_error(self): 30 | result = schema.execute(self.query) 31 | assert not result.errors 32 | 33 | def test_creating_returns_data(self): 34 | expected = {'newRir': 35 | {'rir': {'name': 'New Name', 36 | 'slug': 'rir', 37 | 'isPrivate': True}}} 38 | 39 | result = schema.execute(self.query) 40 | self.assertEquals(result.data, expected) 41 | 42 | def test_creating_creates_it(self): 43 | oldCount = RIR.objects.all().count() 44 | schema.execute(self.query) 45 | self.assertEquals(RIR.objects.all().count(), oldCount + 1) 46 | 47 | 48 | class QueryMultipleTestCase(TestCase): 49 | @classmethod 50 | def setUpTestData(cls): 51 | cls.first = RIRFactory() 52 | cls.second = RIRFactory() 53 | cls.query = ''' 54 | { 55 | rirs { 56 | edges { 57 | node { 58 | id 59 | } 60 | } 61 | } 62 | } 63 | ''' 64 | 65 | def test_querying_all_returns_no_error(self): 66 | result = schema.execute(self.query) 67 | assert not result.errors 68 | 69 | def test_querying_all_returns_two_results(self): 70 | result = schema.execute(self.query) 71 | self.assertEquals(len(result.data['rirs']['edges']), 2) 72 | 73 | 74 | class QuerySingleTestCase(TestCase): 75 | @classmethod 76 | def setUpTestData(cls): 77 | cls.first = RIRFactory() 78 | cls.second = RIRFactory() 79 | cls.query = Template(''' 80 | { 81 | rirs(id: "$id") { 82 | edges { 83 | node { 84 | name 85 | slug 86 | } 87 | } 88 | } 89 | } 90 | ''').substitute(id=obj_to_global_id(cls.first)) 91 | 92 | def test_querying_single_returns_no_error(self): 93 | result = schema.execute(self.query) 94 | assert not result.errors 95 | 96 | def test_querying_single_returns_result(self): 97 | result = schema.execute(self.query) 98 | self.assertEquals(len(result.data['rirs']['edges']), 1) 99 | 100 | def test_querying_single_returns_expected_result(self): 101 | result = schema.execute(self.query) 102 | expected = {'rirs': 103 | {'edges': [ 104 | {'node': {'name': self.first.name, 105 | 'slug': self.first.slug, }} 106 | ]}} 107 | self.assertEquals(result.data, expected) 108 | 109 | 110 | class UpdateTestCase(TestCase): 111 | @classmethod 112 | def setUpTestData(cls): 113 | cls.first = RIRFactory() 114 | cls.query = Template(''' 115 | mutation{ 116 | updateRir(input: { id:"$id", name: "New Name", slug: "nsl1" }) { 117 | rir{ 118 | name 119 | slug 120 | } 121 | } 122 | } 123 | ''').substitute(id=obj_to_global_id(cls.first)) 124 | 125 | def test_updating_returns_no_error(self): 126 | result = schema.execute(self.query) 127 | assert not result.errors 128 | 129 | def test_updating_doesnt_change_count(self): 130 | oldCount = RIR.objects.all().count() 131 | schema.execute(self.query) 132 | self.assertEquals(RIR.objects.all().count(), oldCount) 133 | 134 | def test_updating_returns_updated_data(self): 135 | expected = {'updateRir': 136 | {'rir': {'name': 'New Name', 137 | 'slug': 'nsl1'}}} 138 | result = schema.execute(self.query) 139 | self.assertEquals(result.data, expected) 140 | 141 | def test_updating_alters_data(self): 142 | schema.execute(self.query) 143 | rir = RIR.objects.get(id=self.first.id) 144 | self.assertEquals(rir.name, 'New Name') 145 | self.assertEquals(rir.slug, 'nsl1') 146 | 147 | 148 | class DeleteTestCase(TestCase): 149 | @classmethod 150 | def setUpTestData(cls): 151 | cls.first = RIRFactory() 152 | cls.query = Template(''' 153 | mutation{ 154 | deleteRir(input: { id:"$id" }) { 155 | rir{ 156 | id 157 | } 158 | } 159 | } 160 | ''').substitute(id=obj_to_global_id(cls.first)) 161 | 162 | def test_deleting_returns_no_error(self): 163 | result = schema.execute(self.query) 164 | assert not result.errors 165 | 166 | def test_deleting_removes_a_type(self): 167 | oldCount = RIR.objects.all().count() 168 | schema.execute(self.query) 169 | self.assertEquals(RIR.objects.all().count(), oldCount - 1) 170 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_roles.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from ipam.models import Role 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.ipam_factories import RoleFactory 12 | from netbox_graphql.tests.factories.dcim_factories import SiteFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.query = ''' 19 | mutation{ 20 | newVlanRole(input: { name: "New Name", slug: "nsl1", weight: 1001}) { 21 | vlanRole{ 22 | name 23 | slug 24 | weight 25 | } 26 | } 27 | } 28 | ''' 29 | 30 | def test_creating_returns_no_error(self): 31 | result = schema.execute(self.query) 32 | assert not result.errors 33 | 34 | def test_creating_returns_data(self): 35 | expected = {'newVlanRole': 36 | {'vlanRole': {'name': 'New Name', 37 | 'slug': 'nsl1', 38 | 'weight': 1001}}} 39 | 40 | result = schema.execute(self.query) 41 | self.assertEquals(result.data, expected) 42 | 43 | def test_creating_creates_it(self): 44 | oldCount = Role.objects.all().count() 45 | schema.execute(self.query) 46 | self.assertEquals(Role.objects.all().count(), oldCount + 1) 47 | 48 | 49 | class QueryMultipleTestCase(TestCase): 50 | @classmethod 51 | def setUpTestData(cls): 52 | cls.first = RoleFactory() 53 | cls.second = RoleFactory() 54 | cls.query = ''' 55 | { 56 | vlanRoles { 57 | edges { 58 | node { 59 | id 60 | } 61 | } 62 | } 63 | } 64 | ''' 65 | 66 | def test_querying_all_returns_no_error(self): 67 | result = schema.execute(self.query) 68 | assert not result.errors 69 | 70 | def test_querying_all_returns_two_results(self): 71 | result = schema.execute(self.query) 72 | self.assertEquals(len(result.data['vlanRoles']['edges']), 2) 73 | 74 | 75 | class QuerySingleTestCase(TestCase): 76 | @classmethod 77 | def setUpTestData(cls): 78 | cls.first = RoleFactory() 79 | cls.second = RoleFactory() 80 | cls.query = Template(''' 81 | { 82 | vlanRoles(id: "$id") { 83 | edges { 84 | node { 85 | name 86 | } 87 | } 88 | } 89 | } 90 | ''').substitute(id=obj_to_global_id(cls.second)) 91 | 92 | def test_querying_single_returns_no_error(self): 93 | result = schema.execute(self.query) 94 | assert not result.errors 95 | 96 | def test_querying_single_returns_result(self): 97 | result = schema.execute(self.query) 98 | self.assertEquals(len(result.data['vlanRoles']['edges']), 1) 99 | 100 | def test_querying_single_returns_expected_result(self): 101 | result = schema.execute(self.query) 102 | expected = {'vlanRoles': 103 | {'edges': [ 104 | {'node': {'name': self.second.name}} 105 | ]}} 106 | self.assertEquals(result.data, expected) 107 | 108 | 109 | class UpdateTestCase(TestCase): 110 | @classmethod 111 | def setUpTestData(cls): 112 | cls.first = RoleFactory() 113 | cls.query = Template(''' 114 | mutation{ 115 | updateVlanRole(input: {id: "$id", name: "New Name", slug: "nsl1", weight: 1}) { 116 | vlanRole { 117 | name 118 | slug 119 | weight 120 | } 121 | } 122 | } 123 | ''').substitute(id=obj_to_global_id(cls.first)) 124 | 125 | def test_updating_returns_no_error(self): 126 | result = schema.execute(self.query) 127 | assert not result.errors 128 | 129 | def test_updating_doesnt_change_count(self): 130 | oldCount = Role.objects.all().count() 131 | schema.execute(self.query) 132 | self.assertEquals(Role.objects.all().count(), oldCount) 133 | 134 | def test_updating_returns_updated_data(self): 135 | expected = {'updateVlanRole': 136 | {'vlanRole': {'name': 'New Name', 137 | 'slug': 'nsl1', 138 | 'weight': 1}}} 139 | result = schema.execute(self.query) 140 | self.assertEquals(result.data, expected) 141 | 142 | def test_updating_alters_data(self): 143 | schema.execute(self.query) 144 | role = Role.objects.get(id=self.first.id) 145 | self.assertEquals(role.name, 'New Name') 146 | self.assertEquals(role.slug, 'nsl1') 147 | self.assertEquals(role.weight, 1) 148 | 149 | 150 | class DeleteTestCase(TestCase): 151 | @classmethod 152 | def setUpTestData(cls): 153 | cls.first = RoleFactory() 154 | cls.query = Template(''' 155 | mutation{ 156 | deleteVlanRole(input: {id: "$id"}) { 157 | vlanRole{ 158 | id 159 | name 160 | slug 161 | weight 162 | } 163 | } 164 | } 165 | ''').substitute(id=obj_to_global_id(cls.first)) 166 | 167 | def test_deleting_returns_no_error(self): 168 | result = schema.execute(self.query) 169 | assert not result.errors 170 | 171 | def test_deleting_removes_a_type(self): 172 | oldCount = Role.objects.all().count() 173 | schema.execute(self.query) 174 | self.assertEquals(Role.objects.all().count(), oldCount - 1) 175 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_vlan_groups.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from ipam.models import VLANGroup 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.ipam_factories import VLANGroupFactory 12 | from netbox_graphql.tests.factories.dcim_factories import SiteFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.site = SiteFactory() 19 | cls.query = Template(''' 20 | mutation{ 21 | newVlanGroup(input: { name: "VLANname", slug: "v1", site: "$siteId"}) { 22 | vlanGroup{ 23 | name 24 | slug 25 | site { 26 | name 27 | } 28 | } 29 | } 30 | } 31 | ''').substitute(siteId=obj_to_global_id(cls.site)) 32 | 33 | def test_creating_returns_no_error(self): 34 | result = schema.execute(self.query) 35 | assert not result.errors 36 | 37 | def test_creating_returns_data(self): 38 | expected = {'newVlanGroup': 39 | {'vlanGroup': {'name': 'VLANname', 40 | 'slug': 'v1', 41 | 'site': {'name': self.site.name}}}} 42 | 43 | result = schema.execute(self.query) 44 | self.assertEquals(result.data, expected) 45 | 46 | def test_creating_creates_it(self): 47 | oldCount = VLANGroup.objects.all().count() 48 | schema.execute(self.query) 49 | self.assertEquals(VLANGroup.objects.all().count(), oldCount + 1) 50 | 51 | 52 | class QueryMultipleTestCase(TestCase): 53 | @classmethod 54 | def setUpTestData(cls): 55 | cls.first = VLANGroupFactory() 56 | cls.second = VLANGroupFactory() 57 | cls.query = ''' 58 | { 59 | vlanGroups { 60 | edges { 61 | node { 62 | id 63 | } 64 | } 65 | } 66 | } 67 | ''' 68 | 69 | def test_querying_all_returns_no_error(self): 70 | result = schema.execute(self.query) 71 | assert not result.errors 72 | 73 | def test_querying_all_returns_two_results(self): 74 | result = schema.execute(self.query) 75 | self.assertEquals(len(result.data['vlanGroups']['edges']), 2) 76 | 77 | 78 | class QuerySingleTestCase(TestCase): 79 | @classmethod 80 | def setUpTestData(cls): 81 | cls.first = VLANGroupFactory() 82 | cls.second = VLANGroupFactory() 83 | cls.query = Template(''' 84 | { 85 | vlanGroups(id: "$id") { 86 | edges { 87 | node { 88 | name 89 | slug 90 | site { 91 | name 92 | } 93 | } 94 | } 95 | } 96 | } 97 | ''').substitute(id=obj_to_global_id(cls.first)) 98 | 99 | def test_querying_single_returns_no_error(self): 100 | result = schema.execute(self.query) 101 | assert not result.errors 102 | 103 | def test_querying_single_returns_result(self): 104 | result = schema.execute(self.query) 105 | self.assertEquals(len(result.data['vlanGroups']['edges']), 1) 106 | 107 | def test_querying_single_returns_expected_result(self): 108 | result = schema.execute(self.query) 109 | expected = {'vlanGroups': 110 | {'edges': [ 111 | {'node': {'name': self.first.name, 112 | 'slug': self.first.slug, 113 | 'site': {'name': self.first.site.name}}} 114 | ]}} 115 | self.assertEquals(result.data, expected) 116 | 117 | 118 | class UpdateTestCase(TestCase): 119 | @classmethod 120 | def setUpTestData(cls): 121 | cls.first = VLANGroupFactory() 122 | cls.site = SiteFactory() 123 | cls.query = Template(''' 124 | mutation{ 125 | updateVlanGroup(input: { id:"$id", name: "New Name", slug: "nsl1", site: "$siteId"}) { 126 | vlanGroup{ 127 | name 128 | slug 129 | site { 130 | name 131 | } 132 | } 133 | } 134 | } 135 | ''').substitute(id=obj_to_global_id(cls.first), 136 | siteId=obj_to_global_id(cls.site)) 137 | 138 | def test_updating_returns_no_error(self): 139 | result = schema.execute(self.query) 140 | assert not result.errors 141 | 142 | def test_updating_doesnt_change_count(self): 143 | oldCount = VLANGroup.objects.all().count() 144 | schema.execute(self.query) 145 | self.assertEquals(VLANGroup.objects.all().count(), oldCount) 146 | 147 | def test_updating_returns_updated_data(self): 148 | expected = {'updateVlanGroup': 149 | {'vlanGroup': {'name': 'New Name', 150 | 'slug': 'nsl1', 151 | 'site': {'name': self.site.name}}}} 152 | result = schema.execute(self.query) 153 | self.assertEquals(result.data, expected) 154 | 155 | def test_updating_alters_data(self): 156 | schema.execute(self.query) 157 | vlan_group = VLANGroup.objects.get(id=self.first.id) 158 | self.assertEquals(vlan_group.name, 'New Name') 159 | self.assertEquals(vlan_group.slug, 'nsl1') 160 | self.assertEquals(vlan_group.site.name, self.site.name) 161 | 162 | 163 | class DeleteTestCase(TestCase): 164 | @classmethod 165 | def setUpTestData(cls): 166 | cls.first = VLANGroupFactory() 167 | cls.query = Template(''' 168 | mutation{ 169 | deleteVlanGroup(input: { id:"$id"}) { 170 | vlanGroup{ 171 | id 172 | } 173 | } 174 | } 175 | ''').substitute(id=obj_to_global_id(cls.first)) 176 | 177 | def test_deleting_returns_no_error(self): 178 | result = schema.execute(self.query) 179 | assert not result.errors 180 | 181 | def test_deleting_removes_a_type(self): 182 | oldCount = VLANGroup.objects.all().count() 183 | schema.execute(self.query) 184 | self.assertEquals(VLANGroup.objects.all().count(), oldCount - 1) 185 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_vlans.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from ipam.models import VLAN 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.ipam_factories import VLANFactory, RoleFactory 12 | from netbox_graphql.tests.factories.tenant_factories import TenantFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.tenant = TenantFactory() 19 | cls.role = RoleFactory() 20 | cls.query = Template(''' 21 | mutation{ 22 | newVlan(input: { tenant: "$tenantId", role: "$roleId", vid: 2, name: "New Vlan"}) { 23 | vlan{ 24 | name 25 | vid 26 | tenant{ 27 | name 28 | } 29 | role{ 30 | name 31 | } 32 | } 33 | } 34 | } 35 | ''').substitute(tenantId=obj_to_global_id(cls.tenant), 36 | roleId=obj_to_global_id(cls.role)) 37 | 38 | def test_creating_returns_no_error(self): 39 | result = schema.execute(self.query) 40 | assert not result.errors 41 | 42 | def test_creating_returns_data(self): 43 | expected = {'newVlan': 44 | {'vlan': {'name': 'New Vlan', 45 | 'vid': 2, 46 | 'tenant': {'name': self.tenant.name}, 47 | 'role': {'name': self.role.name} 48 | }}} 49 | 50 | result = schema.execute(self.query) 51 | self.assertEquals(result.data, expected) 52 | 53 | def test_creating_creates_it(self): 54 | oldCount = VLAN.objects.all().count() 55 | schema.execute(self.query) 56 | self.assertEquals(VLAN.objects.all().count(), oldCount + 1) 57 | 58 | 59 | class QueryMultipleTestCase(TestCase): 60 | @classmethod 61 | def setUpTestData(cls): 62 | cls.first = VLANFactory() 63 | cls.second = VLANFactory() 64 | cls.query = ''' 65 | { 66 | vlans { 67 | edges { 68 | node { 69 | id 70 | } 71 | } 72 | } 73 | } 74 | ''' 75 | 76 | def test_querying_all_returns_no_error(self): 77 | result = schema.execute(self.query) 78 | assert not result.errors 79 | 80 | def test_querying_all_returns_two_results(self): 81 | result = schema.execute(self.query) 82 | self.assertEquals(len(result.data['vlans']['edges']), 2) 83 | 84 | 85 | class QuerySingleTestCase(TestCase): 86 | @classmethod 87 | def setUpTestData(cls): 88 | cls.first = VLANFactory() 89 | cls.second = VLANFactory() 90 | cls.query = Template(''' 91 | { 92 | vlans(id: "$id") { 93 | edges { 94 | node { 95 | name 96 | vid 97 | tenant { 98 | name 99 | } 100 | role { 101 | name 102 | } 103 | } 104 | } 105 | } 106 | } 107 | ''').substitute(id=obj_to_global_id(cls.second)) 108 | 109 | def test_querying_single_returns_no_error(self): 110 | result = schema.execute(self.query) 111 | assert not result.errors 112 | 113 | def test_querying_single_returns_result(self): 114 | result = schema.execute(self.query) 115 | self.assertEquals(len(result.data['vlans']['edges']), 1) 116 | 117 | def test_querying_single_returns_expected_result(self): 118 | result = schema.execute(self.query) 119 | expected = {'vlans': 120 | {'edges': [ 121 | {'node': {'name': self.second.name, 122 | 'vid': self.second.vid, 123 | 'tenant': {'name': self.second.tenant.name}, 124 | 'role': {'name': self.second.role.name}}} 125 | ]}} 126 | self.assertEquals(result.data, expected) 127 | 128 | 129 | class UpdateTestCase(TestCase): 130 | @classmethod 131 | def setUpTestData(cls): 132 | cls.first = VLANFactory() 133 | cls.tenant = TenantFactory() 134 | cls.query = Template(''' 135 | mutation{ 136 | updateVlan(input: { id: "$id", vid: 10, name: "New Name", tenant: "$tenantId"}) { 137 | vlan{ 138 | name 139 | vid 140 | tenant { 141 | name 142 | } 143 | } 144 | } 145 | } 146 | ''').substitute(id=obj_to_global_id(cls.first), 147 | tenantId=obj_to_global_id(cls.tenant)) 148 | 149 | def test_updating_returns_no_error(self): 150 | result = schema.execute(self.query) 151 | assert not result.errors 152 | 153 | def test_updating_doesnt_change_count(self): 154 | oldCount = VLAN.objects.all().count() 155 | schema.execute(self.query) 156 | self.assertEquals(VLAN.objects.all().count(), oldCount) 157 | 158 | def test_updating_returns_updated_data(self): 159 | expected = {'updateVlan': 160 | {'vlan': {'name': 'New Name', 161 | 'vid': 10, 162 | 'tenant': {'name': self.tenant.name}}}} 163 | result = schema.execute(self.query) 164 | self.assertEquals(result.data, expected) 165 | 166 | def test_updating_alters_data(self): 167 | schema.execute(self.query) 168 | vlan = VLAN.objects.get(id=self.first.id) 169 | self.assertEquals(vlan.name, 'New Name') 170 | self.assertEquals(vlan.vid, 10) 171 | self.assertEquals(vlan.tenant.name, self.tenant.name) 172 | 173 | 174 | class DeleteTestCase(TestCase): 175 | @classmethod 176 | def setUpTestData(cls): 177 | cls.first = VLANFactory() 178 | cls.query = Template(''' 179 | mutation{ 180 | deleteVlan(input: { id:"$id"}) { 181 | vlan{ 182 | id 183 | } 184 | } 185 | } 186 | ''').substitute(id=obj_to_global_id(cls.first)) 187 | 188 | def test_deleting_returns_no_error(self): 189 | result = schema.execute(self.query) 190 | assert not result.errors 191 | 192 | def test_deleting_removes_a_type(self): 193 | oldCount = VLAN.objects.all().count() 194 | schema.execute(self.query) 195 | self.assertEquals(VLAN.objects.all().count(), oldCount - 1) 196 | -------------------------------------------------------------------------------- /netbox_graphql/tests/ipam/tests_vrfs.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from ipam.models import VRF 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.ipam_factories import VRFFactory 12 | from netbox_graphql.tests.factories.tenant_factories import TenantFactory 13 | 14 | 15 | class CreateTestCase(TestCase): 16 | @classmethod 17 | def setUpTestData(cls): 18 | cls.tenant = TenantFactory() 19 | cls.query = Template(''' 20 | mutation{ 21 | newVrf(input: { tenant: "$tenantId", name: "New Name", rd: "rd", enforceUnique: true }) { 22 | vrf { 23 | name 24 | rd 25 | enforceUnique 26 | tenant { 27 | name 28 | } 29 | } 30 | } 31 | } 32 | ''').substitute(tenantId=obj_to_global_id(cls.tenant)) 33 | 34 | def test_creating_returns_no_error(self): 35 | result = schema.execute(self.query) 36 | assert not result.errors 37 | 38 | def test_creating_returns_data(self): 39 | expected = {'newVrf': 40 | {'vrf': {'name': 'New Name', 41 | 'rd': 'rd', 42 | 'enforceUnique': True, 43 | 'tenant': {'name': self.tenant.name}}}} 44 | 45 | result = schema.execute(self.query) 46 | self.assertEquals(result.data, expected) 47 | 48 | def test_creating_creates_it(self): 49 | oldCount = VRF.objects.all().count() 50 | schema.execute(self.query) 51 | self.assertEquals(VRF.objects.all().count(), oldCount + 1) 52 | 53 | 54 | class QueryMultipleTestCase(TestCase): 55 | @classmethod 56 | def setUpTestData(cls): 57 | cls.first = VRFFactory() 58 | cls.second = VRFFactory() 59 | cls.query = ''' 60 | { 61 | vrfs { 62 | edges { 63 | node { 64 | id 65 | } 66 | } 67 | } 68 | } 69 | ''' 70 | 71 | def test_querying_all_returns_no_error(self): 72 | result = schema.execute(self.query) 73 | assert not result.errors 74 | 75 | def test_querying_all_returns_two_results(self): 76 | result = schema.execute(self.query) 77 | self.assertEquals(len(result.data['vrfs']['edges']), 2) 78 | 79 | 80 | class QuerySingleTestCase(TestCase): 81 | @classmethod 82 | def setUpTestData(cls): 83 | cls.first = VRFFactory() 84 | cls.second = VRFFactory() 85 | cls.query = Template(''' 86 | { 87 | vrfs(id: "$id") { 88 | edges { 89 | node { 90 | name 91 | rd 92 | enforceUnique 93 | tenant { 94 | name 95 | } 96 | } 97 | } 98 | } 99 | } 100 | ''').substitute(id=obj_to_global_id(cls.first)) 101 | 102 | def test_querying_single_returns_no_error(self): 103 | result = schema.execute(self.query) 104 | assert not result.errors 105 | 106 | def test_querying_single_returns_result(self): 107 | result = schema.execute(self.query) 108 | self.assertEquals(len(result.data['vrfs']['edges']), 1) 109 | 110 | def test_querying_single_returns_expected_result(self): 111 | result = schema.execute(self.query) 112 | expected = {'vrfs': 113 | {'edges': [ 114 | {'node': {'name': self.first.name, 115 | 'rd': self.first.rd, 116 | 'enforceUnique': True, 117 | 'tenant': {'name': self.first.tenant.name}}} 118 | ]}} 119 | self.assertEquals(result.data, expected) 120 | 121 | 122 | class UpdateTestCase(TestCase): 123 | @classmethod 124 | def setUpTestData(cls): 125 | cls.first = VRFFactory() 126 | cls.tenant = TenantFactory() 127 | cls.query = Template(''' 128 | mutation{ 129 | updateVrf(input: { id: "$id", name: "New Name", rd: "upd", tenant: "$tenantId" }) { 130 | vrf { 131 | name 132 | rd 133 | tenant { 134 | name 135 | } 136 | } 137 | } 138 | } 139 | ''').substitute(id=obj_to_global_id(cls.first), 140 | tenantId=obj_to_global_id(cls.tenant)) 141 | 142 | def test_updating_returns_no_error(self): 143 | result = schema.execute(self.query) 144 | assert not result.errors 145 | 146 | def test_updating_doesnt_change_count(self): 147 | oldCount = VRF.objects.all().count() 148 | schema.execute(self.query) 149 | self.assertEquals(VRF.objects.all().count(), oldCount) 150 | 151 | def test_updating_returns_updated_data(self): 152 | expected = {'updateVrf': {'vrf': {'name': 'New Name', 153 | 'rd': 'upd', 154 | 'tenant': {'name': self.tenant.name}}}} 155 | result = schema.execute(self.query) 156 | self.assertEquals(result.data, expected) 157 | 158 | def test_updating_alters_data(self): 159 | schema.execute(self.query) 160 | vrf = VRF.objects.get(id=self.first.id) 161 | self.assertEquals(vrf.name, 'New Name') 162 | self.assertEquals(vrf.rd, 'upd') 163 | self.assertEquals(vrf.tenant.name, self.tenant.name) 164 | 165 | 166 | class DeleteTestCase(TestCase): 167 | @classmethod 168 | def setUpTestData(cls): 169 | cls.first = VRFFactory() 170 | cls.query = Template(''' 171 | mutation{ 172 | deleteVrf(input: { id: "$id" }) { 173 | vrf { 174 | id 175 | } 176 | } 177 | } 178 | ''').substitute(id=obj_to_global_id(cls.first)) 179 | 180 | def test_deleting_returns_no_error(self): 181 | result = schema.execute(self.query) 182 | assert not result.errors 183 | 184 | def test_deleting_removes_a_type(self): 185 | oldCount = VRF.objects.all().count() 186 | schema.execute(self.query) 187 | self.assertEquals(VRF.objects.all().count(), oldCount - 1) 188 | -------------------------------------------------------------------------------- /netbox_graphql/tests/tenancy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/tenancy/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/tenancy/tests_groups.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from tenancy.models import TenantGroup 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.tenant_factories import TenantGroupFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.query = ''' 18 | mutation{ 19 | newTenantGroup(input: {name: "Groupname", slug: "groupslug"}) { 20 | tenantGroup{ 21 | name 22 | slug 23 | } 24 | } 25 | } 26 | ''' 27 | 28 | def test_creating_returns_no_error(self): 29 | result = schema.execute(self.query) 30 | assert not result.errors 31 | 32 | def test_creating_returns_data(self): 33 | expected = {'newTenantGroup': 34 | {'tenantGroup': {'name': 'Groupname', 'slug': 'groupslug'}}} 35 | 36 | result = schema.execute(self.query) 37 | self.assertEquals(result.data, expected) 38 | 39 | def test_creating_creates_it(self): 40 | oldCount = TenantGroup.objects.all().count() 41 | schema.execute(self.query) 42 | self.assertEquals(TenantGroup.objects.all().count(), oldCount + 1) 43 | 44 | 45 | class QueryMultipleTestCase(TestCase): 46 | @classmethod 47 | def setUpTestData(cls): 48 | cls.first = TenantGroupFactory() 49 | cls.second = TenantGroupFactory() 50 | cls.query = ''' 51 | {tenantGroups { 52 | edges { 53 | node { 54 | name 55 | slug 56 | } 57 | } 58 | }} 59 | ''' 60 | 61 | def test_querying_all_returns_no_error(self): 62 | result = schema.execute(self.query) 63 | assert not result.errors 64 | 65 | def test_querying_all_returns_two_results(self): 66 | result = schema.execute(self.query) 67 | self.assertEquals(len(result.data['tenantGroups']['edges']), 2) 68 | 69 | 70 | class QuerySingleTestCase(TestCase): 71 | @classmethod 72 | def setUpTestData(cls): 73 | cls.first = TenantGroupFactory() 74 | cls.second = TenantGroupFactory() 75 | cls.query = Template(''' 76 | {tenantGroups(id: "$id") { 77 | edges { 78 | node { 79 | name 80 | slug 81 | } 82 | } 83 | }} 84 | ''').substitute(id=obj_to_global_id(cls.first)) 85 | 86 | def test_querying_single_returns_no_error(self): 87 | result = schema.execute(self.query) 88 | assert not result.errors 89 | 90 | def test_querying_single_returns_result(self): 91 | result = schema.execute(self.query) 92 | self.assertEquals(len(result.data['tenantGroups']['edges']), 1) 93 | 94 | def test_querying_single_returns_expected_result(self): 95 | result = schema.execute(self.query) 96 | expected = {'tenantGroups': 97 | {'edges': [ 98 | {'node': {'name': self.first.name, 'slug': self.first.slug}} 99 | ]}} 100 | self.assertEquals(result.data, expected) 101 | 102 | 103 | class UpdateTestCase(TestCase): 104 | @classmethod 105 | def setUpTestData(cls): 106 | cls.first = TenantGroupFactory() 107 | cls.query = Template(''' 108 | mutation { 109 | updateTenantGroup(input: {id:"$id", name: "New Name", slug: "nsl1"}) { 110 | tenantGroup { 111 | name 112 | slug 113 | } 114 | } 115 | } 116 | ''').substitute(id=obj_to_global_id(cls.first)) 117 | 118 | def test_updating_returns_no_error(self): 119 | result = schema.execute(self.query) 120 | assert not result.errors 121 | 122 | def test_updating_doesnt_change_count(self): 123 | oldCount = TenantGroup.objects.all().count() 124 | schema.execute(self.query) 125 | self.assertEquals(TenantGroup.objects.all().count(), oldCount) 126 | 127 | def test_updating_returns_updated_data(self): 128 | expected = {'updateTenantGroup': 129 | {'tenantGroup': {'name': 'New Name', 'slug': 'nsl1'}}} 130 | result = schema.execute(self.query) 131 | self.assertEquals(result.data, expected) 132 | 133 | def test_updating_alters_data(self): 134 | schema.execute(self.query) 135 | tenant_group = TenantGroup.objects.get(id=self.first.id) 136 | self.assertEquals(tenant_group.name, 'New Name') 137 | self.assertEquals(tenant_group.slug, 'nsl1') 138 | 139 | 140 | class DeleteTestCase(TestCase): 141 | @classmethod 142 | def setUpTestData(cls): 143 | cls.first = TenantGroupFactory() 144 | cls.query = Template(''' 145 | mutation { 146 | deleteTenantGroup(input: {id:"$id"}) { 147 | tenantGroup { 148 | id 149 | } 150 | } 151 | } 152 | ''').substitute(id=obj_to_global_id(cls.first)) 153 | 154 | def test_deleting_returns_no_error(self): 155 | result = schema.execute(self.query) 156 | assert not result.errors 157 | 158 | def test_deleting_removes_a_type(self): 159 | oldCount = TenantGroup.objects.all().count() 160 | schema.execute(self.query) 161 | self.assertEquals(TenantGroup.objects.all().count(), oldCount - 1) 162 | -------------------------------------------------------------------------------- /netbox_graphql/tests/tenancy/tests_tenants.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from tenancy.models import Tenant 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.tenant_factories import TenantFactory, TenantGroupFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.group = TenantGroupFactory() 18 | cls.query = Template(''' 19 | mutation { 20 | newTenant(input: {name: "New Tenant", slug: "t1", group: "$groupId", description: "desc", comments: "comments"}) { 21 | tenant { 22 | name 23 | group { 24 | name 25 | } 26 | } 27 | } 28 | } 29 | ''').substitute(groupId=obj_to_global_id(cls.group)) 30 | 31 | def test_creating_returns_no_error(self): 32 | result = schema.execute(self.query) 33 | assert not result.errors 34 | 35 | def test_creating_returns_data(self): 36 | expected = {'newTenant': 37 | {'tenant': {'name': 'New Tenant', 38 | 'group': {'name': self.group.name}}}} 39 | 40 | result = schema.execute(self.query) 41 | self.assertEquals(result.data, expected) 42 | 43 | def test_creating_creates_it(self): 44 | oldCount = Tenant.objects.all().count() 45 | schema.execute(self.query) 46 | self.assertEquals(Tenant.objects.all().count(), oldCount + 1) 47 | 48 | 49 | class QueryMultipleTestCase(TestCase): 50 | @classmethod 51 | def setUpTestData(cls): 52 | cls.first = TenantFactory() 53 | cls.second = TenantFactory(group=cls.first.group) 54 | cls.third = TenantFactory() 55 | cls.query = Template(''' 56 | { 57 | tenants{ 58 | edges { 59 | node { 60 | name 61 | group { 62 | name 63 | } 64 | } 65 | } 66 | } 67 | } 68 | ''').substitute(id=obj_to_global_id(cls.first)) 69 | 70 | def test_querying_all_returns_no_error(self): 71 | result = schema.execute(self.query) 72 | assert not result.errors 73 | 74 | def test_querying_all_types_returns_three_results(self): 75 | result = schema.execute(self.query) 76 | self.assertEquals(len(result.data['tenants']['edges']), 3) 77 | 78 | 79 | class QuerySingleTestCase(TestCase): 80 | @classmethod 81 | def setUpTestData(cls): 82 | cls.first = TenantFactory() 83 | cls.second = TenantFactory(group=cls.first.group) 84 | cls.query = Template(''' 85 | { 86 | tenants(id: "$id") { 87 | edges { 88 | node { 89 | name 90 | group { 91 | name 92 | } 93 | } 94 | } 95 | } 96 | } 97 | ''').substitute(id=obj_to_global_id(cls.first)) 98 | 99 | def test_querying_single_returns_no_error(self): 100 | result = schema.execute(self.query) 101 | assert not result.errors 102 | 103 | def test_querying_single_returns_result(self): 104 | result = schema.execute(self.query) 105 | self.assertEquals(len(result.data['tenants']['edges']), 1) 106 | 107 | def test_querying_single_returns_expected_result(self): 108 | result = schema.execute(self.query) 109 | expected = {'tenants': 110 | {'edges': [ 111 | {'node': {'name': self.first.name, 112 | 'group': {'name': self.first.group.name}}} 113 | ]}} 114 | self.assertEquals(result.data, expected) 115 | 116 | 117 | class UpdateTestCase(TestCase): 118 | @classmethod 119 | def setUpTestData(cls): 120 | cls.first = TenantFactory() 121 | cls.group = TenantGroupFactory() 122 | cls.query = Template(''' 123 | mutation { 124 | updateTenant(input: {id: "$id", name: "New Name", slug: "nsl1", group: "$groupId"}) { 125 | tenant { 126 | name 127 | slug 128 | group { 129 | name 130 | } 131 | } 132 | } 133 | } 134 | ''').substitute(id=obj_to_global_id(cls.first), groupId=obj_to_global_id(cls.group)) 135 | 136 | def test_updating_returns_no_error(self): 137 | result = schema.execute(self.query) 138 | assert not result.errors 139 | 140 | def test_updating_doesnt_change_count(self): 141 | oldCount = Tenant.objects.all().count() 142 | schema.execute(self.query) 143 | self.assertEquals(Tenant.objects.all().count(), oldCount) 144 | 145 | def test_updating_returns_updated_data(self): 146 | expected = {'updateTenant': 147 | {'tenant': {'name': 'New Name', 148 | 'slug': 'nsl1', 149 | 'group': {'name': self.group.name}}}} 150 | result = schema.execute(self.query) 151 | self.assertEquals(result.data, expected) 152 | 153 | def test_updating_alters_data(self): 154 | schema.execute(self.query) 155 | tenant = Tenant.objects.get(id=self.first.id) 156 | self.assertEquals(tenant.name, 'New Name') 157 | self.assertEquals(tenant.slug, 'nsl1') 158 | self.assertEquals(tenant.group, self.group) 159 | 160 | 161 | class DeleteTestCase(TestCase): 162 | @classmethod 163 | def setUpTestData(cls): 164 | cls.first = TenantFactory() 165 | cls.query = Template(''' 166 | mutation { 167 | deleteTenant(input: {id: "$id"}) { 168 | tenant { 169 | name 170 | } 171 | } 172 | } 173 | ''').substitute(id=obj_to_global_id(cls.first)) 174 | 175 | def test_deleting_returns_no_error(self): 176 | result = schema.execute(self.query) 177 | assert not result.errors 178 | 179 | def test_deleting_removes_a_type(self): 180 | oldCount = Tenant.objects.all().count() 181 | schema.execute(self.query) 182 | self.assertEquals(Tenant.objects.all().count(), oldCount - 1) 183 | -------------------------------------------------------------------------------- /netbox_graphql/tests/utils.py: -------------------------------------------------------------------------------- 1 | from graphql_relay.node.node import from_global_id, to_global_id 2 | 3 | 4 | def obj_to_global_id(obj): 5 | return to_global_id(type(obj).__name__, obj.id) 6 | -------------------------------------------------------------------------------- /netbox_graphql/tests/virtualization/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninech/django-netbox-graphql/8383570bdf3a8ce8d9d912c5b8f7b053b31c7363/netbox_graphql/tests/virtualization/__init__.py -------------------------------------------------------------------------------- /netbox_graphql/tests/virtualization/tests_cluster_groups.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from virtualization.models import ClusterGroup 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.virtualization_factories import ClusterGroupFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.query = ''' 18 | mutation{ 19 | newClusterGroup(input: { name: "New Name", slug: "nsl1"}) { 20 | clusterGroup{ 21 | name 22 | slug 23 | } 24 | } 25 | } 26 | ''' 27 | 28 | def test_creating_returns_no_error(self): 29 | result = schema.execute(self.query) 30 | assert not result.errors 31 | 32 | def test_creating_returns_data(self): 33 | expected = {'newClusterGroup': 34 | {'clusterGroup': {'name': 'New Name', 'slug': 'nsl1'}}} 35 | 36 | result = schema.execute(self.query) 37 | self.assertEquals(result.data, expected) 38 | 39 | def test_creating_creates_it(self): 40 | oldCount = ClusterGroup.objects.all().count() 41 | schema.execute(self.query) 42 | self.assertEquals(ClusterGroup.objects.all().count(), oldCount + 1) 43 | 44 | 45 | class QueryMultipleTestCase(TestCase): 46 | @classmethod 47 | def setUpTestData(cls): 48 | cls.first = ClusterGroupFactory() 49 | cls.second = ClusterGroupFactory() 50 | cls.query = ''' 51 | { 52 | clusterGroups { 53 | edges { 54 | node { 55 | id 56 | } 57 | } 58 | } 59 | } 60 | ''' 61 | 62 | def test_querying_all_returns_no_error(self): 63 | result = schema.execute(self.query) 64 | assert not result.errors 65 | 66 | def test_querying_all_returns_two_results(self): 67 | result = schema.execute(self.query) 68 | self.assertEquals(len(result.data['clusterGroups']['edges']), 2) 69 | 70 | 71 | class QuerySingleTestCase(TestCase): 72 | @classmethod 73 | def setUpTestData(cls): 74 | cls.first = ClusterGroupFactory() 75 | cls.second = ClusterGroupFactory() 76 | cls.query = Template(''' 77 | { 78 | clusterGroups(id: "$id") { 79 | edges { 80 | node { 81 | name 82 | } 83 | } 84 | } 85 | } 86 | ''').substitute(id=obj_to_global_id(cls.first)) 87 | 88 | def test_querying_single_returns_no_error(self): 89 | result = schema.execute(self.query) 90 | assert not result.errors 91 | 92 | def test_querying_single_returns_result(self): 93 | result = schema.execute(self.query) 94 | self.assertEquals(len(result.data['clusterGroups']['edges']), 1) 95 | 96 | def test_querying_single_returns_expected_result(self): 97 | result = schema.execute(self.query) 98 | expected = {'clusterGroups': 99 | {'edges': [ 100 | {'node': {'name': self.first.name}} 101 | ]}} 102 | self.assertEquals(result.data, expected) 103 | 104 | 105 | class UpdateTestCase(TestCase): 106 | @classmethod 107 | def setUpTestData(cls): 108 | cls.first = ClusterGroupFactory() 109 | cls.query = Template(''' 110 | mutation{ 111 | updateClusterGroup(input: { id: "$id", name: "New Name", slug: "nsl1"}) { 112 | clusterGroup { 113 | name 114 | slug 115 | } 116 | } 117 | } 118 | ''').substitute(id=obj_to_global_id(cls.first)) 119 | 120 | def test_updating_returns_no_error(self): 121 | result = schema.execute(self.query) 122 | assert not result.errors 123 | 124 | def test_updating_doesnt_change_count(self): 125 | oldCount = ClusterGroup.objects.all().count() 126 | schema.execute(self.query) 127 | self.assertEquals(ClusterGroup.objects.all().count(), oldCount) 128 | 129 | def test_updating_returns_updated_data(self): 130 | expected = {'updateClusterGroup': 131 | {'clusterGroup': {'name': 'New Name', 'slug': 'nsl1'}}} 132 | result = schema.execute(self.query) 133 | self.assertEquals(result.data, expected) 134 | 135 | def test_updating_alters_data(self): 136 | schema.execute(self.query) 137 | circuit_type = ClusterGroup.objects.get(id=self.first.id) 138 | self.assertEquals(circuit_type.name, 'New Name') 139 | self.assertEquals(circuit_type.slug, 'nsl1') 140 | 141 | 142 | class DeleteTestCase(TestCase): 143 | @classmethod 144 | def setUpTestData(cls): 145 | cls.first = ClusterGroupFactory() 146 | cls.query = Template(''' 147 | mutation{ 148 | deleteClusterGroup(input: { id: "$id"}) { 149 | clusterGroup{ 150 | id 151 | } 152 | } 153 | } 154 | ''').substitute(id=obj_to_global_id(cls.first)) 155 | 156 | def test_deleting_returns_no_error(self): 157 | result = schema.execute(self.query) 158 | assert not result.errors 159 | 160 | def test_deleting_removes_a_type(self): 161 | oldCount = ClusterGroup.objects.all().count() 162 | schema.execute(self.query) 163 | self.assertEquals(ClusterGroup.objects.all().count(), oldCount - 1) 164 | -------------------------------------------------------------------------------- /netbox_graphql/tests/virtualization/tests_cluster_types.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from virtualization.models import ClusterType 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.virtualization_factories import ClusterTypeFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.query = ''' 18 | mutation{ 19 | newClusterType(input: { name: "Cluster Name", slug: "cl1"}) { 20 | clusterType { 21 | name 22 | slug 23 | } 24 | } 25 | } 26 | ''' 27 | 28 | def test_creating_returns_no_error(self): 29 | result = schema.execute(self.query) 30 | assert not result.errors 31 | 32 | def test_creating_returns_data(self): 33 | expected = {'newClusterType': 34 | {'clusterType': {'name': 'Cluster Name', 'slug': 'cl1'}}} 35 | 36 | result = schema.execute(self.query) 37 | self.assertEquals(result.data, expected) 38 | 39 | def test_creating_creates_it(self): 40 | oldCount = ClusterType.objects.all().count() 41 | schema.execute(self.query) 42 | self.assertEquals(ClusterType.objects.all().count(), oldCount + 1) 43 | 44 | 45 | class QueryMultipleTestCase(TestCase): 46 | @classmethod 47 | def setUpTestData(cls): 48 | cls.first = ClusterTypeFactory() 49 | cls.second = ClusterTypeFactory() 50 | cls.query = ''' 51 | { 52 | clusterTypes { 53 | edges { 54 | node { 55 | id 56 | } 57 | } 58 | } 59 | } 60 | ''' 61 | 62 | def test_querying_all_returns_no_error(self): 63 | result = schema.execute(self.query) 64 | assert not result.errors 65 | 66 | def test_querying_all_returns_two_results(self): 67 | result = schema.execute(self.query) 68 | self.assertEquals(len(result.data['clusterTypes']['edges']), 2) 69 | 70 | 71 | class QuerySingleTestCase(TestCase): 72 | @classmethod 73 | def setUpTestData(cls): 74 | cls.first = ClusterTypeFactory() 75 | cls.query = Template(''' 76 | { 77 | clusterTypes(id: "$id") { 78 | edges { 79 | node { 80 | name 81 | } 82 | } 83 | } 84 | } 85 | ''').substitute(id=obj_to_global_id(cls.first)) 86 | 87 | def test_querying_single_returns_no_error(self): 88 | result = schema.execute(self.query) 89 | assert not result.errors 90 | 91 | def test_querying_single_returns_result(self): 92 | result = schema.execute(self.query) 93 | self.assertEquals(len(result.data['clusterTypes']['edges']), 1) 94 | 95 | def test_querying_single_returns_expected_result(self): 96 | result = schema.execute(self.query) 97 | expected = {'clusterTypes': 98 | {'edges': [ 99 | {'node': {'name': self.first.name}} 100 | ]}} 101 | self.assertEquals(result.data, expected) 102 | 103 | 104 | class UpdateTestCase(TestCase): 105 | @classmethod 106 | def setUpTestData(cls): 107 | cls.first = ClusterTypeFactory() 108 | cls.query = Template(''' 109 | mutation { 110 | updateClusterType(input: { id: "$id", name: "New Name", slug: "nsl1"}) { 111 | clusterType { 112 | name 113 | slug 114 | } 115 | } 116 | } 117 | ''').substitute(id=obj_to_global_id(cls.first)) 118 | 119 | def test_updating_returns_no_error(self): 120 | result = schema.execute(self.query) 121 | assert not result.errors 122 | 123 | def test_updating_doesnt_change_count(self): 124 | oldCount = ClusterType.objects.all().count() 125 | schema.execute(self.query) 126 | self.assertEquals(ClusterType.objects.all().count(), oldCount) 127 | 128 | def test_updating_returns_updated_data(self): 129 | expected = {'updateClusterType': 130 | {'clusterType': {'name': 'New Name', 'slug': 'nsl1'}}} 131 | result = schema.execute(self.query) 132 | self.assertEquals(result.data, expected) 133 | 134 | def test_updating_alters_data(self): 135 | schema.execute(self.query) 136 | cluster_type_factory = ClusterType.objects.get(id=self.first.id) 137 | self.assertEquals(cluster_type_factory.name, 'New Name') 138 | self.assertEquals(cluster_type_factory.slug, 'nsl1') 139 | 140 | 141 | class DeleteTestCase(TestCase): 142 | @classmethod 143 | def setUpTestData(cls): 144 | cls.first = ClusterTypeFactory() 145 | cls.query = Template(''' 146 | mutation{ 147 | deleteClusterType(input: { id: "$id"}) { 148 | clusterType{ 149 | id 150 | } 151 | } 152 | } 153 | ''').substitute(id=obj_to_global_id(cls.first)) 154 | 155 | def test_deleting_returns_no_error(self): 156 | result = schema.execute(self.query) 157 | assert not result.errors 158 | 159 | def test_deleting_removes_a_type(self): 160 | oldCount = ClusterType.objects.all().count() 161 | schema.execute(self.query) 162 | self.assertEquals(ClusterType.objects.all().count(), oldCount - 1) 163 | -------------------------------------------------------------------------------- /netbox_graphql/tests/virtualization/tests_clusters.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from virtualization.models import Cluster 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.virtualization_factories import ClusterFactory, ClusterTypeFactory, ClusterGroupFactory 12 | 13 | 14 | class CreateTestCase(TestCase): 15 | @classmethod 16 | def setUpTestData(cls): 17 | cls.type = ClusterTypeFactory() 18 | cls.group = ClusterGroupFactory() 19 | cls.query = Template(''' 20 | mutation{ 21 | newCluster(input: { name: "New Cluster", type: "$typeId", group: "$groupId"}) { 22 | cluster{ 23 | name 24 | type { 25 | name 26 | } 27 | } 28 | } 29 | } 30 | ''').substitute(typeId=obj_to_global_id(cls.type), 31 | groupId=obj_to_global_id(cls.group)) 32 | 33 | def test_creating_returns_no_error(self): 34 | result = schema.execute(self.query) 35 | assert not result.errors 36 | 37 | def test_creating_returns_data(self): 38 | expected = {'newCluster': 39 | {'cluster': {'name': 'New Cluster', 40 | 'type': {'name': self.type.name}}}} 41 | 42 | result = schema.execute(self.query) 43 | self.assertEquals(result.data, expected) 44 | 45 | def test_creating_creates_it(self): 46 | oldCount = Cluster.objects.all().count() 47 | schema.execute(self.query) 48 | self.assertEquals(Cluster.objects.all().count(), oldCount + 1) 49 | 50 | 51 | class QueryMultipleTestCase(TestCase): 52 | @classmethod 53 | def setUpTestData(cls): 54 | cls.first = ClusterFactory() 55 | cls.second = ClusterFactory(type=cls.first.type) 56 | cls.third = ClusterFactory() 57 | cls.query = Template(''' 58 | { 59 | clusters { 60 | edges { 61 | node { 62 | id 63 | } 64 | } 65 | } 66 | } 67 | ''').substitute(id=obj_to_global_id(cls.first)) 68 | 69 | def test_querying_all_returns_no_error(self): 70 | result = schema.execute(self.query) 71 | assert not result.errors 72 | 73 | def test_querying_all_types_returns_three_results(self): 74 | result = schema.execute(self.query) 75 | self.assertEquals(len(result.data['clusters']['edges']), 3) 76 | 77 | 78 | class QuerySingleTestCase(TestCase): 79 | @classmethod 80 | def setUpTestData(cls): 81 | cls.first = ClusterFactory() 82 | cls.second = ClusterFactory(type=cls.first.type) 83 | cls.third = ClusterFactory() 84 | cls.query = Template(''' 85 | { 86 | clusters(id: "$id") { 87 | edges { 88 | node { 89 | name 90 | type { 91 | name 92 | } 93 | } 94 | } 95 | } 96 | } 97 | ''').substitute(id=obj_to_global_id(cls.third)) 98 | 99 | def test_querying_single_returns_no_error(self): 100 | result = schema.execute(self.query) 101 | assert not result.errors 102 | 103 | def test_querying_single_returns_result(self): 104 | result = schema.execute(self.query) 105 | self.assertEquals(len(result.data['clusters']['edges']), 1) 106 | 107 | def test_querying_single_returns_expected_result(self): 108 | result = schema.execute(self.query) 109 | expected = {'clusters': 110 | {'edges': [ 111 | {'node': {'name': self.third.name, 112 | 'type': {'name': self.third.type.name}}} 113 | ]}} 114 | self.assertEquals(result.data, expected) 115 | 116 | 117 | class UpdateTestCase(TestCase): 118 | @classmethod 119 | def setUpTestData(cls): 120 | cls.first = ClusterFactory() 121 | cls.type = ClusterTypeFactory() 122 | cls.query = Template(''' 123 | mutation{ 124 | updateCluster(input: { id:"$id", name: "New Name", type: "$typeId"}) { 125 | cluster{ 126 | name 127 | type { 128 | name 129 | } 130 | } 131 | } 132 | } 133 | ''').substitute(id=obj_to_global_id(cls.first), typeId=obj_to_global_id(cls.type)) 134 | 135 | def test_updating_returns_no_error(self): 136 | result = schema.execute(self.query) 137 | assert not result.errors 138 | 139 | def test_updating_doesnt_change_count(self): 140 | oldCount = Cluster.objects.all().count() 141 | schema.execute(self.query) 142 | self.assertEquals(Cluster.objects.all().count(), oldCount) 143 | 144 | def test_updating_returns_updated_data(self): 145 | expected = {'updateCluster': 146 | {'cluster': {'name': 'New Name', 147 | 'type': {'name': self.type.name}}}} 148 | result = schema.execute(self.query) 149 | self.assertEquals(result.data, expected) 150 | 151 | def test_updating_alters_data(self): 152 | schema.execute(self.query) 153 | cluster = Cluster.objects.get(id=self.first.id) 154 | self.assertEquals(cluster.name, 'New Name') 155 | self.assertEquals(cluster.type, self.type) 156 | 157 | 158 | class DeleteTestCase(TestCase): 159 | @classmethod 160 | def setUpTestData(cls): 161 | cls.first = ClusterFactory() 162 | cls.query = Template(''' 163 | mutation { 164 | deleteCluster(input: {id: "$id"}) { 165 | cluster { 166 | id 167 | } 168 | } 169 | } 170 | ''').substitute(id=obj_to_global_id(cls.first)) 171 | 172 | def test_deleting_returns_no_error(self): 173 | result = schema.execute(self.query) 174 | assert not result.errors 175 | 176 | def test_deleting_removes_a_type(self): 177 | oldCount = Cluster.objects.all().count() 178 | schema.execute(self.query) 179 | self.assertEquals(Cluster.objects.all().count(), oldCount - 1) 180 | -------------------------------------------------------------------------------- /netbox_graphql/tests/virtualization/tests_virtual_machines.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | from graphene.test import Client 4 | from django.test import TestCase 5 | 6 | from virtualization.models import VirtualMachine 7 | 8 | from netbox_graphql.schema import schema 9 | 10 | from netbox_graphql.tests.utils import obj_to_global_id 11 | from netbox_graphql.tests.factories.virtualization_factories import VirtualMachineFactory, ClusterFactory 12 | from netbox_graphql.tests.factories.tenant_factories import TenantFactory 13 | from netbox_graphql.tests.factories.dcim_factories import PlatformFactory 14 | from netbox_graphql.tests.factories.ipam_factories import IPAddressFactory 15 | 16 | 17 | class CreateTestCase(TestCase): 18 | @classmethod 19 | def setUpTestData(cls): 20 | cls.cluster = ClusterFactory() 21 | cls.tenant = TenantFactory() 22 | cls.platform = PlatformFactory() 23 | cls.ipv4 = IPAddressFactory(family=4) 24 | cls.query = Template(''' 25 | mutation{ 26 | newVirtualMachine(input: { cluster: "$clusterId", tenant: "$tenantId", 27 | platform: "$platformId", primaryIp4: "$ipv4Id", 28 | name: "New Name", status: 1, vcpus: 12, 29 | memory:126, disk: 256 }) { 30 | virtualMachine { 31 | name 32 | cluster { 33 | name 34 | } 35 | tenant { 36 | name 37 | } 38 | platform { 39 | name 40 | } 41 | } 42 | } 43 | } 44 | ''').substitute(clusterId=obj_to_global_id(cls.cluster), 45 | tenantId=obj_to_global_id(cls.tenant), 46 | platformId=obj_to_global_id(cls.platform), 47 | ipv4Id=obj_to_global_id(cls.ipv4)) 48 | 49 | def test_creating_returns_no_error(self): 50 | result = schema.execute(self.query) 51 | assert not result.errors 52 | 53 | def test_creating_returns_data(self): 54 | expected = {'newVirtualMachine': 55 | {'virtualMachine': {'name': 'New Name', 56 | 'cluster': {'name': self.cluster.name}, 57 | 'tenant': {'name': self.tenant.name}, 58 | 'platform': {'name': self.platform.name}, }}} 59 | 60 | result = schema.execute(self.query) 61 | self.assertEquals(result.data, expected) 62 | 63 | def test_creating_creates_it(self): 64 | oldCount = VirtualMachine.objects.all().count() 65 | schema.execute(self.query) 66 | self.assertEquals(VirtualMachine.objects.all().count(), oldCount + 1) 67 | 68 | 69 | class QueryMultipleTestCase(TestCase): 70 | @classmethod 71 | def setUpTestData(cls): 72 | cls.first = VirtualMachineFactory() 73 | cls.second = VirtualMachineFactory() 74 | cls.query = ''' 75 | { 76 | virtualMachines { 77 | edges { 78 | node { 79 | id 80 | } 81 | } 82 | } 83 | } 84 | ''' 85 | 86 | def test_querying_all_returns_no_error(self): 87 | result = schema.execute(self.query) 88 | assert not result.errors 89 | 90 | def test_querying_all_returns_two_results(self): 91 | result = schema.execute(self.query) 92 | self.assertEquals(len(result.data['virtualMachines']['edges']), 2) 93 | 94 | 95 | class QuerySingleTestCase(TestCase): 96 | @classmethod 97 | def setUpTestData(cls): 98 | cls.first = VirtualMachineFactory() 99 | cls.query = Template(''' 100 | { 101 | virtualMachines(id: "$id") { 102 | edges { 103 | node { 104 | name 105 | } 106 | } 107 | } 108 | } 109 | ''').substitute(id=obj_to_global_id(cls.first)) 110 | 111 | def test_querying_single_returns_no_error(self): 112 | result = schema.execute(self.query) 113 | assert not result.errors 114 | 115 | def test_querying_single_returns_result(self): 116 | result = schema.execute(self.query) 117 | self.assertEquals(len(result.data['virtualMachines']['edges']), 1) 118 | 119 | def test_querying_single_returns_expected_result(self): 120 | result = schema.execute(self.query) 121 | expected = {'virtualMachines': 122 | {'edges': [ 123 | {'node': {'name': self.first.name}} 124 | ]} 125 | } 126 | self.assertEquals(result.data, expected) 127 | 128 | 129 | class UpdateTestCase(TestCase): 130 | @classmethod 131 | def setUpTestData(cls): 132 | cls.first = VirtualMachineFactory() 133 | cls.tenant = TenantFactory() 134 | cls.query = Template(''' 135 | mutation { 136 | updateVirtualMachine(input: {id:"$id", tenant: "$tenantId", name: "New Name"}) { 137 | virtualMachine { 138 | name 139 | tenant { 140 | name 141 | } 142 | } 143 | } 144 | } 145 | ''').substitute(id=obj_to_global_id(cls.first), 146 | tenantId=obj_to_global_id(cls.tenant)) 147 | 148 | def test_updating_returns_no_error(self): 149 | result = schema.execute(self.query) 150 | assert not result.errors 151 | 152 | def test_updating_doesnt_change_count(self): 153 | oldCount = VirtualMachine.objects.all().count() 154 | schema.execute(self.query) 155 | self.assertEquals(VirtualMachine.objects.all().count(), oldCount) 156 | 157 | def test_updating_returns_updated_data(self): 158 | expected = {'updateVirtualMachine': 159 | {'virtualMachine': {'name': 'New Name', 160 | 'tenant': {'name': self.tenant.name}}}} 161 | result = schema.execute(self.query) 162 | self.assertEquals(result.data, expected) 163 | 164 | def test_updating_alters_data(self): 165 | schema.execute(self.query) 166 | virtual_machine = VirtualMachine.objects.get(id=self.first.id) 167 | self.assertEquals(virtual_machine.name, 'New Name') 168 | self.assertEquals(virtual_machine.tenant.name, self.tenant.name) 169 | 170 | 171 | class DeleteTestCase(TestCase): 172 | @classmethod 173 | def setUpTestData(cls): 174 | cls.first = VirtualMachineFactory() 175 | cls.query = Template(''' 176 | mutation{ 177 | deleteVirtualMachine(input: { id: "$id" }) { 178 | virtualMachine{ 179 | id 180 | } 181 | } 182 | } 183 | ''').substitute(id=obj_to_global_id(cls.first)) 184 | 185 | def test_deleting_returns_no_error(self): 186 | result = schema.execute(self.query) 187 | assert not result.errors 188 | 189 | def test_deleting_removes_a_type(self): 190 | oldCount = VirtualMachine.objects.all().count() 191 | schema.execute(self.query) 192 | self.assertEquals(VirtualMachine.objects.all().count(), oldCount - 1) 193 | -------------------------------------------------------------------------------- /netbox_graphql/urls.py: -------------------------------------------------------------------------------- 1 | import rest_framework 2 | from rest_framework.permissions import IsAuthenticated 3 | from rest_framework.decorators import authentication_classes, permission_classes, api_view 4 | from rest_framework.settings import api_settings 5 | from django.conf.urls import include, url 6 | from django.conf import settings 7 | 8 | graphiql_enabled = getattr(settings, "GRAPHIQL_ENABLED", True) 9 | 10 | from graphene_django.views import GraphQLView 11 | 12 | class DRFAuthenticatedGraphQLView(GraphQLView): 13 | def parse_body(self, request): 14 | if isinstance(request, rest_framework.request.Request): 15 | return request.data 16 | return super(DRFAuthenticatedGraphQLView, self).parse_body(request) 17 | 18 | @classmethod 19 | def as_view(cls, *args, **kwargs): 20 | view = super(DRFAuthenticatedGraphQLView, cls).as_view(*args, **kwargs) 21 | view = permission_classes((IsAuthenticated,))(view) 22 | view = authentication_classes(api_settings.DEFAULT_AUTHENTICATION_CLASSES)(view) 23 | view = api_view(['GET', 'POST'])(view) 24 | return view 25 | 26 | urlpatterns = [ 27 | #GrapQL 28 | url(r'^$', DRFAuthenticatedGraphQLView.as_view(graphiql=graphiql_enabled)), 29 | ] 30 | -------------------------------------------------------------------------------- /netbox_graphql/virtualization_schema.py: -------------------------------------------------------------------------------- 1 | import graphene 2 | from graphene import AbstractType, Node 3 | from graphene_django.filter import DjangoFilterConnectionField 4 | from graphene_django.types import DjangoObjectType 5 | from graphene_django.converter import convert_django_field 6 | from graphene import AbstractType, Field, Node, ClientIDMutation, AbstractType 7 | from graphene import ID, Boolean, Float, Int, List, String 8 | from graphql_relay.node.node import from_global_id 9 | 10 | from .custom_filter_fields import date_types, string_types, number_types 11 | from .helper_methods import not_none, set_and_save 12 | from virtualization.models import ClusterType, ClusterGroup, Cluster, VirtualMachine 13 | from tenancy.models import Tenant 14 | from dcim.models import Site, Interface, Platform, DeviceRole 15 | from ipam.models import IPAddress 16 | 17 | # Nodes 18 | class ClusterTypeNode(DjangoObjectType): 19 | class Meta: 20 | model = ClusterType 21 | interfaces = (Node, ) 22 | filter_fields = { 23 | 'id': ['exact'], 24 | 'name': string_types, 25 | 'slug': ['exact'], 26 | } 27 | 28 | class ClusterGroupNode(DjangoObjectType): 29 | class Meta: 30 | model = ClusterGroup 31 | interfaces = (Node, ) 32 | filter_fields = { 33 | 'id': ['exact'], 34 | 'name': string_types, 35 | 'slug': ['exact'], 36 | } 37 | 38 | class ClusterNode(DjangoObjectType): 39 | class Meta: 40 | model = Cluster 41 | interfaces = (Node, ) 42 | filter_fields = { 43 | 'id': ['exact'], 44 | 'name': string_types, 45 | } 46 | 47 | class VirtualMachineNode(DjangoObjectType): 48 | class Meta: 49 | model = VirtualMachine 50 | interfaces = (Node, ) 51 | filter_fields = { 52 | 'id': ['exact'], 53 | 'name': string_types, 54 | } 55 | 56 | # Queries 57 | class VirtualizationQuery(AbstractType): 58 | cluster_types = DjangoFilterConnectionField(ClusterTypeNode) 59 | cluster_groups = DjangoFilterConnectionField(ClusterGroupNode) 60 | clusters = DjangoFilterConnectionField(ClusterNode) 61 | virtual_machines = DjangoFilterConnectionField(VirtualMachineNode) 62 | 63 | # Mutations 64 | class NewClusterType(ClientIDMutation): 65 | cluster_type = Field(ClusterTypeNode) 66 | class Input: 67 | name = String() 68 | slug = String() 69 | 70 | @classmethod 71 | def mutate_and_get_payload(cls, input, context, info): 72 | temp = ClusterType() 73 | 74 | fields = [ 'name', 'slug' ] 75 | return NewClusterType(cluster_type=set_and_save(fields, input, temp)) 76 | 77 | class UpdateClusterType(ClientIDMutation): 78 | cluster_type = Field(ClusterTypeNode) 79 | class Input: 80 | id = String() 81 | name = String() 82 | slug = String() 83 | 84 | @classmethod 85 | def mutate_and_get_payload(cls, input, context, info): 86 | temp = ClusterType.objects.get(pk=from_global_id(input.get('id'))[1]) 87 | 88 | fields = [ 'name', 'slug' ] 89 | return UpdateClusterType(cluster_type=set_and_save(fields, input, temp)) 90 | 91 | class DeleteClusterType(ClientIDMutation): 92 | cluster_type = Field(ClusterTypeNode) 93 | class Input: 94 | id = String() 95 | 96 | @classmethod 97 | def mutate_and_get_payload(cls, input, context, info): 98 | temp = ClusterType.objects.get(pk=from_global_id(input.get('id'))[1]) 99 | temp.delete() 100 | return DeleteClusterType(cluster_type=temp) 101 | 102 | # Cluster Group 103 | class NewClusterGroup(ClientIDMutation): 104 | cluster_group = Field(ClusterGroupNode) 105 | class Input: 106 | name = String() 107 | slug = String() 108 | 109 | @classmethod 110 | def mutate_and_get_payload(cls, input, context, info): 111 | temp = ClusterGroup() 112 | 113 | fields = [ 'name', 'slug' ] 114 | return NewClusterGroup(cluster_group=set_and_save(fields, input, temp)) 115 | 116 | class UpdateClusterGroup(ClientIDMutation): 117 | cluster_group = Field(ClusterGroupNode) 118 | class Input: 119 | id = String() 120 | name = String() 121 | slug = String() 122 | 123 | @classmethod 124 | def mutate_and_get_payload(cls, input, context, info): 125 | temp = ClusterGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 126 | 127 | fields = [ 'name', 'slug' ] 128 | return UpdateClusterGroup(cluster_group=set_and_save(fields, input, temp)) 129 | 130 | class DeleteClusterGroup(ClientIDMutation): 131 | cluster_group = Field(ClusterGroupNode) 132 | class Input: 133 | id = String() 134 | 135 | @classmethod 136 | def mutate_and_get_payload(cls, input, context, info): 137 | temp = ClusterGroup.objects.get(pk=from_global_id(input.get('id'))[1]) 138 | temp.delete() 139 | return DeleteClusterGroup(cluster_group=temp) 140 | 141 | ### Cluster 142 | 143 | class NewCluster(ClientIDMutation): 144 | cluster = Field(ClusterNode) 145 | class Input: 146 | name = String(default_value=None) 147 | type = String(default_value=None) 148 | group = String(default_value=None) 149 | site = String(default_value=None) 150 | comments = String(default_value=None) 151 | 152 | @classmethod 153 | def mutate_and_get_payload(cls, input, context, info): 154 | type = input.get('type') 155 | group = input.get('group') 156 | site = input.get('site') 157 | 158 | temp = Cluster() 159 | 160 | if not_none(type): 161 | temp.type = ClusterType.objects.get(pk=from_global_id(type)[1]) 162 | 163 | if not_none(group): 164 | temp.group = ClusterGroup.objects.get(pk=from_global_id(group)[1]) 165 | 166 | if not_none(site): 167 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 168 | 169 | fields = ['name', 'comments'] 170 | return NewCluster(cluster=set_and_save(fields, input, temp)) 171 | 172 | class UpdateCluster(ClientIDMutation): 173 | cluster = Field(ClusterNode) 174 | class Input: 175 | id = String() 176 | name = String(default_value=None) 177 | type = String(default_value=None) 178 | group = String(default_value=None) 179 | site = String(default_value=None) 180 | comments = String(default_value=None) 181 | 182 | @classmethod 183 | def mutate_and_get_payload(cls, input, context, info): 184 | temp = Cluster.objects.get(pk=from_global_id(input.get('id'))[1]) 185 | 186 | type = input.get('type') 187 | group = input.get('group') 188 | site = input.get('site') 189 | 190 | if not_none(type): 191 | temp.type = ClusterType.objects.get(pk=from_global_id(type)[1]) 192 | 193 | if not_none(group): 194 | temp.group = ClusterGroup.objects.get(pk=from_global_id(group)[1]) 195 | 196 | if not_none(site): 197 | temp.site = Site.objects.get(pk=from_global_id(site)[1]) 198 | 199 | fields = ['name', 'comments'] 200 | 201 | return UpdateCluster(cluster=set_and_save(fields, input, temp)) 202 | 203 | class DeleteCluster(ClientIDMutation): 204 | cluster = Field(ClusterNode) 205 | class Input: 206 | id = String() 207 | 208 | @classmethod 209 | def mutate_and_get_payload(cls, input, context, info): 210 | temp = Cluster.objects.get(pk=from_global_id(input.get('id'))[1]) 211 | temp.delete() 212 | return DeleteCluster(cluster=temp) 213 | 214 | ### Virtual machine 215 | 216 | class NewVirtualMachine(ClientIDMutation): 217 | virtual_machine = Field(VirtualMachineNode) 218 | class Input: 219 | cluster = String(default_value=None) 220 | tenant = String(default_value=None) 221 | platform = String(default_value=None) 222 | name = String(default_value=None) 223 | status = Int(default_value=None) 224 | role = String(default_value=None) 225 | primary_ip4 = String(default_value=None) 226 | primary_ip6 = String(default_value=None) 227 | vcpus = Int(default_value=None) 228 | memory = Int(default_value=None) 229 | disk = Int(default_value=None) 230 | comments = String(default_value=None) 231 | 232 | @classmethod 233 | def mutate_and_get_payload(cls, input, context, info): 234 | cluster = input.get('cluster') 235 | tenant = input.get('tenant') 236 | platform = input.get('platform') 237 | role = input.get('role') 238 | primary_ip4 = input.get('primary_ip4') 239 | primary_ip6 = input.get('primary_ip6') 240 | 241 | temp = VirtualMachine() 242 | 243 | if not_none(cluster): 244 | temp.cluster = Cluster.objects.get(pk=from_global_id(cluster)[1]) 245 | 246 | if not_none(tenant): 247 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 248 | 249 | if not_none(platform): 250 | temp.platform = Platform.objects.get(pk=from_global_id(platform)[1]) 251 | 252 | if not_none(role): 253 | temp.role = DeviceRole.objects.get(pk=from_global_id(role)[1]) 254 | 255 | if not_none(primary_ip4): 256 | temp.primary_ip4 = IPAddress.objects.get(pk=from_global_id(primary_ip4)[1]) 257 | 258 | if not_none(primary_ip6): 259 | temp.primary_ip6 = IPAddress.objects.get(pk=from_global_id(primary_ip6)[1]) 260 | 261 | fields = ['name', 'status', 'vcpus', 'memory', 'disk', 'comments'] 262 | return NewVirtualMachine(virtual_machine=set_and_save(fields, input, temp)) 263 | 264 | class UpdateVirtualMachine(ClientIDMutation): 265 | virtual_machine = Field(VirtualMachineNode) 266 | class Input: 267 | id = String() 268 | cluster = String(default_value=None) 269 | tenant = String(default_value=None) 270 | platform = String(default_value=None) 271 | name = String(default_value=None) 272 | status = Int(default_value=None) 273 | role = String(default_value=None) 274 | primary_ip4 = String(default_value=None) 275 | primary_ip6 = String(default_value=None) 276 | vcpus = Int(default_value=None) 277 | memory = Int(default_value=None) 278 | disk = Int(default_value=None) 279 | comments = String(default_value=None) 280 | 281 | @classmethod 282 | def mutate_and_get_payload(cls, input, context, info): 283 | temp = VirtualMachine.objects.get(pk=from_global_id(input.get('id'))[1]) 284 | 285 | cluster = input.get('cluster') 286 | tenant = input.get('tenant') 287 | platform = input.get('platform') 288 | role = input.get('role') 289 | primary_ip4 = input.get('primary_ip4') 290 | primary_ip6 = input.get('primary_ip6') 291 | 292 | if not_none(cluster): 293 | temp.cluster = Cluster.objects.get(pk=from_global_id(cluster)[1]) 294 | 295 | if not_none(tenant): 296 | temp.tenant = Tenant.objects.get(pk=from_global_id(tenant)[1]) 297 | 298 | if not_none(platform): 299 | temp.platform = Platform.objects.get(pk=from_global_id(platform)[1]) 300 | 301 | if not_none(role): 302 | temp.role = DeviceRole.objects.get(pk=from_global_id(role)[1]) 303 | 304 | if not_none(primary_ip4): 305 | temp.primary_ip4 = IPAddress.objects.get(pk=from_global_id(primary_ip4)[1]) 306 | 307 | if not_none(primary_ip6): 308 | temp.primary_ip6 = IPAddress.objects.get(pk=from_global_id(primary_ip6)[1]) 309 | 310 | fields = ['name', 'status', 'vcpus', 'memory', 'disk', 'comments'] 311 | 312 | return UpdateVirtualMachine(virtual_machine=set_and_save(fields, input, temp)) 313 | 314 | class DeleteVirtualMachine(ClientIDMutation): 315 | virtual_machine = Field(VirtualMachineNode) 316 | class Input: 317 | id = String() 318 | 319 | @classmethod 320 | def mutate_and_get_payload(cls, input, context, info): 321 | temp = VirtualMachine.objects.get(pk=from_global_id(input.get('id'))[1]) 322 | temp.delete() 323 | return DeleteVirtualMachine(virtual_machine=temp) 324 | 325 | class VirtualizationMutations(AbstractType): 326 | # Cluster Type 327 | new_cluster_type = NewClusterType.Field() 328 | update_cluster_type = UpdateClusterType.Field() 329 | delete_cluster_type = DeleteClusterType.Field() 330 | # Cluster Group 331 | new_cluster_group = NewClusterGroup.Field() 332 | update_cluster_group = UpdateClusterGroup.Field() 333 | delete_cluster_group = DeleteClusterGroup.Field() 334 | # Cluster 335 | new_cluster = NewCluster.Field() 336 | update_cluster = UpdateCluster.Field() 337 | delete_cluster = DeleteCluster.Field() 338 | # Virtual Machine 339 | new_virtual_machine = NewVirtualMachine.Field() 340 | update_virtual_machine = UpdateVirtualMachine.Field() 341 | delete_virtual_machine = DeleteVirtualMachine.Field() 342 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=1 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import find_packages, setup 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'README.rst'), 'r') as readme: 5 | README = readme.read() 6 | 7 | with open(os.path.join(os.path.dirname(__file__), 'VERSION'), 'r') as version_file: 8 | VERSION = version_file.read().replace('\n', '') 9 | 10 | # allow setup.py to be run from any path 11 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 12 | 13 | setup( 14 | name='django-netbox-graphql', 15 | version=VERSION, 16 | packages=find_packages(), 17 | include_package_data=True, 18 | license='MIT', 19 | description='Django module which provides a GraphQL API for Netbox (For django 1.11)', 20 | long_description=README, 21 | url='https://github.com/ninech/django-netbox-graphql', 22 | author='nine.ch', 23 | author_email='dev@nine.ch', 24 | classifiers=[ 25 | 'Environment :: Web Environment', 26 | 'Framework :: Django', 27 | 'Framework :: Django :: 1.11', 28 | 'Intended Audience :: Developers', 29 | 'License :: OSI Approved :: MIT License', 30 | 'Operating System :: OS Independent', 31 | 'Programming Language :: Python', 32 | 'Programming Language :: Python :: 2', 33 | 'Programming Language :: Python :: 2.6', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: 3', 36 | 'Programming Language :: Python :: 3.2', 37 | 'Programming Language :: Python :: 3.3', 38 | 'Programming Language :: Python :: 3.4', 39 | 'Topic :: Internet :: WWW/HTTP', 40 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 41 | ], 42 | keywords='django netbox graphql python', 43 | install_requires=[ 44 | 'graphene-django==1.3', 45 | 'graphene==1.4', 46 | 'graphql-core==1.1', 47 | ], 48 | extras_require={ 49 | 'test': [ 50 | 'snapshottest', 51 | 'factory_boy' 52 | ] 53 | }, 54 | ) 55 | --------------------------------------------------------------------------------