Ansible is a powerful, accessible, and open-source automation tool that offers immense functionality combined with simple and declarative language.
Ansible provides an idempotent nature which allows it only to make the defined changes when necessary. But how does Ansible decide if a task changed something on a remote system?
More often than not, the default behavior suffices. However, we might sometimes need to specify the custom conditions to decide if a task made any changes. Enter the “changed_when” directive.
The “changed_when” directive allows us to define when a task should be marked as “changed” which can be based on the outcome of the task or even on the results of other tasks.
Ansible Changed_When
In Ansible, you can specify the conditions under which a task is deemed to have “modified” a remote host using the “changed_when” directive.
This provision allows you to decide, grounded on outputs or return values, if Ansible should record a change in its metrics and if an associated handler needs activation.
Example 1: Basic Example
Let us explore an essential playbook to use the “changed_when” directive.
Suppose we have a shell command that outputs a random number between 1 and 5. Suppose we only want to consider the task changed if the random number is 3.
We can define the playbook as follows:
- hosts: localhost
tasks:
- name: Generate a random number
command: echo $((1 + RANDOM % 5))
register: result
changed_when: "'3' in result.stdout"
The given playbook uses the “register” directive to capture the command output. We then use the “changed_when” directive to check if the output has the number 3. If true, Ansible marks the task as changed.
Example 2: Ansible File Manipulation
We can also use the “changed_when” directive in file manipulation. For example, suppose we are trying to append a given entry to a file but only want the task marked as changed if the entry does not exist.
We can define a playbook as follows:
- hosts: localhost
tasks:
- name: Check if entry exists in file
command: grep 'ff02::1 ip6-allnodes' /etc/hosts
register: grep_result
failed_when: false
changed_when: false
- name: Append line to file
lineinfile:
path: /etc/hosts
line: 'ff02::1 ip6-allnodes'
when: grep_result.rc != 0
changed_when: true
In this example, we check if the entry exists in the target file. The task will never be marked as changed because of the “changed_when: false”. The second task appends the entry if it doesn’t exist.
Example 3: Complex Queries
We can also create complex and more precise conditions by chaining multiple commands and tools. For example, suppose we want to check the disk usage and only mark the task as changed when the disk usage exceeds to 90%.
We can define a playbook to accomplish the previous task as follows:
- hosts: localhost
tasks:
- name: Check disk usage
command: df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1
register: disk_usage
changed_when: disk_usage.stdout|int > 90
In this example, we combine the df, awk, and cut commands to check the disk usage percentage. We then use the “changed_when” parameter to mark the task as changed when the specified condition is true.
Conclusion
As discussed in this tutorial, the “changed_when” directive gives us the flexibility to define the custom conditions for determining whether an Ansible task has made changes. Hence, it offers more granular control over the changed status of a task, ensuring that our playbooks accurately represent the state of the target systems.