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 != 0Conditionals 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 > 0The 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 < 2048The 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.
