Skip to main content
RunBook Academy

AnsibleII · Ansible ArchitectureThe execution model

What Ansible does not do for you

Intermediate⏱ ~17 minansible

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

Not yet marked complete on this device.

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 / rescue gives 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.
Read-only / Safea fleet the run knows nothing about
$ 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=4

Dealt 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.

JobWhy Ansible is the wrong toolWhat is right
MonitoringIt runs when invoked; monitoring must be continuousA monitoring system
AlertingNo daemon, no evaluation loopThe monitoring system
BackupIt configures the backup; it is not the backupA backup system, verified by restore
Provisioning infrastructureIt configures hosts; creating them is a different model with different state handlingAn infrastructure provisioning tool
Application deployment orchestration at high frequencyPossible, but the ordering and rollback story is yours to buildA deployment system, or Ansible plus significant scaffolding
Secret storageVault encrypts secrets at rest in your repository; it is not a secret manager with rotation and auditA 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

  1. Q1. A play fails at task 12 of 20 against a group of hosts. What is the state of those hosts?

  2. Q2. A playbook run that reports every task successful demonstrates that the estate is in the declared state.

  3. Q3. Which of these follow directly from Ansible having no daemon? Select all that apply.

  4. Q4. Why is provisioning infrastructure a poor fit for Ansible, as distinct from configuring it?

Passing score: 75%. Answers are checked in this browser.