How to Use when for Conditional Task Execution in Ansible

Ansible When Conditionals

Ever wanted to run an Ansible task only if a condition is met? Whether it’s checking the operating system, available memory, a custom variable, or the result of a previous task, the when statement lets you control when tasks run.

The when statement is used to conditionally run tasks in Ansible based on facts, variables, or registered output. If the condition evaluates to true, the task runs—otherwise, it’s skipped.

In this guide, we’ll explore how to use the when conditional in Ansible to control task execution based on specific conditions.

Basic Syntax

The basic syntax of the when conditional in Ansible is simple. You use the when keyword followed by a condition that evaluates to true or false. Here’s a simple example:

- name: Install Apache on Debian
  apt:
    name: apache2
    state: present
  when: ansible_os_family == 'Debian'

In this example, the Apache package will only be installed if the target system belongs to the Debian family.

Use when with Variables (Roles, Environments)

Assume you want to configure Nginx on servers that are in the production environment and have a specific role. We’ll use inventory variables and check multiple conditions.

In this example playbook, Nginx is installed, configured, and restarted only on servers in the production environment with the role web.

- hosts: web_servers
  vars:
    env: production
    role: web
  tasks:
    - name: Ensure Nginx is installed
      apt:
        name: nginx
        state: present
      when: env == 'production' and role == 'web'

    - name: Configure Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      when: env == 'production' and role == 'web'

    - name: Restart Nginx
      service:
        name: nginx
        state: restarted
      when: env == 'production' and role == 'web'

Use when with AND Operator

Sometimes, you need to check multiple conditions. You can use the and operator to combine them.

In this playbook, the web server will only restart if both service_running and config_changed are true.

- name: Restart web server if the service is running and the configuration has changed
  service:
    name: apache2
    state: restarted
  when: service_running and config_changed

Use not Operator to Run When a Condition Is False

In a situation where you need to perform maintenance tasks only if a service is not running, you can use the NOT operator.

This playbook runs maintenance tasks only if PostgreSQL is not currently active.

- hosts: db_servers
  tasks:
    - name: Check if PostgreSQL is running
      shell: systemctl is-active postgresql
      register: postgresql_status
      failed_when: false

    - name: Perform maintenance if PostgreSQL is not running
      shell: ./maintenance_tasks.sh
      when: postgresql_status.stdout != 'active'

Use not equal to Compare Values

Let’s consider a scenario where you want to start a service only if the current timezone is not set to UTC. This can be useful in cases where certain services or configurations are specific to non-UTC timezones.

In this playbook, the when condition checks if the current timezone is not equal to ‘UTC’. If the condition is true (i.e., the timezone is not UTC), the task will execute.

- name: Start the ntpd service if timezone is not UTC
  ansible.builtin.systemd:
    name: ntpd
    state: started
  when: ansible_date_time.tz != 'UTC'

Use when with Registered Variables

Using the register keyword, you can capture the output of a task and use it as a condition for subsequent tasks. This is useful for making decisions based on dynamic data during playbook execution.

In this playbook, disk cleanup will only be performed if the disk usage exceeds 80%.

- hosts: all
  tasks:
    - name: Check disk space
      shell: df -h / | tail -1 | awk '{print $5}' | sed 's/%//'
      register: disk_usage

    - name: Print disk usage
      debug:
        msg: "Disk usage is {{ disk_usage.stdout }}%"

    - name: Clean up disk if usage is above 80%
      shell: ./cleanup_disk.sh
      when: disk_usage.stdout | int > 80

This example checks disk space using the shell module and prints the usage with the debug module.

Use when with Facts

Ansible gathers facts about the system it manages and stores them in variables. You can use these facts to make decisions in your playbooks. Let’s consider an example where you want to install packages only if the target system has a certain amount of memory.

In this playbook, high-memory-package will be installed on systems with more than 4GB of RAM, while low-memory-package will be installed on systems with 4GB or less.

- hosts: all
  tasks:
    - name: Gather facts
      setup:

    - name: Ensure high-memory package is installed
      apt:
        name: high-memory-package
        state: present
      when: ansible_memtotal_mb > 4096

    - name: Ensure low-memory package is installed
      apt:
        name: low-memory-package
        state: present
      when: ansible_memtotal_mb <= 4096

Use when with Boolean Variable

Let’s say you have a boolean variable enable_firewall that determines whether the firewall should be enabled on a server. You can use the when conditional to apply this setting.

This example uses the systems module to start and enable the firewall service only if the enable_firewall variable is true.

- name: Enable and start the firewall if enable_firewall is true
  ansible.builtin.systemd:
    name: firewalld
    state: started
    enabled: true
  when: enable_firewall

Use when to Install Packages Based on the Operating System

To install packages based on the operating system using Ansible when conditional, you can check the OS family or distribution and then apply the appropriate package management tasks. This approach allows you to tailor package installations to different types of systems, such as RedHat-based or Debian-based distributions.

Here’s a playbook that installs httpd on RedHat-based systems and apache2 on Debian-based systems:

- name: Install web server based on OS
  hosts: all
  become: yes
  tasks:
    - name: Install httpd on RedHat-based systems
      ansible.builtin.yum:
        name: httpd
        state: present
      when: ansible_os_family == 'RedHat'

    - name: Install apache2 on Debian-based systems
      ansible.builtin.apt:
        name: apache2
        state: present
      when: ansible_os_family == 'Debian'

Use when with Multiple Conditions

You can combine multiple conditions using AND and OR. The following playbook installs the httpd package (which is the Apache web server) on all hosts that meet specific conditions. It runs on all target machines with elevated privileges.

This playbook uses the yum module to install the httpd package if the system is running a Red Hat-based distribution like Rocky Linux or CentOS with a major version of 8 or higher.

- name: Install httpd package based on multiple conditions
  hosts: all
  become: yes
  tasks:
    - name: Install httpd on eligible systems
      ansible.builtin.yum:
        name: httpd
        state: present
      when:
        - ansible_os_family == 'RedHat'
        - ansible_distribution in ['Rocky', 'CentOS']
        - (ansible_distribution_major_version | int >= 8) or (ansible_distribution == 'Rocky' and ansible_distribution_major_version | int >= 8)

Conclusion

In this article, we explored the various ways to use the Ansible When Conditional to control task execution based on different conditions. Use these techniques in your projects to execute tasks, making your automation scripts smarter and more reliable conditionally.

Happy automating!

FAQs

1. Can I use multiple conditions in the 'when' statement?

Yes, you can use logical operators like and, or, and not to combine multiple conditions in a single when statement.

2. What happens if the 'when' condition is false?

If the when condition is false, the task is skipped, and Ansible proceeds to the next task in the playbook without failing.

3. How do I debug the 'when' conditional if a task doesn't execute as expected?

You can use the debug module or run the playbook in verbose mode (-vvv) to inspect the value of variables and conditions to troubleshoot issues.

About Hitesh Jethva

Experienced Technical writer, DevOps professional with a demonstrated history of working in the information technology and services industry. Skilled in Game server hosting, AWS, Jenkins, Ansible, Docker, Kubernetes, Web server, Security, Proxy, Iptables, Linux System Administration, Domain Name System (DNS), and Technical Writing.

View all posts by Hitesh Jethva