Аннотация.
Условия в Ansible: when, changed_when, failed_when без боли — это способ сделать плейбуки умнее, чище и предсказуемее. В этой статье на живых примерах разберём, как работать с условиями when, переопределять статус изменений через changed_when и мягко обрабатывать ошибки с помощью failed_when, чтобы Ansible не «орал» changed и failed там, где всё в порядке. Пишем простыми словами, без магии: вы поймёте, когда и как применять условия в Ansible в своих реальных плейбуках.
Зачем вообще условия в Ansible
В реальной жизни у нас редко «идеальный» одинаковый зоопарк серверов.
Чаще так:
- часть хостов — Ubuntu, часть — CentOS;
- где-то стоит Nginx, где-то нет;
- есть тестовые окружения и есть прод.
Если всем хостам без разбора давать одинаковые задачи, начинаются проблемы:
- установка пакета, которого нет в репозитории;
- перезапуск сервиса, которого на этом сервере нет;
- лишние «changed» там, где ничего не поменялось.
Условия в Ansible — это просто фильтр «делать/не делать задачу».
Самый популярный вариант — директива when.
when: включаем и выключаем задачи
when — это «если».
Ansible перед запуском задачи проверяет выражение в when.
- если условие даёт true (истина) — задача выполняется;
- если false — задача пропускается и помечается как skipped.
Синтаксис очень простой:
when с переменными
Переменные — это значения, которые вы задаёте сами: в group_vars, host_vars, плейбуке или ролях.
Например, вы хотите, чтобы какая-то задача выполнялась только в прод-окружении:
Задача:
Здесь логика прозрачная:
- на проде env_type == "prod" → условие истинно → задача выполняется;
- на деве env_type == "dev" → условие ложно → задача пропускается.
Важно.
В when лучше писать условия так, чтобы их было легко прочитать через месяц.
env_type == "prod" понятнее, чем env_type != "dev".
when с фактами (ansible_facts)
Факты — это информация, которую Ansible сам собирает о хосте:
тип системы, версия, IP-адреса, процессор и т.д.
Примеры фактов:
- ansible_os_family — семейство ОС (Debian, RedHat и т.п.);
- ansible_distribution — конкретный дистрибутив (Ubuntu, CentOS);
- ansible_facts['hostname'] — имя хоста, и многое другое.
Частая задача: разные команды для разных семейств ОС.
То же самое через «полное» имя факта:
Смысл одинаковый. Короткий вариант (ansible_os_family) проще читать, поэтому им обычно и пользуются.
Типичная ошибка.
Забыть gather_facts: yes в плейбуке.
Без этого Ansible не соберёт факты, и ansible_os_family будет просто пустым значением.
changed_when: когда таска всегда пишет changed и это бесит
Некоторые модули Ansible не понимают, меняли ли они что-то на самом деле.
Например, command и shell по умолчанию всегда считают, что что-то «изменили», даже если команда была просто проверкой.
В результате:
- вы запускаете плейбук «просто посмотреть»;
- половина задач зелёные с пометкой changed;
- непонятно, где были реальные изменения.
changed_when позволяет переопределить, считать ли задачу изменившей что-то.
Простой пример: задача точно ничего не меняет
Эта задача только читает статус сервиса, значит:
- мы явно говорим changed_when: false;
- в отчёте она будет зелёной без «changed».
Чуть сложнее: changed только при реальном обновлении
Представим скрипт, который обновляет приложение и пишет в вывод:
- already up-to-date — если ничего не обновлялось;
- что-то ещё — если была установка/обновление.
Логика:
- если в выводе НЕТ текста already up-to-date → считаем, что были изменения → changed = true;
- если есть эта строка → изменений не было → changed = false.
Так отчёт по плейбуку становится честнее: видно, где действительно что-то поменялось.
failed_when: как мягко ловить ошибки
По умолчанию Ansible считает:
- успех — код возврата (rc) команды равен 0;
- ошибка — любой другой код.
Но в жизни не всегда так просто.
Классика:
grep "ERROR" /var/log/app.log
- rc = 0 — строка найдена;
- rc = 1 — строку не нашли (это не ошибка программы, просто «ничего не нашлось»);
- rc > 1 — уже какая-то настоящая проблема.
Если такую команду просто запустить через command, rc = 1 будет считаться падением задачи.
failed_when позволяет настроить, при каких условиях задача считается «упавшей».
Что происходит:
- rc = 0 → ошибки найдены → задача успешна (возможно, дальше вы что-то с этим делаете);
- rc = 1 → ничего не нашли → тоже считаем успешно, просто нет строк;
- rc > 1 → уже проблема с самой командой/файлом → падаем.
«Не падать вообще»
Бывает, нужна диагностическая команда, которая никогда не должна рушить плейбук:
Таска выполнится, результат сохранится, но даже при ошибке плейбук продолжит работу.
Типичная ошибка.
Ставить ignore_errors: yes везде, где страшно.
Так легко спрятать настоящую проблему.
Гораздо лучше явно описать условие в failed_when.
Почему это работает
Ansible для каждой задачи делает одно и то же:
- Собирает переменные и факты.
- Проверяет условие when — «нужно ли вообще запускать эту задачу».
- Запускает модуль (если условие прошло).
- Получает результат: код возврата, вывод, признак изменения.
- Сверху применяет ваши правила:
changed_when может переписать статус «менял/не менял»;
failed_when может переписать статус «упал/не упал».
То есть when, changed_when и failed_when — это просто тонкие настройки поведения задач, а не «магия».
Вы чётко говорите Ansible, чего вы от него ждёте, и в ответ получаете более честный и читаемый отчёт.
Что сделали
- Разобрались, зачем нужны условия в плейбуках и почему без них быстро наступает хаос.
- Посмотрели, как использовать when:
с собственными переменными (env_type == "prod");
с фактами ansible_facts (ansible_os_family == "Debian"). - Научились приручать ложные изменения с помощью changed_when.
- Посмотрели, как мягко обрабатывать ошибки через failed_when, вместо тотального ignore_errors.
Сделать прямо сейчас
- Откройте любой свой плейбук и найдите задачу, которая:
должна выполняться только на части хостов,
— добавьте к ней понятный when. - Найдите задачу с command или shell, которая всегда показывает changed,
— добавьте changed_when: false или разумное условие по выводу. - Там, где вы сейчас используете ignore_errors: yes, подумайте:
— можно ли заменить это на аккуратное failed_when с понятной логикой по rc? - Добавьте в плейбук комментарии «по-человечески», чтобы коллега понял, зачем здесь это условие.
CTA
Если вам зашла такая подача Ansible,
подпишитесь на канал» — дальше разберём циклы, handlers и jinja.
Есть вопросы по when, changed_when или failed_when?
Напишите в комментариях свой пример задачи — разберём и превратим в аккуратный, понятный плейбук.