AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible troubleshooting - Error 301: no-changed-when

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

"Ansible Error 301, no-changed-when, ensures tasks properly report changes. Use changed_when to define task modifications accurately."

Ansible troubleshooting - Error 301: no-changed-when

Introduction

Ansible, the automation tool of choice for many IT professionals, allows users to automate tasks, manage configurations, and deploy software with ease and efficiency. However, the reliability and predictability of Ansible playbooks depend on how well tasks report changes. In this article, we will explore Ansible Error 301, "no-changed-when," in Ansible-Lint which emphasizes the importance of ensuring that tasks return changes to results or conditions. We'll discuss the best practices for handling task outputs, improving playbook reliability, and preventing unexpected behavior.

See also: Ansible troubleshooting - Error 102: No Jinja2 in 'when' Conditions

The Problem: Tasks Not Reflecting Changes

Ansible Error 301, "no-changed-when," checks whether tasks within a playbook report changes to results or conditions. Tasks that do not naturally detect whether a change has occurred should use the changed_when clause to define under what conditions they should be considered "changed." This is particularly important for tasks that read or execute arbitrary commands, such as those using the shell or command modules.

Problematic Code Example:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Does not handle any output or return codes
      ansible.builtin.command: cat {{ my_file | quote }} # <- Does not handle the command output.

In the problematic code above, the task does not handle the output of the cat command or the return codes, making it difficult to determine if the task resulted in any changes.

Output:

WARNING  Listing 1 violation(s) that are fatal
no-changed-when: Commands should not change things if nothing needs doing.
301.yml:5 Task/Handler: Does not handle any output or return codes

Read documentation for instructions on how to ignore specific rule violations.

                  Rule Violation Summary                  
 count tag             profile rule associated tags       
     1 no-changed-when shared  command-shell, idempotency 

Failed: 1 failure(s), 0 warning(s) on 1 files. Last profile that met the validation criteria was 'safety'. Rating: 3/5 star

Correcting Tasks to Reflect Changes

To address Ansible Error 301 and ensure tasks properly reflect changes, you should use the changed_when clause or other relevant arguments. Here's the corrected code:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Handle shell output with return code
      ansible.builtin.command: cat {{ my_file | quote }}
      register: my_output # <- Registers the command output.
      changed_when: my_output.rc != 0 # <- Uses the return code to define when the task has changed.

In the corrected code, the task registers the command output and uses the changed_when clause to specify under what conditions the task should be considered "changed."

See also: Ansible troubleshooting - Error 104: Deprecated Bare Vars

Choosing the Right changed_when Value

The snippet above is the example from the ansible-lint documentation, but in real playbooks the right value of changed_when depends on what the command actually does. There are three common patterns.

Read-only commands never change anything. A command that only reads state — cat, ls, getsebool, a --dry-run — should report changed_when: false so it always shows as ok:

    - name: Read a configuration file (never reports changed)
      ansible.builtin.command: cat /etc/myapp/config.ini
      register: my_output
      changed_when: false

Detect a real change from the command output. When a command may or may not modify the system, inspect its stdout (not the return code) to decide. For example, a script that prints UPDATED only when it changed something:

    - name: Apply config and report changed only when it acted
      ansible.builtin.command: /usr/local/bin/apply-config.sh
      register: my_output
      changed_when: "'UPDATED' in my_output.stdout"

Separate failure from change with failed_when. changed_when controls the changed status; failed_when controls the failed status. They are independent, so a non-zero return code that you expect can be treated as success while still reporting whether anything changed:

    - name: Run a check that returns 1 when drift is found
      ansible.builtin.command: /usr/local/bin/drift-check.sh
      register: my_output
      failed_when: my_output.rc not in [0, 1]
      changed_when: my_output.rc == 1

As a rule of thumb: use changed_when: false for anything read-only, and base changed_when on stdout content for commands that conditionally change state.

Benefits of Tasks Reflecting Changes

  1. Reliability: Ensuring that tasks reflect changes improves the reliability and predictability of your Ansible playbooks.
  1. Transparency: It provides transparency into which tasks have an impact on the system and under what conditions they trigger changes.
  1. Security: By detecting and reporting changes, you can identify any unexpected alterations or unauthorized activities within your automation environment.
  1. Adherence to Best Practices: Using changed_when aligns with Ansible best practices and ensures that your playbooks behave as expected.

The "changed_when" Clause for Handlers

It's worth noting that the "changed_when" clause applies not only to regular tasks but also to handlers. Handlers are special tasks that are triggered only when notified by other tasks. Just like regular tasks, handlers should also be configured to report changes when necessary.

See also: Ansible troubleshooting - Error 105: Deprecated Module Usage

Conclusion

Ansible Error 301, "no-changed-when", emphasizes the importance of ensuring that tasks reflect changes in your Ansible playbooks. By using the changed_when clause and other relevant arguments, you can improve playbook reliability and maintain transparency in your automation processes.

In the world of automation, consistency, and predictability are paramount. Therefore, when working with Ansible, make it a practice to handle task outputs and return codes effectively to ensure that your playbooks operate as intended.

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home