Ansible OEL 8 DevOps · OEL 8 · Fundamentals

AnsibleConditionals — the when keyword

How to make tasks conditional on facts, variables, prior task results, or any expression you can write in Jinja2 — with the operator cheat sheet and the gotchas that catch every beginner.

when attaches a Jinja2 expression to a task. If the expression evaluates true, the task runs; if false, the task is reported as skipped and the playbook continues.

- name: Configure database when: ansible_distribution == "OracleLinux" true RUN the task module executes on host false SKIP the task reported as "skipped" when: is evaluated PER HOST — same task may run on some, skip on others
YAML — when patterns
- hosts: all
  tasks:
    # 1. Match a fact
    - name: Install firewalld (RHEL family only)
      ansible.builtin.dnf:
        name: firewalld
        state: present
      when: ansible_os_family == "RedHat"

    # 2. Check a variable was passed
    - name: Apply custom config
      ansible.builtin.template:
        src: app.conf.j2
        dest: /etc/app.conf
      when: app_custom_config is defined

    # 3. Branch on a list inclusion
    - name: Restart web tier services
      ansible.builtin.systemd:
        name: nginx
        state: restarted
      when: "'webservers' in group_names"
OperatorMeaningExample
== !=equalitywhen: x == "primary"
> >= < <=numeric comparisonwhen: ansible_memtotal_mb >= 4096
and or notboolean logicwhen: a and not b
in / not inlist / string membershipwhen: "deploy" in admin_users
is definedvariable existswhen: tls_cert is defined
is not definedvariable doesn't existwhen: backup_path is not defined
is nonevariable is nullwhen: result.stdout is none
is match("re")regex matchwhen: ver is match("^8\\.")

You can chain tasks: register the result of one, then run the next only if the first succeeded, failed, changed, or produced a particular output.

YAML — register + when
- name: Check if MySQL is already initialised
  ansible.builtin.stat:
    path: /var/lib/mysql/ibdata1
  register: ibdata_stat

- name: Initialise data dir
  ansible.builtin.command: mysqld --initialize-insecure
  when: not ibdata_stat.stat.exists

- name: Check current version
  ansible.builtin.command: mysql --version
  register: version_check
  changed_when: false   # this is a read-only check

- name: Upgrade if version is too old
  ansible.builtin.dnf:
    name: mysql-server
    state: latest
  when: "'8.0' not in version_check.stdout"

For complex conditions, use a YAML list — every entry is implicitly AND-ed:

YAML — list-form when (implicit AND)
- name: Configure GR primary
  ansible.builtin.command: |
    mysql -e "SET GLOBAL group_replication_bootstrap_group=ON;"
  when:
    - mysql_role == "primary"
    - inventory_hostname == groups['mysql_primary'][0]
    - bootstrap_cluster | bool

For OR semantics, use a single line with explicit or:

YAML — explicit OR
- name: Send alert
  ansible.builtin.uri:
    url: https://hooks.slack.com/services/...
    method: POST
  when: deploy_failed or rollback_required

when evaluates per loop iteration. The item variable is in scope, so you can filter what the loop processes:

YAML — when inside a loop
- name: Open ports for services we use
  ansible.posix.firewalld:
    port: "{{{{ item.port }}}}/tcp"
    state: enabled
    permanent: true
  loop:
    - {{ name: ssh, port: 22, enabled: true }}
    - {{ name: http, port: 80, enabled: false }}
    - {{ name: https, port: 443, enabled: true }}
    - {{ name: mysql, port: 3306, enabled: true }}
  when: item.enabled
MistakeFix
Wrapping when in {{ }}Don't — when is already evaluated as Jinja2: when: x == 1 not when: "{{ x == 1 }}"
Forgetting to quote a string with a colonwhen: "':' in value" — inner colon needs quoting around the whole expression
Comparing a string to a bool"true" == True is False — use my_bool | bool first
Using = instead of ==Easy typo — = is assignment, == is comparison