Как работает ansible when: механика и синтаксис
Ключевое, что надо понять сразу: значение when - это выражение Jinja2, но БЕЗ фигурных скобок. Внутри when ты пишешь голое выражение, как будто оно уже внутри {{ }}. Поэтому переменные тут указываются по имени, без скобок и в большинстве случаев без кавычек.
Код: Выделить всё
- name: Поставить httpd только на RHEL-семействе
ansible.builtin.package:
name: httpd
state: present
when: ansible_facts['os_family'] == "RedHat"
Доступные операторы - обычные питоновские: == != > < >= <=, логические and / or / not, проверка вхождения in, а также Jinja-тесты через is: is defined, is not defined, is none.

Условие ansible на фактах, переменных и результатах register
Источников для условия три, и каждый ты будешь использовать.
1. Факты. Имя дистрибутива, версия, объём памяти, список интерфейсов - всё это факты. Современный канонический доступ - через словарь ansible_facts:
Код: Выделить всё
- name: Открыть порт 80 только если дистрибутив именно RHEL 9
ansible.posix.firewalld:
service: http
permanent: true
immediate: true
state: enabled
when:
- ansible_facts['distribution'] == "RedHat"
- ansible_facts['distribution_major_version'] == "9"
2. Обычные переменные. Их удобно проверять на сравнение или на само наличие:
Код: Выделить всё
- name: Включить debug-режим, если он явно задан в true
ansible.builtin.debug:
msg: "Режим отладки активен"
when: enable_debug | default(false) | bool
Код: Выделить всё
- name: Проверить, есть ли файл-флаг
ansible.builtin.stat:
path: /etc/app/installed.flag
register: flag
- name: Развернуть приложение, если флага ещё нет
ansible.builtin.command: /opt/app/install.sh
when: not flag.stat.exists
Код: Выделить всё
- name: Узнать версию ядра
ansible.builtin.command: uname -r
register: kern
changed_when: false
- name: Предупредить про старое ядро
ansible.builtin.debug:
msg: "Внимание: ядро серии 4.x"
when: '"4." in kern.stdout'
Несколько условий комбинируются логическими операторами прямо в строке:
Код: Выделить всё
when: ansible_facts['os_family'] == "RedHat" and ansible_facts['distribution_major_version'] == "9"
Код: Выделить всё
when:
- ansible_facts['os_family'] == "RedHat"
- ansible_facts['distribution_major_version'] | int >= 9
- install_web | default(true) | bool
Проверка наличия переменной - отдельная важная тема, на ней часто срезаются:
Код: Выделить всё
when: ssl_cert is defined
when: backup_path is not defined
when: my_list is defined and my_list | length > 0
Оператор in удобен для проверки членства - и в списке, и в строке:
Код: Выделить всё
when: ansible_facts['distribution'] in ["RedHat", "CentOS", "Rocky", "AlmaLinux"]
Когда when стоит рядом с loop, условие проверяется для каждого элемента отдельно. Внутри условия доступна переменная item:
Код: Выделить всё
- name: Поставить только тяжёлые пакеты
ansible.builtin.package:
name: "{{ item.name }}"
state: present
loop:
- { name: nginx, heavy: true }
- { name: vim, heavy: false }
- { name: postgresql, heavy: true }
when: item.heavy
Код: Выделить всё
- name: Настройка веб-стека (только RHEL-семейство)
block:
- name: Установить веб-сервер
ansible.builtin.package:
name: httpd
state: present
- name: Запустить и включить сервис
ansible.builtin.service:
name: httpd
state: started
enabled: true
when: ansible_facts['os_family'] == "RedHat"
Типичные грабли
- Кавычки вокруг переменной в when. Самая частая ошибка новичков. Писать when: "ansible_facts['os_family'] == 'RedHat'" целиком в кавычках НЕ надо - переменную внутри when кавычить нельзя, иначе она станет просто строкой и условие всегда будет истинным. Кавычки нужны только для строковых ЛИТЕРАЛОВ ("RedHat") и для всего выражения целиком только тогда, когда YAML спотыкается о двоеточие или начальную кавычку.
- Фигурные скобки. when: "{{ my_var }}" работать как ожидаешь не будет и кинет варнинг. Внутри when скобки не нужны - пиши when: my_var.
- Сравнение версии с числом. ansible_facts['distribution_major_version'] - строка. Сравнивай со строкой "9" или прогоняй через | int перед числовым сравнением.
- undefined без is defined. Сравнение неопределённой переменной валит плей. Сначала is defined.
- Булевы строки. "true" из vars - это строка, а не булево. Прогоняй через | bool, чтобы when сработал корректно.
Мини-лаба
Собери один плейбук на смешанном инвентаре (хотя бы одна RHEL/Fedora-нода) и повтори руками:
- задача с when: ansible_facts['os_family'] == "RedHat" ставит httpd, а параллельный block под Debian ставит apache2;
- через register сохрани вывод командой и сделай вторую задачу зависимой от not ...stat.exists или от текста в stdout;
- проверь is defined: запусти плейбук с -e "ssl=on" и без, посмотри как меняется skipped;
- поставь when на loop и убедись, что часть item пропускается;
- заверни две задачи в block с одним when и глянь в выводе, что условие применилось к обеим.
Контрольные вопросы
- Нужны ли фигурные скобки {{ }} и кавычки вокруг переменной внутри when? Почему?
- Чем отличается when списком от when с and в одну строку, и можно ли так выразить OR?
- Как безопасно проверить переменную, которая может быть не определена, и почему важен порядок условий?
- Как ведёт себя when, если он стоит рядом с loop?
when - это if на уровне задачи: голое Jinja-выражение без скобок, с переменными без кавычек. Условия строятся на фактах (ansible_facts['os_family']), обычных переменных и результатах register. Операторы обычные питоновские плюс and/or/not, in и тесты is defined. Список условий = неявный AND и читается лучше. Один when на block прикрывает сразу группу задач, а рядом с loop условие проверяется для каждого item. Запомни три грабли - кавычки, фигурные скобки и забытый is defined - и на экзамене эта тема перестанет тебя цеплять.