AnsibleII · Ansible ArchitectureThe execution model
What Ansible does not do for you
What you'll learn
- Enumerate the guarantees Ansible does not provide, and why each follows from the architecture
- Identify which part of the course deals with the consequence of each
- Avoid designing automation that assumes a guarantee that is not there
- Explain why a successful run is not a statement that the fleet is correct
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
Part II has built the execution model. This lesson states its boundaries in one place, so that no later part has to introduce a limitation apologetically, and so that you can recognise a design that assumes a guarantee Ansible does not offer.
None of these are defects. Every one follows directly from the architecture in the previous six lessons, and most of them are the price of a property you wanted.
1. There is no daemon
Ansible is a program you run. Between invocations there is no Ansible process anywhere in your estate — not on the managed nodes, and not on the controller either.
Follows from: the agentless model.
Consequences:
- Nothing notices that a scheduled run did not happen. A run that does not occur produces no error, because there is nothing alive to generate one.
- Two people can run the same playbook against the same hosts at the same time. Nothing detects the overlap and nothing holds a lock.
- The record of a run exists only where its output went.
Dealt with in: the observability and auditing part, which covers callbacks and run records; the automation-platform part, which is about deliberately adding a daemon back.
2. There is no continuous enforcement
A change made to a managed host after a run persists until the next run. There is no background process reverting it.
Follows from: the same thing.
Consequences:
- “We manage this with Ansible” is a statement about what happens when the playbook runs, not about the state of the host right now.
- Between runs, the fleet is exactly as trustworthy as the people and processes with access to it.
- The interval between runs is your drift window, and it is a number you should be able to state.
Dealt with in: the drift and convergence part.
3. There is no state database
Ansible keeps no record of what it did last time. With the default
memory cache plugin, even gathered facts do not survive the process.
Follows from: the agentless model, and the deliberate choice not to store state on managed nodes.
Consequences:
- Every run rediscovers everything, which is why fact gathering costs time on every run.
- A task cannot condition on “the previous run did X”. It can only inspect the state that run left behind.
- Ansible cannot tell you what changed since last week. It can tell you what differs from the declaration right now, which is a different question with a different answer.
Dealt with in: the facts part, which covers fact caching when you want to opt into some persistence.
4. There is no dependency graph across hosts
Within a play, tasks run in the order written. Across hosts, the default
linear strategy keeps hosts in step task by task. That is the whole of
the ordering model.
There is no way to express “configure the database cluster before the application servers, and only if the cluster reports healthy” as a declared dependency. You express it as sequence: separate plays, ordered, with an explicit health check between them.
Follows from: the model being a task runner over an inventory rather than a scheduler over a graph.
Consequences:
- Cross-host ordering is your responsibility, written as play order.
- A play that must not start until another has succeeded needs an
explicit gate — an assertion, a
wait_for, or a health check. - There is no automatic reasoning about which hosts depend on which.
Dealt with in: the playbooks part; the delegation part, for tasks that must run somewhere other than the host being configured; the rolling deployment part, where drain, deploy, verify and return-to-service is exactly this problem.
5. There is no automatic rollback
If a play fails at task 12 of 20, tasks 1 to 11 have happened and stay happened. Ansible does not undo them, and it has no general mechanism that could.
Follows from: convergence being a forward operation. The declaration describes a target state; there is no record of the prior state to return to.
This is the guarantee people most often assume exists, so it is worth being blunt: reverting the declaration and re-running is not rollback. It applies an older declaration to hosts that have since changed, which is another forward convergence that happens to move in a backwards direction. If the failed run installed a package, reverting the commit that added it does not remove it unless something declares it absent.
Consequences:
- A partial run leaves a fleet in a state no declaration describes.
block/rescuegives you a place to put compensating actions, which is not the same as rollback — you write the compensation.- Anything genuinely irreversible needs a backup taken before the change, by you.
Dealt with in: the error handling part, for block/rescue; the
maintenance windows and rollback part, for the patterns Ansible does not
give you for free.
6. There is no guarantee about a host it could not reach
The most important one, and the one this course keeps returning to.
An unreachable host has not been checked, not been changed, and not
been verified. Its state is unknown. A run that reports success for 260
hosts and unreachable for 40 has told you nothing whatsoever about
those 40.
Follows from: the push model.
Consequences:
- A successful run is not a statement that the fleet is correct. It is a statement about the hosts it reached.
- Coverage — how many hosts a run reached, against how many it targeted — is a metric you must instrument yourself.
- Compliance evidence derived from a run silently excludes the hosts the run could not reach, unless you check.
$ ansible-playbook -i inv.ini reach.yml; echo "EXIT=$?"PLAY RECAP *********************************************************************
db01 : ok=0 changed=0 unreachable=1 failed=0
web01 : ok=0 changed=0 unreachable=1 failed=0
web02 : ok=0 changed=0 unreachable=1 failed=0
EXIT=4Dealt with in: the failure modes part; the targeting part; the observability part.
What Ansible is not for
Distinct from the list above, which is about guarantees. This is about scope, and it is worth stating because reaching for the wrong tool is a more expensive mistake than any of the six.
| Job | Why Ansible is the wrong tool | What is right |
|---|---|---|
| Monitoring | It runs when invoked; monitoring must be continuous | A monitoring system |
| Alerting | No daemon, no evaluation loop | The monitoring system |
| Backup | It configures the backup; it is not the backup | A backup system, verified by restore |
| Provisioning infrastructure | It configures hosts; creating them is a different model with different state handling | An infrastructure provisioning tool |
| Application deployment orchestration at high frequency | Possible, but the ordering and rollback story is yours to build | A deployment system, or Ansible plus significant scaffolding |
| Secret storage | Vault encrypts secrets at rest in your repository; it is not a secret manager with rotation and audit | A secrets manager, with Ansible retrieving from it |
The provisioning row is the boundary people cross most often, and it is worth being precise about why. Creating infrastructure requires tracking what you created so you can modify or destroy it — that is state, and state is exactly what Ansible does not keep. A tool that provisions without tracking what it provisioned will create duplicates. Ansible can call provisioning APIs, and does, but the tracking is not something the model provides.
The list as a design check
When you design automation, check it against these. Each row is a question worth asking of a design before it ships.
| Does the design assume… | If yes |
|---|---|
| …that a host stays configured between runs? | Bound the drift window, and say what it is |
| …that a failed run leaves nothing behind? | Design the compensation explicitly |
| …that hosts are configured in a particular cross-host order? | Express it as play order with an explicit gate |
| …that everything targeted was reached? | Instrument coverage and alert on it |
| …that the tool knows what it did last time? | Store that yourself, outside Ansible |
| …that something will notice if the run stops happening? | Add a dead-man check |
Knowledge check
Knowledge check · 4 questions
Q1. A play fails at task 12 of 20 against a group of hosts. What is the state of those hosts?
Q2. A playbook run that reports every task successful demonstrates that the estate is in the declared state.
Q3. Which of these follow directly from Ansible having no daemon? Select all that apply.
Q4. Why is provisioning infrastructure a poor fit for Ansible, as distinct from configuring it?
Passing score: 75%. Answers are checked in this browser.