Dynamic Inventory Script
Back in the very first inventory chapter, this course made a promise: static files are the foundation, not the endpoint, and dynamic inventory would get its proper treatment later. This is that chapter.
The Limitation, Restated
Every host in this entire course has come from a hand-written inventory.yaml. That’s fine for a stable, small lab — genuinely wrong the moment infrastructure changes on its own. Cloud instances get created and destroyed by autoscaling; containers restart with new IPs; a hand-maintained file goes stale the instant reality moves faster than someone remembers to edit it.
What Dynamic Inventory Actually Is
Instead of a static file Ansible parses directly, dynamic inventory is a program — a script, or a plugin — that Ansible runs, expecting it to report the current, real host list fresh, every single time. Point -i at something executable instead of a plain YAML file, and Ansible treats it completely differently: rather than parsing it as data, it runs it, and reads whatever that program prints as the inventory.
The Script Contract
A dynamic inventory script needs to respond correctly to being run with --list (your inventory script should understand --list option), printing a specific JSON structure to stdout:
{
"servers": {
"hosts": ["ubuntu", "fedora"]
},
"_meta": {
"hostvars": {
"ubuntu": {"ansible_host": "10.0.0.1", "ansible_user": "alice"},
"fedora": {"ansible_host": "10.0.0.2", "ansible_user": "alice"}
}
}
}Look closely — this is genuinely the same information as the static inventory.yaml used throughout this entire course, just generated programmatically instead of hand-written. Groups, hosts, and per-host variables, all present, just produced by running code instead of reading a file.
The _meta.hostvars block matters specifically: including it directly in the --list output lets Ansible get every host’s variables in one call, rather than needing a separate --host <name> invocation per host — the modern, efficient way to write one of these.
Inventory Script Should Recongnize --list Argument
The program/script should recognize --list as a command-line argument and then perform the appropriate action.
For example:
./inventory.py --listThe program should roughly do:
Did I receive --list?
↓
Yes → generate inventory
↓
Convert it to JSON
↓
Print JSON to stdoutSo “respond correctly to being run with --list” means the program needs to handle that argument, not just ignore it or fail with an “unknown argument” error.
For example (very rough one):
import sys
import json
if "--list" in sys.argv:
inventory = {"webservers": {"hosts": ["web1", "web2"]}}
print(json.dumps(inventory))Then:
./inventory.py --list{"webservers": {"hosts": ["web1", "web2"]}}--host Is Old Convention
For Ansible’s newer dynamic inventory interface, --host can be optional depending on how the inventory is structured.
The important part is:
--list→ required behavior for a script-style dynamic inventory. It returns the inventory in JSON.--host <hostname>→ legacy/optional behavior. Ansible may call it, but if your--listoutput includes_meta.hostvars, Ansible can get host variables from there without needing a separate--hostcall.
For example:
{
"webservers": {
"hosts": ["web1", "web2"]
},
"_meta": {
"hostvars": {
"web1": {
"ansible_host": "10.0.0.10"
},
"web2": {
"ansible_host": "10.0.0.11"
}
}
}
}Here, Ansible gets both:
- which hosts exist →
webservers.hosts - host-specific variables →
_meta.hostvars
So if your requirement specifically says:
“The script must respond to
--listand print this JSON structure”
then you should focus on implementing --list correctly. You don’t necessarily need another --host unless the specification explicitly requires it.
Using A Script-Based Inventory
chmod +x inventory_script.py
ansible-playbook site.yaml -i inventory_script.pyAnsible detects the executable bit and runs the script, using its output exactly as it would have used a static file’s parsed content — every other tool covered in this course (ansible-inventory --host, patterns, --limit) works identically regardless of which kind of inventory is actually behind it.
Best Practices
- Keep a dynamic inventory script genuinely fast. Ansible may invoke it more than once per run — a script making slow network calls on every invocation can noticeably slow down every single playbook execution.
- Include
_meta.hostvarsdirectly in--listoutput, avoiding the older, slower--host-per-host pattern entirely. - Treat a hand-written script as a teaching tool for understanding the mechanism — the next chapter builds one for our own lab, but a real production setup usually reaches for an existing, properly maintained plugin instead, covered directly there.