Understanding Ansible Idempotency | Generated by AI

Home 2025.11

Yes, you’re absolutely correct!

In Ansible, idempotency means that running the same playbook multiple times on a system that is already in the desired state should result in no changes (i.e., all tasks report ok or skipped, not changed).

However, whether a playbook is truly idempotent does depend entirely on how it’s written.

Cases where idempotency is broken (non-idempotent behavior):

You mentioned the classic example — and it’s spot-on:

- name: Increment a counter (BAD - not idempotent)
  shell: echo $(( $(cat /tmp/counter) + 1 )) > /tmp/counter

Every run increases the value → changed every time → not idempotent.

Other common non-idempotent patterns:

How to make it idempotent (correct way):

Use declarative modules that check the desired state:

- name: Ensure counter is exactly 5 (idempotent)
  copy:
    content: "5\n"
    dest: /tmp/counter

- name: Ensure line exists in file (idempotent)
  lineinfile:
    path: /etc/myconfig.conf
    line: "debug = true"
    state: present

- name: Ensure service is restarted only when needed
  service:
    name: nginx
    state: restarted
  listen: "restart nginx"
  # Only triggered when config actually changed

- name: Ensure latest code from specific commit (idempotent)
  git:
    repo: https://github.com/example/app.git
    dest: /var/www/app
    version: v1.2.3   # pinned → same every time

Summary

So yes — you’re 100% right: idempotency depends completely on the details of how the playbook and tasks are written.

Well spotted! This is one of the most common pitfalls when people say “my playbook isn’t idempotent” — it’s almost always because they used imperative-style shell commands instead of Ansible’s declarative modules.


Back

x-ai/grok-4.1-fast

Donate