AnsibleVII · Ad-Hoc ExecutionAd-hoc execution
When ad-hoc is right, and when it is not
What you'll learn
- Apply a four-question test to decide between an ad-hoc command and a playbook
- Distinguish an inspection from a change when the module name does not make it obvious
- Recognise the three arguments for ad-hoc change that do not survive scrutiny
- Name the narrow cases where an ad-hoc change is genuinely the right call
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
The previous lesson covered what an ad-hoc command does. This one covers whether to run it, which is the harder question and the one you will be answering under time pressure with an incident bridge open.
Ansible’s own documentation frames ad-hoc commands as the thing you use “when you want to do a quick task on a few machines” and playbooks as the thing for anything you will repeat. That is true and insufficient. It tells you nothing about the 03:00 case where you will run this once, will never repeat it, and are about to touch 40 machines.
The four questions
Ask these in order. The first no is the answer.
- Is it read-only?
- Is it a single action?
- Would you be content to have no record of it?
- Would you object if a colleague did this unreviewed?
Four yeses means run it. Anything else means write it down first, even if “writing it down” is a six-line playbook you commit afterwards.
The questions are ordered by how cheap they are to answer. Question 1 is usually settled by the module name. Question 4 requires you to imagine someone else doing exactly what you are about to do, which is uncomfortable and is the point.
Question 1: is it read-only?
Read-only means the module makes no change on the target under any argument you passed. Not “I think this is safe”. Not “it only reads a file”. The module either has no write path or it does.
These are unambiguously read-only:
| Module | What it does |
|---|---|
ansible.builtin.ping | Confirms a connection and a usable Python |
ansible.builtin.setup | Gathers facts |
ansible.builtin.stat | Returns metadata about one path |
ansible.builtin.slurp | Returns the contents of one file, base64-encoded |
ansible.builtin.find | Returns a list of files matching criteria |
ansible.builtin.service_facts | Returns service state |
ansible.builtin.package_facts | Returns installed packages |
ansible.builtin.getent | Queries a passwd, group or hosts database |
These are not, whatever arguments you give them: command, shell,
raw, script, file, copy, template, lineinfile, service,
systemd, package, user, cron, mount.
Question 2: is it a single action?
An ad-hoc command runs one task. Two ad-hoc commands run two tasks with nothing coordinating them, and that gap is where the damage lives.
Consider the sequence “push the config, then restart the service”. As two ad-hoc commands:
$ ansible web -i inventory.ini -b -m ansible.builtin.copy -a "src=./nginx.conf dest=/etc/nginx/nginx.conf"$ ansible web -i inventory.ini -b -m ansible.builtin.service -a "name=nginx state=restarted"Nothing connects them. If the copy failed on two hosts, the restart still runs on all forty; if the copy changed nothing on thirty of them, the restart happens anyway and you have taken thirty services down for no reason. A playbook expresses the dependency in one line — the copy notifies a handler and the restart happens only where something actually changed — and the ad-hoc form cannot express it at all.
The single-action rule is therefore not about counting commands. It is about whether the second thing depends on the outcome of the first. If it does, the coupling has to live somewhere, and if it does not live in a playbook it lives in your head.
Question 3: would you be content to have no record?
By default an ad-hoc command produces no artefact. Not a log entry, not a diff, not a file. The complete record is your terminal scrollback and your shell history, on your workstation.
Ask what you would need if this went wrong. “Which hosts did the change actually land on?” is answerable from the terminal for about as long as the terminal stays open. “What was the previous value?” is not answerable at all — no module you ran recorded it.
For an inspection, the answer is usually yes, you are content: the state you observed still exists and you can observe it again. For a change, the answer is almost always no, and the next lesson but one is entirely about what that costs.
Question 4: would you object if a colleague did it unreviewed?
This is the question that catches the cases the first three miss.
You know the estate, you know the pattern resolves to the right hosts, you know the module. So did the person who caused the last incident. The test is not whether you are competent; it is whether the action is one that should require a second pair of eyes regardless of who runs it.
If the honest answer is “I would want to see that in a pull request first”, the fact that you are the one typing it does not change the answer.
The three arguments that do not survive
“It is faster.” It is faster to type. A six-line playbook takes about ninety seconds to write, and it is the same ninety seconds whether you write it before the change or during the incident review afterwards. The speed argument compares the wrong two things: writing the playbook against typing the command, rather than writing the playbook against reconstructing what happened from partial evidence.
“It is a one-off.” Almost nothing is. The change you make once is the change someone repeats next quarter from your shell history, without the context that made it correct the first time. And a genuinely one-off change is precisely the one nobody will remember, which is an argument for recording it, not against.
“It is an emergency.” Emergencies are when the cost of a mistake is highest and your judgement is worst. This is the strongest of the three arguments and it is still usually wrong, because the emergency case is where “which hosts did I just change?” matters most. What an emergency genuinely justifies is skipping review, not skipping the artefact — write the playbook, run it, get it reviewed after.
The rule, short enough to remember
Inspect ad-hoc. Change in a playbook.
If you must change ad-hoc, name the host with
--limit, and write the playbook afterwards anyway.
That is the whole position of this part. Everything else is the justification.
Knowledge check
Knowledge check · 4 questions
Q1. At 02:40 a service is down on one host in a 40-host group. You know the fix is a single service restart. Which action best fits the decision rule in this lesson?
Q2. Which of these ad-hoc commands pass question 1, "is it read-only?" Select all that apply.
Q3. Because an ad-hoc command runs a single task, running two ad-hoc commands in sequence is equivalent to a two-task playbook.
Q4. Which argument for making an ad-hoc change carries the most weight, and why is it still usually wrong?
Passing score: 75%. Answers are checked in this browser.