Найти в Дзене
Infra as Code по-русски

Условия в Ansible: when, changed_when, failed_when без боли

Условия в Ansible: when, changed_when, failed_when без боли — это способ сделать плейбуки умнее, чище и предсказуемее. В этой статье на живых примерах разберём, как работать с условиями when, переопределять статус изменений через changed_when и мягко обрабатывать ошибки с помощью failed_when, чтобы Ansible не «орал» changed и failed там, где всё в порядке. Пишем простыми словами, без магии: вы поймёте, когда и как применять условия в Ansible в своих реальных плейбуках. В реальной жизни у нас редко «идеальный» одинаковый зоопарк серверов.
Чаще так: Если всем хостам без разбора давать одинаковые задачи, начинаются проблемы: Условия в Ansible — это просто фильтр «делать/не делать задачу».
Самый популярный вариант — директива when. when — это «если».
Ansible перед запуском задачи проверяет выражение в when. Синтаксис очень простой: Переменные — это значения, которые вы задаёте сами: в group_vars, host_vars, плейбуке или ролях. Например, вы хотите, чтобы какая-то задача выполнялась тольк
Оглавление

Аннотация.

Условия в 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.

Синтаксис очень простой:

-2

when с переменными

Переменные — это значения, которые вы задаёте сами: в group_vars, host_vars, плейбуке или ролях.

Например, вы хотите, чтобы какая-то задача выполнялась только в прод-окружении:

-3

Задача:

-4

Здесь логика прозрачная:

  • на проде 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'] — имя хоста, и многое другое.

Частая задача: разные команды для разных семейств ОС.

-5

То же самое через «полное» имя факта:

-6

Смысл одинаковый. Короткий вариант (ansible_os_family) проще читать, поэтому им обычно и пользуются.

Типичная ошибка.

Забыть
gather_facts: yes в плейбуке.

Без этого Ansible не соберёт факты, и ansible_os_family будет просто пустым значением.

changed_when: когда таска всегда пишет changed и это бесит

Некоторые модули Ansible не понимают, меняли ли они что-то на самом деле.

Например, command и shell по умолчанию всегда считают, что что-то «изменили», даже если команда была просто проверкой.

В результате:

  • вы запускаете плейбук «просто посмотреть»;
  • половина задач зелёные с пометкой changed;
  • непонятно, где были реальные изменения.

changed_when позволяет переопределить, считать ли задачу изменившей что-то.

Простой пример: задача точно ничего не меняет

-7

Эта задача только читает статус сервиса, значит:

  • мы явно говорим changed_when: false;
  • в отчёте она будет зелёной без «changed».

Чуть сложнее: changed только при реальном обновлении

Представим скрипт, который обновляет приложение и пишет в вывод:

  • already up-to-date — если ничего не обновлялось;
  • что-то ещё — если была установка/обновление.
-8

Логика:

  • если в выводе НЕТ текста 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 позволяет настроить, при каких условиях задача считается «упавшей».

-9

Что происходит:

  • rc = 0 → ошибки найдены → задача успешна (возможно, дальше вы что-то с этим делаете);
  • rc = 1 → ничего не нашли → тоже считаем успешно, просто нет строк;
  • rc > 1 → уже проблема с самой командой/файлом → падаем.

«Не падать вообще»

Бывает, нужна диагностическая команда, которая никогда не должна рушить плейбук:

-10

Таска выполнится, результат сохранится, но даже при ошибке плейбук продолжит работу.

Типичная ошибка.

Ставить
ignore_errors: yes везде, где страшно.

Так легко спрятать настоящую проблему.

Гораздо лучше явно описать условие в failed_when.

Почему это работает

Ansible для каждой задачи делает одно и то же:

  1. Собирает переменные и факты.
  2. Проверяет условие when — «нужно ли вообще запускать эту задачу».
  3. Запускает модуль (если условие прошло).
  4. Получает результат: код возврата, вывод, признак изменения.
  5. Сверху применяет ваши правила:
    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.

Сделать прямо сейчас

  1. Откройте любой свой плейбук и найдите задачу, которая:
    должна выполняться только на части хостов,

    — добавьте к ней понятный when.
  2. Найдите задачу с command или shell, которая всегда показывает changed,

    — добавьте changed_when: false или разумное условие по выводу.
  3. Там, где вы сейчас используете ignore_errors: yes, подумайте:

    — можно ли заменить это на аккуратное failed_when с понятной логикой по rc?
  4. Добавьте в плейбук комментарии «по-человечески», чтобы коллега понял, зачем здесь это условие.

CTA

Если вам зашла такая подача Ansible,

подпишитесь на канал» — дальше разберём циклы, handlers и jinja.

Есть вопросы по when, changed_when или failed_when?

Напишите в комментариях свой пример задачи — разберём и превратим в аккуратный, понятный плейбук.