Ansible Conditionals
Overview
Conditionals in Ansible allow you to execute tasks based on specific conditions, making your playbooks more dynamic and adaptable.
Basic Conditionals
When Statement
# Simple condition
- name: Install Apache on Debian-based systems
ansible.builtin.apt:
name: apache2
state: present
when: ansible_facts['os_family'] == "Debian"
# Multiple conditions
- name: Configure production settings
ansible.builtin.template:
src: prod-settings.j2
dest: /etc/app/settings.conf
when:
- environment == "production"
- ansible_facts['memory_mb']['real']['total'] >= 4096
Boolean Operations
# AND condition
- name: Execute with multiple conditions
debug:
msg: "All conditions met"
when:
- condition1 | bool
- condition2 | bool
- condition3 | bool
# OR condition
- name: Execute with any condition
debug:
msg: "One condition met"
when: condition1 | bool or condition2 | bool
# NOT condition
- name: Skip when condition is true
debug:
msg: "Condition not met"
when: not condition1
Advanced Conditionals
Conditional Imports
# Conditional include
- name: Include OS-specific tasks
ansible.builtin.include_tasks:
file: "{{ ansible_facts['os_family'] | lower }}.yml"
when: ansible_facts['os_family'] in ['Debian', 'RedHat']
# Conditional roles
- name: Include role based on environment
ansible.builtin.include_role:
name: "{{ item }}"
loop:
- common
- "{{ environment }}_specific"
when: environment in ['dev', 'prod']
Variable Existence
# Check if variable exists
- name: Configure when variable exists
debug:
msg: "Variable exists and equals {{ myvar }}"
when: myvar is defined
# Check variable type
- name: Process list variable
debug:
msg: "Processing list items"
when: myvar is sequence
File and Path Conditions
# Check file status
- name: Check file conditions
debug:
msg: "File exists and is not empty"
when:
- path_to_file is exists
- path_to_file is file
- path_to_file is not directory
- path_to_file.stat.size > 0
vars:
path_to_file: "/path/to/file"
Complex Conditionals
Nested Conditions
# Multiple level conditions
- name: Complex conditional execution
debug:
msg: "All conditions met"
when:
- environment == "production"
- ansible_facts['os_family'] == "Debian"
- ansible_facts['distribution_version'] is version('18.04', '>=')
- ansible_facts['memory_mb']['real']['total'] >= 4096
Register and Conditions
# Use registered variables
- name: Check process status
ansible.builtin.command: systemctl status nginx
register: nginx_status
ignore_errors: yes
- name: Restart if not running
ansible.builtin.service:
name: nginx
state: restarted
when: nginx_status.rc != 0
Custom Conditions
# Define custom conditions
- name: Set custom facts
ansible.builtin.set_fact:
is_valid_env: "{{ environment in ['dev', 'staging', 'prod'] }}"
has_enough_memory: "{{ ansible_facts['memory_mb']['real']['total'] >= min_memory }}"
is_supported_os: "{{ ansible_facts['os_family'] in supported_os }}"
- name: Execute with custom conditions
debug:
msg: "System meets all requirements"
when:
- is_valid_env
- has_enough_memory
### Pattern Matching
```yaml
# String pattern matching
- name: Match hostname pattern
debug:
msg: "Webserver detected"
when: inventory_hostname is match("web-*")
# Regular expressions
- name: Match using regex
debug:
msg: "Development server detected"
when: inventory_hostname is regex("^dev-\d+")
Version Comparisons
# Compare versions
- name: Check minimum version
debug:
msg: "Version meets requirement"
when: app_version is version('2.0.0', '>=')
# Version ranges
- name: Check version compatibility
debug:
msg: "Version in supported range"
when:
- app_version is version('1.5.0', '>=')
- app_version is version('3.0.0', '<')
Error Handling with Conditionals
Failed Status Handling
# Check task failure
- name: Attempt primary action
ansible.builtin.command: /usr/local/bin/primary-action
register: primary_result
ignore_errors: yes
- name: Attempt fallback action
ansible.builtin.command: /usr/local/bin/fallback-action
when: primary_result is failed
# Multiple failure checks
- name: Complex error handling
block:
- name: Primary database connection
ansible.builtin.command: check_db_connection.sh primary
register: primary_db
- name: Failover database connection
ansible.builtin.command: check_db_connection.sh failover
register: failover_db
when: primary_db is failed
- name: Emergency backup connection
ansible.builtin.command: check_db_connection.sh backup
when:
- primary_db is failed
- failover_db is failed
rescue:
- name: Notify on complete failure
ansible.builtin.mail:
to: [email protected]
subject: "Database connection failure"
body: "All database connections failed"
when: primary_db is failed and failover_db is failed
Conditional Tasks Based on Environment
Environment-Specific Configuration
# Multi-environment handling
- name: Configure environment settings
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/app/config.yml"
with_first_found:
- files:
- "config-{{ environment }}.yml.j2"
- "config-default.yml.j2"
paths:
- templates/configs
when: environment is defined
# Resource allocation by environment
- name: Set resource limits
ansible.builtin.template:
src: limits.conf.j2
dest: /etc/security/limits.conf
vars:
max_memory: "{{ '512MB' if environment == 'dev' else '2GB' if environment == 'staging' else '8GB' }}"
when: environment in ['dev', 'staging', 'prod']
Conditional Role Execution
Role-Based Logic
# Conditional role inclusion
- name: Include monitoring role
ansible.builtin.include_role:
name: monitoring
when:
- enable_monitoring | bool
- monitoring_type in ['basic', 'advanced']
# Dynamic role parameters
- name: Configure backup role
ansible.builtin.include_role:
name: backup
tasks_from: "{{ backup_type }}"
vars:
backup_params:
retention: "{{ '7d' if environment == 'dev' else '30d' }}"
compression: "{{ 'low' if environment == 'dev' else 'high' }}"
when: enable_backups | default(true) | bool
Best Practices
Readable Conditions
# Use descriptive variables
- name: Set condition variables
ansible.builtin.set_fact:
is_production: "{{ environment == 'production' }}"
is_high_capacity: "{{ ansible_facts['memory_mb']['real']['total'] >= 16384 }}"
is_backup_day: "{{ ansible_date_time.weekday in ['Saturday', 'Sunday'] }}"
- name: Execute weekend backup
ansible.builtin.include_role:
name: backup
tasks_from: full
when:
- is_production
- is_high_capacity
- is_backup_day
Conditional Documentation
# Document complex conditions
- name: Document conditional logic
ansible.builtin.set_fact:
deployment_conditions: |
Deployment requires:
1. Production environment
2. Minimum 16GB RAM
3. Supported OS version
4. All health checks passing
- name: Deploy application
ansible.builtin.include_role:
name: app_deploy
vars:
conditions_met: "{{
environment == 'production' and
ansible_facts['memory_mb']['real']['total'] >= 16384 and
ansible_distribution_version is version('20.04', '>=') and
health_checks.status == 'passing'
}}"
when: conditions_met
Testing Conditions
# Debug conditional logic
- name: Debug condition evaluation
ansible.builtin.debug:
msg: |
Condition evaluation:
- Environment: {{ environment }}
- Memory: {{ ansible_facts['memory_mb']['real']['total'] }}
- OS Version: {{ ansible_distribution_version }}
- Health Status: {{ health_checks.status }}
when: debug_mode | default(false) | bool
Performance Optimization
# Optimize condition checking
- name: Cache frequent condition results
ansible.builtin.set_fact:
cache_time: 3600 # Cache for 1 hour
system_conditions: "{{
{
'meets_memory': ansible_facts['memory_mb']['real']['total'] >= min_memory,
'meets_version': ansible_distribution_version is version(min_version, '>='),
'meets_disk': ansible_facts['mounts'][0]['size_available'] >= min_disk_space
}
}}"
when: system_conditions is not defined
- name: Use cached conditions
debug:
msg: "System meets requirements"
when:
- system_conditions.meets_memory
- system_conditions.meets_version
- system_conditions.meets_disk