Skip to content

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 --list

The program should roughly do:

Did I receive --list?
    ↓
Yes → generate inventory
    ↓
Convert it to JSON
    ↓
Print JSON to stdout

So “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:

  • --listrequired 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 --list output includes _meta.hostvars, Ansible can get host variables from there without needing a separate --host call.

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 existwebservers.hosts
  • host-specific variables_meta.hostvars

So if your requirement specifically says:

“The script must respond to --list and 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.py

Ansible 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.hostvars directly in --list output, 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.
Last updated on