When the Inventory Cannot Be a File
Scenario: Cloud instances are created and destroyed by an autoscaler forty times a day. The hand-maintained inventory file was accurate for about six minutes after it was written.
New words, in plain English
- Static inventory - a file you write and maintain by hand.
- Dynamic inventory - inventory generated at run time by asking a real source of truth - a cloud API, a CMDB, a database.
- Inventory plugin - the modern, supported way to do dynamic inventory: a YAML config file that Ansible turns into hosts and groups.
- Inventory script - the older mechanism: any executable that prints JSON in a documented shape when called with
--list.
Any inventory maintained by a human will be wrong. Dynamic inventory removes the human by asking the system that actually knows.
The modern approach is an inventory plugin: a small YAML file naming a plugin and its options, which Ansible executes to build hosts, groups and variables. Cloud providers, container platforms and asset databases all ship them, and they support keyed_groups to build groups automatically from tags.
The older approach is an inventory script - any executable, in any language, that honours a simple contract:
- called with
--list, print a JSON object mapping group names to their hosts, plus a_metakey containinghostvarsfor every host; - called with
--host <name>, print a JSON object of that host's variables (returning{}is fine once_metais populated, and is far faster because Ansible then makes only one call instead of one per host).
Both mechanisms can coexist: Ansible accepts multiple inventory sources and merges them, so a static file of fixed infrastructure can sit alongside a dynamic source of ephemeral instances.
Analogy: A static inventory is a printed phone book. A dynamic inventory is directory enquiries: slower per lookup, but it knows about the person who moved in yesterday.
A worked example
# The shape an inventory script must print for --list
{
"webservers": { "hosts": ["web01", "web02"] },
"dbservers": { "hosts": ["dbprod"] },
"loadbalancers": { "hosts": ["lb01"] },
"production": { "children": ["webservers", "dbservers", "loadbalancers"] },
"_meta": {
"hostvars": {
"web01": { "ansible_host": "127.0.0.1", "ansible_port": 2201, "ansible_user": "web01" },
"web02": { "ansible_host": "127.0.0.1", "ansible_port": 2202, "ansible_user": "web02" }
}
}
}
Dynamic inventory shifts a class of failure from "stale data" to "unavailable data": if the API is down or the credentials expired, you now have no inventory at all. Production setups usually cache the result (ansible.cfg supports inventory caching) and fail loudly rather than silently returning an empty estate - because an empty inventory produces a green, entirely no-op run.
Whichever mechanism you use, ansible-inventory --graph and --list remain the tools that tell you what Ansible actually built, as opposed to what you meant to build.
Warning: A dynamic inventory that errors and returns zero hosts produces a completely successful-looking run that did nothing at all. Assert a minimum expected host count in CI if this matters to you - and it usually does.
Goal: Put this to work in the ansible-dynamic-inventory lab. Open/labs/ansible, pickansible-dynamic-inventory, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.