You've already forked ansible-netbox-inventory
5.9 KiB
5.9 KiB
Ansible NetBox Inventory
An Ansible dynamic inventory script that sources hosts from NetBox, either from the IP address list or from the virtual machine list, with a single configurable filter option on top.
Contract in one sentence: one source, one optional filter, one value — set in a config file, overridable per-run through environment variables.
Features
- Two host sources: IP addresses (
ipam/ip-addresses) and virtual machines (virtualization/virtual-machines) - Filter by tenant name, VRF name, cluster name, site name, hostname domain, or restrict IP addresses to the ones that have a DNS name (deduplicated)
- Name-based filters are resolved server-side (name → id) so NetBox does the narrowing, not the script
- Hosts land in a single
netboxgroup with host variables delivered through_meta, so Ansible calls the script exactly once - Plain Ansible inventory script protocol (
--list/--host), no plugin installation, no collections
Requirements
- Python 3.10+
requestsandPyYAML(PyYAML ships with Ansible anyway)- A NetBox API token with read permissions on the objects you inventory
Installation
git clone https://git.bjphoster.com/source/ansible-netbox-inventory.git
cd ansible-netbox-inventory
cp config.yaml.example config.yaml
$EDITOR config.yaml
Point Ansible at the script directly:
ansible-inventory -i netbox_inventory.py --list
ansible all -i netbox_inventory.py -m ping
ansible-playbook -i netbox_inventory.py site.yml
Configuration
Everything lives in config.yaml next to the script (gitignored, see
config.yaml.example):
netbox:
url: "https://netbox.example.com"
token: "0123456789abcdef0123456789abcdef01234567"
verify_ssl: true
timeout: 30
inventory:
source: "ip-addresses"
filter: "tenant"
filter_value: "customer1"
| Key | Default | Meaning |
|---|---|---|
netbox.url |
— (required) | Base URL of the NetBox instance |
netbox.token |
— (required) | API token, sent as Authorization: Token ... |
netbox.verify_ssl |
true |
Verify the TLS certificate |
netbox.timeout |
30 |
Per-request timeout in seconds |
inventory.source |
ip-addresses |
ip-addresses or virtual-machines |
inventory.filter |
none | Filter option, see the table below |
inventory.filter_value |
none | Value for the filter option |
Every relevant key can be overridden through the environment, which is how you run several differently-filtered inventories off one config file:
| Variable | Overrides |
|---|---|
NETBOX_INVENTORY_CONFIG |
Path to the config file |
NETBOX_URL |
netbox.url |
NETBOX_TOKEN |
netbox.token |
NETBOX_INVENTORY_SOURCE |
inventory.source |
NETBOX_INVENTORY_FILTER |
inventory.filter |
NETBOX_INVENTORY_FILTER_VALUE |
inventory.filter_value |
Filters
One filter at a time, each takes exactly one value:
| Filter | Sources | Value | Behaviour |
|---|---|---|---|
tenant |
both | tenant name | Objects assigned to that tenant |
domain |
both | domain | Hostname ends with the domain, on a label boundary (web.example.com matches example.com, notexample.com does not) |
named |
ip-addresses | true/false (empty = true) |
Only addresses with a DNS name, deduplicated by hostname (first one wins) |
vrf |
ip-addresses | VRF name | Addresses in that VRF |
cluster |
virtual-machines | cluster name | Virtual machines in that cluster |
site |
virtual-machines | site name | Virtual machines at that site |
Examples:
# every IP address of one tenant
NETBOX_INVENTORY_FILTER=tenant NETBOX_INVENTORY_FILTER_VALUE=customer1 \
ansible-inventory -i netbox_inventory.py --list
# only IPs that resolve to something, one host per DNS name
NETBOX_INVENTORY_FILTER=named \
ansible-inventory -i netbox_inventory.py --list
# all virtual machines of one cluster
NETBOX_INVENTORY_SOURCE=virtual-machines \
NETBOX_INVENTORY_FILTER=cluster NETBOX_INVENTORY_FILTER_VALUE=proxmox01 \
ansible-inventory -i netbox_inventory.py --list
# every host in a DNS domain
NETBOX_INVENTORY_FILTER=domain NETBOX_INVENTORY_FILTER_VALUE=example.com \
ansible-inventory -i netbox_inventory.py --list
Behaviour
- IP addresses: the inventory hostname is the DNS name when set, the bare
address otherwise;
ansible_hostis always the bare address (no prefix length). Host variables:netbox_ip_address,netbox_dns_name,netbox_tenant,netbox_vrf,netbox_description. - Virtual machines: the inventory hostname is the VM name;
ansible_hostis set to the primary IP when the VM has one, otherwise Ansible falls back to resolving the name. Host variables:netbox_status,netbox_cluster,netbox_site,netbox_tenant. - Duplicate inventory names (two IPs sharing a DNS name, outside the
namedfilter) keep both hosts: the second one falls back to its bare address as the inventory name. - Pagination is followed transparently;
config_contextis excluded from the virtual machine query to keep responses small. - Errors (unreachable NetBox, bad token, unknown tenant/cluster/site/VRF name,
invalid source/filter combination) print one readable line on stderr and
exit non-zero, so
ansible-inventoryfails loudly instead of running against an empty host list.
Development
make dev-environment # venv + dev dependencies
make test # unit tests (mocked API, no NetBox needed)
make lint # ruff checks
make format # ruff formatter
Known limitations
- One filter option per run, filters do not combine; run the script twice with different environments if you need an intersection
- No caching: every run hits the NetBox API
- Devices (
dcim/devices) are not a source, only IP addresses and virtual machines - Name lookups (tenant, VRF, cluster, site) take the first match when NetBox returns several objects with the same name
License
GPL-2.0-or-later. See LICENSE for more information.