Using when Function in Ansible
In Ansible, the when statement conditionally executes tasks based on certain conditions. It allows you to control the execution flow in your playbooks based on the values of variables, facts, or the results of previous tasks.
Ansible supports various types of conditions you can use with when
:
- Boolean values: You can directly use true or false for simple conditions.
- Variables: You can use variables defined in your playbook or inventory files to control task execution.
- Facts: You can access facts gathered during Ansible's execution using ansible_facts or specific fact names. For example, when: ansible_os_family == "Debian" checks if the operating system belongs to the Debian family. You can use these facts to conditionally execute tasks.
- Jinja2 Expressions: You can use Jinja2 expressions to evaluate complex conditions based on variable values, mathematical operations, string comparisons, etc.
- Registered Variables: You can use the results of previous tasks (stored in registered variables) to determine whether subsequent tasks should be executed.
In this post, I will explain how to use the Ansible when using practical examples.
Basic syntax of when in Ansible
Here's a basic syntax of how to use when
in Ansible:
- name: Task Name
<module_name>:
<module_options>
when: <condition>
In this syntax:
- name: A descriptive name for the task.
- module_name: The Ansible module you want to execute.
- module_options: Any options or parameters specific to the module.
- condition: The condition under which the task should be executed. It's usually written as an expression evaluating to true or false.
Example 1: Use Ansible when with a loop and conditionals
You can use the Ansible when
statement with a loop
and conditionals
to install the Apache web server based on the package manager detected on the target system. Here is an example playbook that shows you how to install Apache or HTTPd based on the package manager:
---
- name: Install Apache or HTTPd based on package manager
hosts: all
become: true
tasks:
- name: Determine package manager
set_fact:
apache_pkg:
- "{{ 'apache2' if ansible_pkg_mgr == 'apt' else 'httpd' }}"
when: ansible_pkg_mgr == 'apt' or ansible_pkg_mgr == 'dnf' or ansible_pkg_mgr == 'yum'
- name: Install Apache or HTTPd
ansible.builtin.package:
name: "{{ apache_pkg }}"
state: present
ignore_errors: yes
- name: Print error message if no suitable package manager found
debug:
msg: "No suitable package manager found to install Apache or HTTPd."
when: apache_pkg is undefined
This Ansible playbook is designed to install either Apache or HTTPd based on the package manager available on the target system. Let's break down each part of the playbook:
- Determine package manager: This task uses the
set_fact
module to determine the appropriate package name for Apache or HTTPd based on the detected package manager(ansible_pkg_mgr)
. If the package manager isapt
, it setsapache_pkg
toapache2
; otherwise, it sets it tohttpd
. This task is conditional(when)
on the package manager being one ofapt
,dnf
, oryum
. - Install Apache or HTTPd: This task uses the
ansible.builtin.package
module to install the package specified inapache_pkg
. It sets the state to present, indicating that the package should be installed. Theignore_errors: yes
directive is used to continue execution even if the package installation fails. - Print error message if no suitable package manager found: This task prints a debug message if
apache_pkg
is undefined, indicating that no suitable package manager was detected to install Apache or HTTPd.
Now, run the playbook.
ansible-playbook playbook.yml
You will see the following screenshot.
Example 2: Use Ansible when with a loop
Here's an example of using the Ansible when
statement with a loop
to create directories for different users based on specified conditions:
- name: Create directories for specific users
hosts: node1
tasks:
- name: Create directories for multiple users
ansible.builtin.file:
path: "/home/{{ item }}/data"
state: directory
when: item != 'admin' # Create directories for all users except 'admin'
loop:
- user1
- user2
- user3
- admin
In this example, the task creates directories for multiple users but skips the directory creation for the user admin
using when condition with the loop.
Now, run the playbook.
ansible-playbook playbook.yml
You will see the following screenshot.
💡 If you are new to Ansible and want to learn it from the scratch, our Ansible tutorial series will be of great help. It's written for RHCE exam but it helps you the same whether you are preparing for the exam or not.
Example 3: Run a command only if a file exists
In this example, we will create a playbook that prints the content of a remote file if it exists and fetches the file to a local directory before displaying its content.
---
- name: Print content of remote file if it exists
hosts: node3
tasks:
- name: Check if the file exists
ansible.builtin.stat:
path: /etc/file
register: file_stat
- name: Print content of the file if it exists
ansible.builtin.fetch:
src: /etc/file
dest: /tmp/file
flat: yes
when: file_stat.stat.exists
- name: Display content of the file
debug:
msg: "File content: {{ lookup('file', '/tmp/file') }}"
when: file_stat.stat.exists
Let's break down the playbook:
- The playbook targets the
node3
host. - The first task uses the stat module to check if the file
/etc/file
exists on the target node. The result is registered in the variablefile_stat
. - The second task uses the
fetch
module to fetch the file/etc/file
from the remote host to the local directory/tmp/file
. Theflat: yes
option ensures that the file is fetched without any directory structure. This task only runs if the file exists on the target node(when: file_stat.stat.exists)
. - The third task uses the debug module to display the content of the file fetched to the local directory. This task also runs only if the file exists on the target node
(when: file_stat.stat.exists)
.
Use the following command to run the playbook.
ansible-playbook playbook.yml
You will see the following screenshot.
Example 4: Use Ansible when with facts
In this playbook, we will demonstrate the usage of conditional statements when
based on Ansible facts to execute tasks selectively depending on the distribution and major version of the target systems.
---
- name: Ansible When with facts example
hosts: all
become: true
tasks:
- name: Display distribution and major version
debug:
msg: "Distribution: {{ ansible_facts['distribution'] }}, Major Version: {{ ansible_facts['distribution_major_version'] }}"
- name: Shutdown the remote node if distribution is Ubuntu with a major Version 22.04
ansible.builtin.command: /sbin/shutdown -t now
when: ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] == '22'
- name: Shutdown the remote node if distribution is RedHat
ansible.builtin.command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "RedHat"
This playbook prints the distribution and major version of the target systems and then selectively shuts down the remote node based on the detected distribution and OS family.
Let's break down each part of the playbook:
- Display distribution and major version: This task uses the debug module to display the distribution and major version of the target systems. It uses
ansible_facts['distribution']
andansible_facts['distribution_major_version']
to access these facts. - Shutdown the remote node if the distribution is Ubuntu with a major Version 22.04: This task uses the
ansible.builtin.command
module to execute the/sbin/shutdown -t now
command if the distribution is Ubuntu and the major version is 22.04. The when condition checks ifansible_facts['distribution']
is equal toUbuntu
andansible_facts['distribution_major_version']
is equal to22
. - Shutdown the remote node if distribution is RedHat: Similar to the previous task, this task executes the
/sbin/shutdown -t now
command if the target system's OS family isRedHat
. It checks this condition usingansible_facts['os_family']
.
Now, run the above playbook.
ansible-playbook playbook.yml
You will see the following screenshot:
Example 5: Use Ansible when based on registered values
Ansible's when clause allows you to execute tasks conditionally based on the output of previous tasks.
In this playbook, you can use the stat module in Ansible along with the when condition to check if a remote directory is empty. Here's how to use it with registered values to check if a remote directory is empty:
---
- name: Check the empty directory
hosts: node3
tasks:
- name: Get directory stats
stat:
path: /opt
register: dir_info
- name: Find files in a directory
find:
paths: /opt
file_type: file
hidden: true
register: files_found
- name: Fail if directory not empty
fail:
msg: "Directory /opt is not empty."
when: dir_info.stat.exists and files_found.matched > 0
- name: Debug message if directory is empty
debug:
msg: "Directory /opt is empty."
when: dir_info.stat.exists and files_found.matched == 0
In this example:
- The first task uses stat to get information about the directory, including its existence. It stores the result in
dir_info
. - The second task uses find to search for all files (including hidden) within the directory. It stores the number of matches in
files_found.matched
. - The fail task triggers only if the directory exists
(dir_info.stat.exists is True)
and there are files found(files_found.matched is greater than 0)
. This indicates a non-empty directory. - The debug task prints a message if the directory is empty (both existence check and no files found).
Let's run this playbook:
ansible-playbook playbook.yml
You will see the following screenshot:
Conclusion
Throughout this article, we've explored various examples showcasing the versatility of the Ansible when function. From basic conditionals based on system facts such as distribution and version to more complex scenarios involving file existence checks and custom conditionals.
By leveraging Ansible facts, variables, and logical operators within the "when" statement, users can create flexible and dynamic playbooks tailored to specific scenarios and environments.