← Recipes

阅读中文版本

Template an Idempotent Ansible Role

Write an Ansible role that converges to the same state on repeated runs, using declarative modules instead of shell tasks.

~35 minansibleopsautomation

Task

Convert imperative shell steps into idempotent Ansible modules so reruns cause no changes.

When to use this

Re-running a playbook reports changes every time, making it unsafe to run in production.

Prerequisites

  • Ansible installed
  • An inventory to test against
  • SSH access

Steps

1. Replace shell with a declarative module and handler.

- name: Configure service
  template:
    src: service.conf.j2
    dest: /etc/app/service.conf
    mode: '0644'
  notify: restart app

Expected output: Files are only rewritten when content differs, and the handler fires only on change.

2. Re-run the playbook and expect no changes.

ansible-playbook -i inventory site.yml
ansible-playbook -i inventory site.yml | tail -5

Expected output: The second run reports changed=0, proving idempotency.

Troubleshooting

Problem

Handlers not firing

Solution

Ensure the task actually reports changed; handlers only run on change.

Problem

Command tasks always changed

Solution

Add creates or changed_when conditions to command and shell tasks.

Limitations

  • Some operations need command and cannot be fully idempotent.
  • Idempotency does not imply correctness of the desired state.
  • Does not cover secret management.

What this recipe does

Convert imperative shell steps into idempotent Ansible modules so reruns cause no changes.

Re-running a playbook reports changes every time, making it unsafe to run in production.

Prerequisites

  • Ansible installed
  • An inventory to test against
  • SSH access

Procedure

  1. Replace shell with a declarative module and handler.
- name: Configure service
  template:
    src: service.conf.j2
    dest: /etc/app/service.conf
    mode: '0644'
  notify: restart app

Expected result: Files are only rewritten when content differs, and the handler fires only on change.

  1. Re-run the playbook and expect no changes.
ansible-playbook -i inventory site.yml
ansible-playbook -i inventory site.yml | tail -5

Expected result: The second run reports changed=0, proving idempotency.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows a second run reports zero changes and the configured service restarts only when its config actually changed.

Troubleshooting

Handlers not firing — Ensure the task actually reports changed; handlers only run on change.

Command tasks always changed — Add creates or changed_when conditions to command and shell tasks.

Limitations

  • Some operations need command and cannot be fully idempotent.
  • Idempotency does not imply correctness of the desired state.
  • Does not cover secret management.