If you need to execute Ansible tasks based on different conditions, then you’re in for a treat. Ansible when
and other conditionals lets you evaluate conditions, such as based on OS, or if one task is dependent on the previous task.
In this tutorial, you’re going to learn how to work with Ansible when
and other conditionals so you can execute tasks without messing things up.
Let’s get into it!
Prerequisites
This tutorial comprises hands-on examples. If you’d like to follow along, be sure you have the following in place:
- An Ansible controller host – This tutorial uses Ansible v2.9.24 hosted on an Ubuntu 18.04.5 LTS machine.
- A remote computer to run commands.
- You’ll need an inventory file set up and one or more hosts already configured to run Ansible command and playbooks. The tutorial will use an inventory group called web.
Working with Ansible when
with Multiples Tasks in Playbook
Having multiple tasks in a playbook can be a drag if they all execute without specific conditions. Let’s begin this tutorial by defining Ansible when
conditions in the Ansible playbook with multiple tasks.
1. Open a terminal on the Ansible controller host.
2. Run the commands below to create a directory and name it anything you prefer in your home directory, and navigate to that directory.
For this example, the directory is named ansible_when_condition_demo
. This directory will contain the playbook you’ll use to invoke the when condition within the Ansible task.
# Create a directory named ~/ansible_when_condition_demo
mkdir ~/ansible_when_condition_demo
# Change working directory to ~/ansible_when_condition_demo
cd ~/ansible_when_condition_demo
3. In your preferred code editor, create a YAML file in the ~/ansible_when_condition_demo directory. In this example, the file is called my_playbook.yml. Copy and paste the YAML playbook contents below to the my_playbook.yml file.
In both tasks below (Task-1
and Task-2
), the when
conditions check which operating system every remote host is on. The result is then passed to the ansible_os_family
placeholder variable on each task.
If the ansible_os_family
placeholders’ value equals either RedHat
or Debian
, then Ansible executes either of the tasks to install Apache.
---
- name: Ansible tasks to work on Ansible When
# Defining the remote server where Ansible will run
hosts: web
remote_user: ubuntu # Using Remote host as ubuntu
become: true # Run the tasks as an elevated user (sudo)
tasks:
# (Task-1) Checks if ansible_os_family == "RedHat" and then Installs Apache on Remote Node
- name: Install Apache on CentOS Server
yum: name=httpd state=present
become: yes
when: ansible_os_family == "RedHat"
# (Task-2) Checks if ansible_os_family == "Debian" and then Installs Apache on Remote Node
- name: Install Apache on Ubuntu Server
apt:name=apache2 state=present
become: yes
when: ansible_os_family == "Debian"
4. Now run the ansible-playbook
command below to execute the tasks defined in the playbook (my_playbook.yml) on the remote host, defined in your existing inventory file.
ansible-playbook my_playbook.yml
In the screenshot below, you can see that:
- The first TASK returned an OK status, which shows the task doesn’t require any changes.
- The second TASK returned the skipping status. When the condition is not met, the task will be skipped.
- The third TASK returned a changed status, which indicates the remote host wasn’t in the proper state (i.e., Apache is not present) and was modified to install Apache.
5. Open a SSH session to the remote host, that was the target of the Ansible playbook, using your favorite SSH client to verify that Apache is installed and running.
6. Finally, run the service
command below to verify if Apache is installed (status apache2
) on the remote host.
service status apache2
As you can see below, you’ve installed Apache service on the remote machine.
Working with Ansible when
and loops
You previously executed Ansible tasks according to an Ansible when
for a particular parameter such as ansible_os_family
. But perhaps you need to check a condition with multiple parameters defined in a list. If so, then try adding a loop
in a task.
Open the my_playbook.yml file you previously created (step three under the “Working with Ansible when
with Multiples Tasks in Playbook”). Replace the content of the my_playbook.yml file with the code below.
The task in the code below (Task-1
) runs a loop
where the when
condition checks if the item value is greater than five and returns the result.
---
- name: Ansible tasks to work on Ansible When
# Defining the remote server where Ansible will run
hosts: web
remote_user: ubuntu # Using Remote host as ubuntu
become: true
tasks:
# (Task -1) Checking if item value is greater than 5
- name: Run with items greater than 5
ansible.builtin.command: echo {{ item }}
loop: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5*
Now run the command below to execute the playbook as you did previously.
ansible-playbook my_playbook.yml
Below, you can see the task returned skipping status for when the condition is false and changed status for when the condition is true.
Working with Ansible when
and Ansible facts
Perhaps you want to add multiple conditions to execute a task. If so, learn how to utilize Ansible facts within when
condition. Ansible facts allow you to add a conditional statement to execute tasks based on collected facts, such as your OS, IP addresses, attached file systems, and more.
Replace the content of the my_playbook.yml file with the below code.
In the code below, both tasks (Task-1
and Task-2
) only execute (system shutdown) when either of the conditions below is true:
- Both the
distribution
anddistribtion_major_version
returned a true value. - The
os_family
value is equal toCentOS
.
---
- name: Ansible When Single task example
hosts: web
remote_user: ubuntu
become: true
tasks:
# (Task-1): To shutdown the remote node if distribution is CentOS with a major Version 6
- name: Shut down CentOS 6 systems
ansible.builtin.command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"
# (Task-2): To shutdown the remote node if os_family is CentOS.
- name: Shut down CentOS flavored systems
ansible.builtin.command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "CentOS"
Execute the playbook as you previously did with the command below.
ansible-playbook my_playbook.yml
Notice below that both tasks show the skipping status since you’re in Ubuntu. The task only executes if you’re in CentOS.
Working with Ansible when
Based on Registered Values
At times you want to execute or skip a task based on the outcome of an earlier task in a playbook. For instance, you might want to configure a service after a previous task upgrade. In that case, use a registered variable. A registered variable allows you to register the outcome of the earlier task as a variable and use it for the next task as an input.
1. Create an empty directory named /home/ubuntu/hello.
2. Replace my_playbook.yml file’s content with the below code, which performs the following:
The first task (Task-1
) lists the contents (files and sub-directories) of the /etc/hosts
directory in memory and saves that result to the contents1
variable via the register
command.
The second task (Task-2
) lists the contents (currently empty) of the /home/ubuntu/hello directory in memory and saves that list to the contents2
variable.
The third task (Task-3
) checks and prints a “Directory is empty” message if either registered result for the contents1
or contents2
variable is empty.
The
stdout
property of thecontents1
andcontents2
variable is the saved shell output from the result of running the task commands.
---
- name: Ansible When Single task example
hosts: web
remote_user: ubuntu
become: true
tasks:
# (Task-1): To list the directory content in /etc/hosts directory
- name: List contents of directory and Store in content1
ansible.builtin.command: ls /etc/hosts
register: contents1
# (Task-2): To list the directory content in /home/ubuntu/hello
- name: List contents of directory and Store in content2
ansible.builtin.command: ls /home/ubuntu/hello
register: contents2
# (Task-3): Display Directory is empty if any of the directory
# /etc/hosts or /home/ubuntu/hello is empty directory
- name: Check contents for emptiness for content1 or content2
ansible.builtin.debug:
msg: "Directory is empty"
when: contents1.stdout == "" or contents2.stdout == ""
3. Finally, execute the playbook with the ansible-playbook
command below.
ansible-playbook my_playbook.yml
As shown below, since the registered result for the contents2
variable is empty, the third task returns the Directory is empty message.
Working with Ansible when
in Ansible Roles
In this final example, you will learn how Ansible when
works within Ansible roles
. Ansible roles
allow you to re-use standard configurations and make a quicker deployment. Read on to learn how a task invokes Ansible roles
only if the Ansible when
condition is true.
1. Run the commands below to create a directory named ~/ansible_role_when_demo in your home directory and change to that folder as the working directory. The ~/ansible_role_when_demo directory will hold this example’s demo files.
# Create a directory named ~/ansible_role_when_demo in your home directory
mkdir ~/ansible_role_when_demo
# Change to the ~/ansible_role_when_demo directory
cd ~/ansible_role_when_demo
2. Next, run the commands below to create a ~/ansible_role_when_demo/roles and ~/ansible_role_when_demo/roles/java/tasks directory.
Below is what each directory will contain:
- The ~/ansible_role_when_demo/roles directory will contain the role that you need to deploy.
By default, Ansible looks for roles in two locations in a directory called roles/ within the directory where playbook resides or in the /etc/ansible/roles. If you wish to store roles at different paths, declare the paths using the
- role:
parameter in the playbook.
- The ~/ansible_role_when_demo/roles/java/tasks folder will contain a main.yml file you’ll need to deploy a role.
# Create a directory named roles inside the ~/ansible_role_when_demo directory
mkdir -p roles
# Change working directory to ~/ansible_role_when_demo/roles directory
cd roles
# Create the parent (-p) directory named java and a subdirectory named tasks
mkdir -p java/tasks
Now, create a file named main.yml in the ~/ansible_role_when_demo/roles/java/tasks directory, then copy and paste the playbook code below to the main.yml file.
The playbook below installs Java on the remote node it’s run on with the apt module.
---
# Installing the Java (Open Jdk)
- name: Install Java 1.8
apt: name=openjdk-8-jdk
4. Create another YAML file with a name you prefer, and copy/paste the below code. For this example, the file is named ~/ansible_role_when_demo/java-setup.yml.
The code below deploys the Ansible role
(java
) to the remote user (ubuntu
) that has admin access only when the remote user is on Debian OS.
- name: Java Installation playbook
# Defining the remote server where the package will be deployed
hosts: myserver
remote_user: ubuntu # Using Remote user as ubuntu
become: true
tasks:
roles:
- role: java
# Execute the task only if the remote_user is on a Debian OS.
when: ansible_facts['os_family'] == 'Debian'
5. Run the tree
command to verify all required folders and files exist in the ~/ansible_role_when_demo directory.
6. Finally, execute the playbook with the ansible-playbook
command below. ansible-playbook java-setup.yml
ansible-playbook java-setup.yml
Below, the task returned a changed status, indicating Java has been installed successfully as the remote node is on a Debian OS. Running the Ansible playbook using Ansible when
with Ansible roles
Conclusion
In this tutorial, you learned different ways of using Ansible when
and other conditionals. You’ve also learned how to apply Ansible when
conditions, from basic tasks leveraging Ansible facts
and deploying Ansible roles
.
Now how would you build upon this newfound knowledge? Perhaps save time configuring multiple servers with Ansible templates while applying Ansible when
conditions?