Running It, and Running It Again
Scenario: A playbook works perfectly the first time. Run twice in a row, it reports fourteen changes on the second pass and restarts the service again.
New words, in plain English
- Idempotency - the property that running the same automation again changes nothing, because everything is already correct.
- Convergence - the process of bringing a machine from wherever it is to the described state.
- Dry run -
--check: report what would change without changing it. - Diff -
--diff: show the actual textual difference a change would make.
Idempotency is the property that makes automation safe to run on a schedule, in CI, and during an incident. It is not automatic - it is a property of the modules and options you chose.
Most ansible.builtin modules are idempotent by design. copy compares checksums and does nothing if the content already matches. file checks whether the path already has the requested state. user checks whether the account already exists with the requested properties.
The modules that are not idempotent are command and shell, because Ansible cannot know what an arbitrary command does. They run every time and report changed every time unless you tell them otherwise - which is where creates, removes, and changed_when come in, covered properly in the next phase.
The two-run test is the entire discipline in one sentence: run it twice; the second run must be changed=0.
Analogy: A thermostat is idempotent. Ask for 20 degrees, and if the room is already at 20 it does nothing at all. A heater with a plain on-switch is not: press it twice and you have made the room twice as hot, having asked for exactly the same thing.
A worked example
# The everyday workflow, in order:
ansible-playbook site.yml --syntax-check # does it parse?
ansible-playbook site.yml --list-hosts # who would it touch?
ansible-playbook site.yml --check --diff # what would it change?
ansible-playbook site.yml # do it
ansible-playbook site.yml # MUST be changed=0
# Useful extras
ansible-playbook site.yml --limit web01 # one host only
ansible-playbook site.yml -v # show module results
ansible-playbook site.yml --start-at-task 'Deploy the release'
--check deserves a caveat you will meet properly in Phase 4: it is only as honest as the playbook makes it. Tasks marked check_mode: false genuinely execute during a dry run, and command/shell tasks are skipped by default - which can make a later task that depends on their output fail during --check even though a real run works.
--diff pairs naturally with --check and is the single most useful flag for change review: it prints the actual before/after of every file the run would touch, which is a far better change ticket than any description you would write by hand.
Tip: Make --check --diff your reflex for the first run of any change you did not write yourself. It costs nothing and reads like a proper change request.
Goal: Put this to work in the ansible-idempotent-modules lab. Open/labs/ansible, pickansible-idempotent-modules, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.