How Does When Condition Work in Ansible
In Ansible, conditionals are used to run tasks based on specific conditions. The when
keyword is a conditional statement that specifies a task to be carried out based on the outcome of a certain condition. This could be an Ansible fact or a variable. The conditional statement takes a boolean expression as an argument, and if the expression evaluates to true, the playbook task is executed, otherwise, it is skipped.
This tutorial explores the Ansible when
conditional statement and how to use it to execute tasks in playbooks.
#Ansible When syntax
The most basic use case of the Ansible when
statement is executing a single task. In this example, the playbook consists of a single task that updates the local cache on target nodes running Ubuntu distribution only.
---
- name: Update local cache
hosts: all
become: yes
tasks:
- name: Update local cache on Ubuntu
apt:
update_cache: yes
when: ansible_distribution == "Ubuntu"
The playbook updates the local cache on all nodes running Ubuntu and skips the rest of the nodes.
Run your deployments in a scalable and cost-effective open cloud infrastructure. Cherry Servers' secure virtual private servers offer automatic scaling, flexible pricing, and 24/7 technical support. Our pre-defined Ansible module helps you automate the installation and configuration.
#How does When
Conditional work in Ansible?
As we have seen in our earlier example, the when
conditional statement runs a task if a particular condition is met. The condition can be based either on an Ansible fact, a declared variable, or a registered variable that stores the output of a previous task.
Let’s explore various use cases of the Ansible when
statement.
#When Conditional based on Ansible facts
Ansible facts is a term that refers to information gathered about target nodes or managed hosts. This data is stored in JSON format and is used to make key decisions when running tasks on the target nodes. Ansible facts include details such as the IP address, filesystem, operating system, system architecture, date and time, and much more.
To view all the Ansible facts, run the following Ansible ad-hoc command. The setup
module fetches all the data from the remote target nodes and displays it on your terminal.
ansible all -m setup
Ansible facts provide a set of variables for referencing system information for example hardware and filesystem information, OS type, date and time, etc. When running playbooks, you can set conditions based on these facts to execute tasks.
The following playbook is an example of how you can leverage Ansible facts. In this example, the playbook installs Apache on hosts running Debian servers only. The ansible_distribution
Ansible facts variable is set to Debian
to dictate which servers the tasks should be executed on.
---
- name: Install Apache on Ubuntu
hosts: webservers
become: yes
tasks:
- name: Update apt package cache
apt:
update_cache: yes
when: ansible_distribution == "Debian"
- name: Install Apache
apt:
name: apache2
state: present
when: ansible_distribution == "Debian"
Both tasks ( updating local cache and installing Apache ) are executed on servers running Debian OS only and skipped on non-Debian servers.
Sample Output
PLAY [Install Apache on Debian] *******************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [5.199.162.116]
ok: [5.199.161.74]
TASK [Update apt package cache] *******************************************************************
skipping: [5.199.161.74]
ok: [5.199.162.116]
TASK [Install Apache] *****************************************************************************
skipping: [5.199.161.74]
changed: [5.199.162.116]
PLAY RECAP ****************************************************************************************
5.199.161.74 : ok=1 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
5.199.162.116 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#Using when condition with logical OR operator
Logical operators are used to combine multiple conditions. The OR
operator executes a task when one or the other condition evaluates to true
.
The following playbook example installs a package called neofetch
on hosts running either Debian or Ubuntu Linux distribution.
---
- name: Install a package on Debian or Ubuntu
hosts: all
become: yes
tasks:
- name: Install neofetch on Debian or Ubuntu
apt:
name: neofetch
state: present
when: ansible_distribution == "Debian" or ansible_distribution == "Ubuntu"
Sample Output
PLAY [Install a package on Debian or Ubuntu] ***************************************************************
TASK [Gathering Facts] *************************************************************************************
ok: [5.199.162.116]
ok: [5.199.161.74]
TASK [Install neofetch on Debian or Ubuntu] ****************************************************************
changed: [5.199.162.116]
changed: [5.199.161.74]
PLAY RECAP *************************************************************************************************
5.199.161.74 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
5.199.162.116 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
From the output, you can see that the task has been executed on both nodes because the condition has been met.
#Using when condition with logical NOT operator
The logical NOT operator ( != ) specifies tasks to be carried out when a certain condition is NOT TRUE
or a variable does not equal a specific value. The operator is often used to exclude hosts during task execution.
The following example installs the git
package on all nodes that are not of the RedHat
OS family.
---
- name: Install Git
hosts: all
become: yes
tasks:
- name: Install Git on all hosts except the RedHat family
apt:
name: git
state: present
when: ansible_os_family != "RedHat"
#Using when condition with logical AND operator
The AND
operator is used when you have multiple conditions that all need to evaluate to true
. The following playbook example installs the SQLite3 package on Debian 11 servers only. The ansible_distribution
and ansible_distribution_major_version
facts are set to “Debian” and “11” respectively. The AND
operator ensures that both conditions are met for the task to run.
---
- name: Install sqlite3
hosts: all
become: yes
tasks:
- name: Install sqlite on Debian 11 servers
apt:
name: sqlite3
state: present
when: ansible_distribution == "Debian" and ansible_distribution_major_version == "11"
Alternatively, you can specify the conditions to be met as a list. This has the same effect as using the AND
operator.
- name: Install sqlite on Debian 11 servers
apt:
name: sqlite3
state: present
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version == "11"
#When Conditional based on variables
In Ansible, you can define conditions to be evaluated before a task is executed. If the condition is met, the task is evaluated, otherwise, it will be skipped.
The following playbook has a single variable called create_file
. When the variable evaluates to true
the index.html
file will be copied from the /var/www/html
directory on the remote webserver to the /srv/
directory.
---
- hosts: webservers
become: yes
vars:
- create_file: true
tasks:
- name: create a backup index html file
copy:
src: /var/www/html/index.html
dest: /srv/index.html
remote_src: yes
when: create_file
When the boolean condition is met, you’ll see a changed
status in the TASK output:
Sample Output
TASK [Gathering Facts] *****************************************************************************
ok: [5.199.162.116]
TASK [create a backup index html file] *************************************************************
changed: [5.199.162.116]
When the create_file
variable is set to false
the task is skipped. The skipping
status will be displayed in the play output showing that the task has been aborted.
TASK [Gathering Facts] *****************************************************************************
ok: [5.199.162.116]
TASK [create a backup index html file] *************************************************************
skipping: [5.199.162.116]
#When Conditional based on the output from the previous tasks
Sometimes, you might need to save the output of a task in a variable and leverage it in other tasks. The Ansible register
keyword lets you capture the output of a task and store it in a variable for use in subsequent tasks in the play.
In the following playbook, the register
keyword captures the output of the uptime -p
command and stores it in a variable called uptime_file
. In the second task, the debug
module prints the variable’s value to stdout.
---
- hosts: webservers
tasks:
- name: Register the uptime of the server
command: 'uptime -p'
register: uptime_file
ignore_errors: True
- name: Display the server uptime
debug:
var: uptime_file
You can use the when
conditional to filter the output stored in a variable. If the output matches a condition, a particular task is executed.
In the next playbook example, the first task captures the output of the cat /etc/hosts
command in a variable called hosts_file
.
The second task evaluates the output stored in the hosts_file
variable and checks if it contains the localhost
entry. If the entry exists, the message The word 'localhost' exists in the /etc/hosts file
is printed.
Otherwise, if the localhost
entry is missing, the last task is executed and the message The word 'localhost' is not present in the /etc/hosts file
is printed.
---
- hosts: webservers
tasks:
- name: Register the contents of the /etc/hosts file
command: cat /etc/hosts
register: hosts_file
- name: Check if the word 'localhost' exists in the /etc/hosts file
debug:
msg: "The word 'localhost' exists in the /etc/hosts file: 1"
when: hosts_file.stdout.find('localhost') != -1
- name: Display a message when the word 'localhost' is not found
debug:
msg: "The word 'localhost' is not present in the /etc/hosts file."
when: hosts_file.stdout.find('localhost') == -1
Output
TASK [Register the contents of the /etc/hosts file] ************************************************
changed: [5.199.161.74]
TASK [Check if the word 'localhost' exists in the /etc/hosts file] *********************************
ok: [5.199.161.74] => {
"msg": "The word 'hosts' exists in the /etc/hosts file: True"
}
TASK [Display a message when the word 'localhost' is not found] ***********************************
skipping: [5.199.161.74]
PLAY RECAP *****************************************************************************************
5.199.161.74 : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
The last task is skipped because the /etc/hosts
file contains the localhost
entry.
#When Conditional with loops
It's not uncommon to combine conditionals and loops in Ansible playbooks. This helps automate complex tasks a great deal. Let's consider adding multiple users to a remote node only if those users do not exist. Below is a playbook that does exactly that.
---
- name: Create users on servers
hosts: all
become: true
vars:
create_users:
- name: alex
- name: bob
tasks:
- name: check if users exist
command: "id "
ignore_errors: yes
register: check_user
loop: ""
changed_when: false
- name: create users if they don't exist
user:
name: ""
state: present
loop: ""
when: item.rc != 0
Let’s break this playbook down:
A list of users is defined using the create_users
variable.
The first task checks to see if each user defined in the list exists on the target node using the id
command. The ignore_errors
attribute is used for error handling and prevents the task from failing if the user does not exist on the target node.
The output of the id
command is stored in the check_user
variable using the register
directive.
In the second task, the play loops over the output of the check_user
variable. If the return code, denoted by rc
is not 0 ( implying the user does not exist on the target node ), the user is created using the user
module.
The playbook uses a loop to iterate over a list of two users and a conditional to determine whether a user is to be created based on their existence on the target node.
#Conclusion
This brings us to the end of this tutorial. In this guide, you have learned about the Ansible when
statement and how to use it to run tasks based on Ansible facts, declared variables, registered variables, and loops.
Cloud VPS - Cheaper Each Month
Start with $9.99 and pay $0.5 less until your price reaches $6 / month.