You've already forked ansible-netbox-inventory
docs: installation, configuration, filter and behaviour documentation
This commit is contained in:
162
README.md
162
README.md
@@ -1 +1,163 @@
|
||||
# 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 `netbox` group 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+
|
||||
- `requests` and `PyYAML` (PyYAML ships with Ansible anyway)
|
||||
- A NetBox API token with read permissions on the objects you inventory
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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`):
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```sh
|
||||
# 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_host` is 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_host`
|
||||
is 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 `named`
|
||||
filter) keep both hosts: the second one falls back to its bare address as
|
||||
the inventory name.
|
||||
- Pagination is followed transparently; `config_context` is 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-inventory` fails loudly instead of running
|
||||
against an empty host list.
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
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](LICENSE) for more information.
|
||||
|
||||
Reference in New Issue
Block a user