How Does When Condition Work in Ansible

September 16th, 2024
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_filevariable 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.

Winnie is a seasoned Linux Systems administrator, currently specializing in writing technical Linux tutorials. With over seven years of experience in deploying and working with major Linux distributions such as Ubuntu, Debian, RHEL, OpenSUSE, and ArchLinux, she has written detailed and well-written "How to" Linux guides and tutorials. Winnie holds a Bachelor's Degree in Computer Science from Masinde Muliro University, Kenya and resides in Nairobi, Kenya. She is an expert in authoring Linux and DevOps topics involving Docker, Ansible, and Kubernetes. She currently works as a freelance technical writer and consultant. In her previous roles, she worked in the capacity of an IT support specialist and Linux administrator. Her key roles included offering level 1 and 2 support to both in-house and remote staff and managing and monitoring Linux servers.

Start Building Now

Deploy your new Cloud VPS server in 3 minutes starting from $5.83 / month.

We use cookies to ensure seamless user experience for our website. Required cookies - technical, functional and analytical - are set automatically. Please accept the use of targeted cookies to ensure the best marketing experience for your user journey. You may revoke your consent at any time through our Cookie Policy.
build: 5bc831c3.737