AnsibleXXX · Host Targeting and Blast RadiusNarrowing a run
Verifying the effective host list before you run
What you'll learn
- Produce the exact host list a given command will act on, before running it
- Choose the authoritative verification command rather than a convenient one
- Avoid the --graph trap, which reports inventory contents rather than run scope
- Verify the other half of scope with --list-tasks and --list-tags
Prerequisites
Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11
This is the skill the part exists to teach.
Before you run something that changes hosts, determine exactly which hosts it will change — from the command line, not from belief.
It takes about four seconds, connects to nothing, and is the only
control that catches every targeting mistake in this part at once: a
mistyped group, an exclusion that did not fire, a glob that reached
staging, a dynamic source that grew, a --limit that intersected to
nothing.
The commands are simple. The discipline is running the right one and comparing the count against a number you decided beforehand.
The authoritative command
ansible-playbook -i inventory/ site.yml --limit 'us_east:!canary' --list-hostsIt is authoritative because it accounts for both halves of the
target: the play’s own hosts: line, and your --limit. Every other
form accounts for one of them.
$ ansible-playbook -i inventory/hosts.yml site.yml --limit eu_west --list-hostsplaybook: site.yml
play #1 (web): Configure the web tier TAGS: []
pattern: ['web']
hosts (1):
web01.example.com
play #2 (db): Configure the database tier TAGS: []
pattern: ['db']
hosts (1):
db01.example.comRead three things from that output:
- The
pattern:line is the play’s ownhosts:value, unmodified. - The
hosts (N):count is the effective blast radius for that play. - The number of plays — a
site.ymlwith nine plays has nine separate answers, and the total is their union, not any single one.
The trap: --graph ignores --limit
This one has a specific name because it catches people who are doing the right thing.
$ ansible-inventory -i inventory/hosts.yml --graph --limit canary@all:
|--@ungrouped:
|--@production:
| |--@web:
| | |--web01.example.com
| | |--web02.example.com
| | |--web03.example.com
| | |--web04.example.com
| |--@db:
| | |--db01.example.com
| | |--db02.example.com
| |--@cache:
| | |--cache01.example.com
|--@staging:
| |--@web_stage:
| | |--stage-web01.example.com
| | |--stage-web02.example.com
| |--@db_stage:
| | |--stage-db01.example.com
|--@eu_west:
...This is documented, not a bug. The tool says so in its own help:
$ ansible-inventory --helpActions:
One of following must be used on invocation, ONLY ONE!
--graph create inventory graph, if supplying pattern it must
be a valid group name. It will ignore limit
--host HOST Output specific host info, works as inventory script.
It will ignore limit
--list Output all hosts info, works as inventory script--list does honour it:
$ ansible-inventory -i inventory/hosts.yml --list --limit canary --yamlall:
children:
canary:
hosts:
web01.example.com: {}
eu_west:
hosts:
web01.example.com: {}
production:
children:
web:
hosts:
web01.example.com:
ansible_host: 192.0.2.11The other half of scope: which tasks
Knowing the hosts answers half the question. --list-tasks answers the
other half, and it resolves includes, imports and roles rather than
showing you the file.
$ ansible-playbook -i inventory/hosts.yml site.yml --list-tasksplaybook: site.yml
play #1 (web): Configure the web tier TAGS: []
tasks:
Install the package TAGS: [packages]
Render the configuration TAGS: [config]
Restart the service TAGS: [config, restart]
play #2 (db): Configure the database tier TAGS: []
tasks:
Tune the database TAGS: [config]It honours --tags, which is how you verify that a tagged run does what
you think:
$ ansible-playbook -i inventory/hosts.yml site.yml --list-tasks --tags config play #1 (web): Configure the web tier TAGS: []
tasks:
Render the configuration TAGS: [config]
Restart the service TAGS: [config, restart]
play #2 (db): Configure the database tier TAGS: []
tasks:
Tune the database TAGS: [config]--list-tags gives the vocabulary rather than the tasks — useful when
somebody hands you an unfamiliar playbook and a ticket saying “run it
with the config tag”:
$ ansible-playbook -i inventory/hosts.yml site.yml --list-tags play #1 (web): Configure the web tier TAGS: []
TASK TAGS: [config, packages, restart]
play #2 (db): Configure the database tier TAGS: []
TASK TAGS: [config]The four commands, and what each is for
| Question | Command | Honours --limit |
|---|---|---|
| What will this run touch? | ansible-playbook <pb> --limit X --list-hosts | Yes — authoritative |
| What does this pattern resolve to? | ansible <pattern> --list-hosts | Yes (-l also works) |
| What does my inventory contain? | ansible-inventory --graph | No — ignored |
| What variables do the in-scope hosts have? | ansible-inventory --list --limit X | Yes |
| What tasks would run? | ansible-playbook <pb> --list-tasks | Host list not shown |
| What tags exist? | ansible-playbook <pb> --list-tags | n/a |
- Decide the number first. "This should hit about twelve hosts" is the expectation, and it has to exist before the output does.
- Build the exact command you intend to run, then append --list-hosts.
- Read the count on each play. Compare it with the number from step one. A mismatch stops here.
- Spot-check the list itself for a host that should not be there, especially one from a different environment.
- Append --list-tasks instead, and confirm the task set matches the change you think you are making, including under any --tags.
- Remove the --list flag and run, with --check --diff first if the change is not trivially reversible.
Step one is the step people skip, and it is the one that makes the rest work. The output is not self-validating: twelve hosts and three hundred hosts look equally reasonable on screen. Only the comparison against a prior expectation turns the number into information.
Knowledge check
Knowledge check · 5 questions
Q1. Which command answers "which hosts will this playbook change" most completely?
Q2. You run ansible-inventory --graph --limit canary and see every host in the inventory. What has happened?
Q3. --list-hosts shows only the hosts in the first serial batch when the play sets serial.
Q4. A verification run and the real run selected different hosts. Which explanations point at a genuine problem worth investigating? Select all that apply.
Q5. Why does the procedure insist on deciding the expected host count before running --list-hosts?
Passing score: 75%. Answers are checked in this browser.