An Ansible collection featuring a high-performance dynamic inventory plugin for NetBox powered by NetBox's GraphQL API.
By leveraging GraphQL, this collection fetches deeply nested device and virtual machine relationships—such as interfaces, IP addresses, and services—in single server-side requests without expensive client-side REST endpoint joins. The plugin is completely schema-agnostic, enabling users to supply custom .graphql query files to build inventory hosts from any NetBox object type without modifying Python code.
- GraphQL-Powered Performance: Resolves nested relationships (interfaces, IP addresses, services) server-side, collapsing inventory generation into a single HTTP request per source.
- Schema-Agnostic Design: No hardcoded NetBox object types or options. Any field selected in your
.graphqlfile automatically becomes an Ansible host variable. - Native Ansible
constructedSupport: Use standard Ansiblecompose,groups, andkeyed_groupsoptions to dynamically shape host variables and group hosts. - Automatic Pagination: Seamless server-side pagination for large NetBox instances via
OffsetPaginationInput. - Intelligent Connection Target: Automatic DNS name and IP address fallback chain for
ansible_host. - Nested List Matching: Includes the
any_attribute_equalsJinja test plugin for cross-referencing nested list structures incomposeexpressions.
Install the collection directly from Ansible Galaxy:
ansible-galaxy collection install mikuuw.netbox_graphqlAlternatively, add it to your project's requirements.yml:
---
collections:
- name: mikuuw.netbox_graphql
version: ">=0.1.0"- Create your inventory configuration (e.g.
netbox_graphql.yml):
plugin: mikuuw.netbox_graphql.nb_inventory_graphql
api_endpoint: "{{ lookup('env', 'NETBOX_API') }}"
token: "{{ lookup('env', 'NETBOX_TOKEN') }}"
ansible_host_dns_name: true
sources:
- name: vms
query_file: queries/virtual_machines.graphql
list_path: virtual_machine_list
hostname: "{{ name }}"
- name: devices
query_file: queries/devices.graphql
list_path: device_list
hostname: "{{ name }}"
keyed_groups:
- key: services | map(attribute='name') | list
prefix: service
- key: status
prefix: status- Add a GraphQL query file (e.g.
queries/virtual_machines.graphql):
query ($pagination: OffsetPaginationInput) {
virtual_machine_list(pagination: $pagination) {
id
name
status
primary_ip4 {
address
dns_name
}
services {
name
ports
}
}
}- Run
ansible-inventory:
ansible-inventory -i netbox_graphql.yml --graphParameters:
api_endpoint(required): NetBox root URL (derived as<api_endpoint>/graphql/).token(optional): NetBox API token or header dictionary.sources(required): List of GraphQL sources to fetch.name(required): Unique label for the source.query_file(required): Path to.graphqlquery file.list_path(required): Dotted path to the list of objects in the GraphQL response.hostname(required): Jinja2 template evaluated against each item to set inventory hostname.variables(optional): Additional GraphQL variables to pass to the query.
ansible_host_dns_name(default:false): Prefer DNS name over IP address foransible_host.
Checks if at least one element of a nested list has an attribute path equal to a given value. Useful in compose expressions to match nested interfaces or IP addresses:
compose:
primary_interface: >-
interfaces
| selectattr('ip_addresses', 'any_attribute_equals', 'address', primary_ip4.address)
| first | default(omit)GNU General Public License v3.0 or later (GPL-3.0-or-later).