Ansible Conditionals

Real infrastructure is not homogeneous. Your inventory might contain Ubuntu and CentOS servers, servers with different amounts of RAM, or servers in different geographic regions that require different configurations. Conditionals let a single playbook handle all of these scenarios by skipping or running tasks based on runtime conditions.

The when Keyword

The when keyword attaches a condition to a task. The task runs only if the condition evaluates to true:

- name: Install Apache on Debian/Ubuntu systems
  apt:
    name: apache2
    state: present
  when: ansible_os_family == "Debian"

- name: Install Apache on RedHat systems
  yum:
    name: httpd
    state: present
  when: ansible_os_family == "RedHat"

The ansible_os_family fact is gathered automatically and contains values like "Debian", "RedHat", "Suse", or "Windows". This pattern — using gathered facts to select the correct module — is the most common use of conditionals in Ansible.

Condition Syntax

Conditions use Jinja2 expression syntax (without the double curly braces — Ansible adds those internally):

# Comparison operators
when: ansible_memtotal_mb >= 2048     # Greater than or equal
when: nginx_port != 80                # Not equal
when: app_version == "2.0"            # Equal

# Boolean checks
when: ssl_enabled                     # True if ssl_enabled is truthy
when: not ssl_enabled                 # True if ssl_enabled is falsy

# String operations
when: "'web' in inventory_hostname"   # True if hostname contains "web"
when: ansible_distribution in ['Ubuntu', 'Debian']

# Variable existence check
when: my_variable is defined
when: my_variable is not defined
when: my_variable is none

Multiple Conditions

# AND - task runs if BOTH conditions are true
when:
  - ansible_os_family == "Debian"
  - ansible_memtotal_mb >= 1024

# OR - task runs if EITHER condition is true (requires parentheses in Jinja2)
when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"

# Combined with and/or
when: (ansible_os_family == "Debian" and ansible_memtotal_mb >= 2048) or
      ansible_os_family == "RedHat"

Conditionals with Registered Variables

- name: Check if config file exists
  stat:
    path: /etc/myapp/config.yml
  register: config_file

- name: Deploy default config if none exists
  copy:
    src: files/default-config.yml
    dest: /etc/myapp/config.yml
  when: not config_file.stat.exists

- name: Check service status
  command: systemctl is-active nginx
  register: nginx_status
  ignore_errors: true

- name: Restart nginx if it was stopped
  service:
    name: nginx
    state: restarted
  when: nginx_status.rc != 0

Conditionals with Facts

System facts provide rich conditional possibilities:

- name: Apply memory-intensive config only on servers with enough RAM
  template:
    src: high-mem-nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  when: ansible_memtotal_mb >= 8192

- name: Install GPU driver only on GPU-equipped servers
  apt:
    name: nvidia-driver-535
    state: present
  when: "'nvidia' in ansible_devices"

- name: Configure IPv6 only where available
  template:
    src: nginx-ipv6.conf.j2
    dest: /etc/nginx/conf.d/ipv6.conf
  when: ansible_all_ipv6_addresses | length > 0

The fail Module for Explicit Precondition Checks

- name: Verify minimum requirements before proceeding
  fail:
    msg: "This playbook requires at least 2GB RAM. This host has {{ ansible_memtotal_mb }}MB."
  when: ansible_memtotal_mb < 2048

The fail module with a when condition is an elegant way to enforce preconditions. The playbook stops immediately on any host that does not meet the requirement, with a clear error message explaining why.

Try This: Multi-OS Package Installation

Write a playbook that installs a web server on all hosts in your inventory, using apt for Debian/Ubuntu and yum for RedHat/CentOS. Add a task that fails with a descriptive message if the OS family is neither Debian nor RedHat. Test by running against your lab VMs and verify the correct package manager task runs for each host.

Summary

The when keyword evaluates a Jinja2 condition and skips the task if false. Common condition sources include gathered facts (OS family, memory, distribution), registered variable results (return codes, file existence), and custom variables. Multiple conditions combine with a YAML list (implicit AND) or explicit or operators. The fail module enforces preconditions explicitly. Conditionals are the feature that makes one playbook serve many environments correctly.

Leave a Comment