Ansible Idempotency Design Prompt
Make Ansible tasks idempotent — when to use changed_when / failed_when, check mode, validating shell tasks.
- Target user
- Ansible engineers writing reliable playbooks
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior automation engineer who has refactored thousands of non-idempotent Ansible tasks. You know that `shell` and `command` are idempotency landmines. I will provide: - The task that's non-idempotent - Current behavior - Symptom (always changed, unwanted side effects) Your job: 1. **Idempotent by default modules**: - `package`, `service`, `template`, `copy`, `file`, `user`, `group`, `lineinfile` - Self-report changed state 2. **Non-idempotent by default**: - `shell` and `command` - Always report changed unless overridden - Use `changed_when` to control 3. **For shell idempotency**: - `creates:` — skip if path exists - `removes:` — skip if path missing - `changed_when:` — derive change from output 4. **For check mode** (`--check`): - Dry-run; reports what would change - Modules implement check mode - Custom shell tasks: `check_mode: false` to skip 5. **For diff mode** (`--diff`): - Shows what would change in templates / files - Useful with --check 6. **For multi-step idempotency**: - Compose tasks: check current state, then change if needed - register: + when: 7. **For testing idempotency**: - Run twice; second should report 0 changed - Molecule has idempotence test 8. **For "always changed"**: - shell/command without changed_when - lineinfile with regex matching multiple - Diff in template due to whitespace Mark DESTRUCTIVE: tasks with side effects in check mode (data writes), always-changed tasks causing handler restarts every run, removing changed_when without testing. --- Non-idempotent task: ```yaml [PASTE] ``` Symptom: [DESCRIBE]
Why this prompt works
Idempotency is Ansible’s promise. This prompt walks patterns.
How to use it
- Prefer idempotent modules.
- For shell, use changed_when.
- Test with double-run.
- Validate with —check.
Useful commands
# Dry-run (check mode)
ansible-playbook playbook.yml --check
# With diff
ansible-playbook playbook.yml --check --diff
# Verify idempotency: run twice
ansible-playbook playbook.yml
ansible-playbook playbook.yml | grep changed=0
# Second run should have changed=0 for all hosts
# Molecule idempotence test
molecule test
Patterns
Idempotent shell with creates
- name: Initialize database
shell: /usr/local/bin/init-db.sh
args:
creates: /var/lib/myapp/db-initialized.marker
Idempotent shell with changed_when
- name: Get current version
shell: myapp --version
register: app_version
changed_when: false # this never changes anything
- name: Upgrade if old version
shell: /usr/local/bin/upgrade-myapp.sh
when: app_version.stdout is version('2.0.0', '<')
lineinfile carefully
# Risk: regex matches multiple lines
- name: Ensure log level
lineinfile:
path: /etc/myapp.conf
regexp: '^log_level' # exact prefix
line: 'log_level = info'
state: present
Template + handler
- name: Render config
template:
src: app.conf.j2
dest: /etc/myapp.conf
notify: restart myapp # only fires if template changed
handlers:
- name: restart myapp
service:
name: myapp
state: restarted
Common findings this catches
- Shell always changed → add
changed_when: falseor output-derived. - Service restart every run → handler triggered by always-changed task.
- Template diff every run → whitespace, line endings.
- lineinfile multi-match → tighten regex.
- Check mode shows nothing for custom tasks → implement
check_mode: falsefor unsafe. - Failure mid-task → handle with rescue / block.
- Conditional with undefined → default(false).
When to escalate
- Module-specific bug — file upstream.
- Reusable role idempotency review — coordinate.
- Check mode coverage gap — engineering.
Related prompts
-
Ansible Handlers & Notification Prompt
Use Ansible handlers correctly — notify, listen, force handlers, multi-handler chains, when handlers don't fire.
-
Ansible Playbook Generator Prompt
Generate idempotent Ansible playbooks with proper handlers, tags, and check-mode support.
-
Ansible Role Generator Prompt
Generate a complete, idempotent Ansible role with proper directory structure, defaults, handlers, molecule tests, and OS-family conditionals.