Управление состоянием задач с помощью changed_when и failed_when
На этом шаге вы получите более точный контроль над тем, как Ansible интерпретирует результаты ваших задач. Вы узнаете о двух мощных директивах: changed_when и failed_when.
changed_when: По умолчанию модули, такие как ansible.builtin.command или ansible.builtin.shell, почти всегда сообщают о состоянии "changed" (изменено), даже если выполненная ими команда не внесла изменений в систему. changed_when позволяет определить пользовательское условие, которое определяет, должна ли задача быть помечена как "changed". Это крайне важно для написания идемпотентных плейбуков и для точного запуска обработчиков.
failed_when: Иногда команда может завершиться с ненулевым кодом выхода (что Ansible считает ошибкой), даже если результат является приемлемым. failed_when позволяет переопределить условия ошибки по умолчанию, позволяя вашему плейбуку продолжать работу на основе более интеллектуальных критериев, таких как вывод команды или конкретный код выхода.
Начнем с настройки нового каталога проекта.
cd ~/project
mkdir control-state-lab
cd control-state-lab
Создайте стандартный файл inventory для localhost.
nano inventory
Добавьте следующее содержимое:
localhost ansible_connection=local
Сохраните и выйдите из редактора (Ctrl+X, Y, Enter).
Использование changed_when
Сначала посмотрим, как задача команды ведет себя по умолчанию. Мы создадим плейбук, который выполняет команду date. Эта команда просто выводит дату и не изменяет систему, но модуль command сообщит о ней как об изменении.
Создайте новый плейбук с именем playbook.yml.
nano playbook.yml
Введите следующее содержимое:
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (default behavior)
ansible.builtin.command: date
Сохраните и выйдите. Теперь запустите плейбук.
ansible-playbook -i inventory playbook.yml
Обратите внимание в выводе, что задача помечена как changed=1, хотя ничего в системе не было изменено.
...
TASK [Check local time (default behavior)] *************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 ...
Теперь давайте используем changed_when, чтобы сообщить Ansible, что эта команда никогда не изменяет систему. Измените playbook.yml.
nano playbook.yml
Добавьте changed_when: false к задаче.
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (with changed_when)
ansible.builtin.command: date
changed_when: false
Сохраните и выйдите. Запустите плейбук снова.
ansible-playbook -i inventory playbook.yml
На этот раз задача сообщает ok, а в итоговом сводке показано changed=0. Вы успешно переопределили поведение по умолчанию.
...
TASK [Check local time (with changed_when)] ************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
Использование failed_when
Далее давайте изучим failed_when. Мы создадим задачу, которая проверяет наличие файла, которого нет. Команда по умолчанию "завершится с ошибкой".
Сначала создайте фиктивный файл для поиска.
echo "System is running" > status.txt
Теперь измените playbook.yml, чтобы искать слово "ERROR" в этом файле. Команда grep завершится с кодом выхода 1, поскольку слово не найдено, что Ansible интерпретирует как ошибку.
nano playbook.yml
Замените содержимое следующим:
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (will fail)
ansible.builtin.command: grep ERROR status.txt
Сохраните и выйдите. Запустите плейбук.
ansible-playbook -i inventory playbook.yml
Как и ожидалось, выполнение плейбука останавливается с сообщением FAILED!.
...
TASK [Check for ERROR in status file (will fail)] ******************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["grep", "ERROR", "status.txt"], "delta": "...", "end": "...", "msg": "non-zero return code", "rc": 1, ...}
...
Это не то, чего мы хотим. Отсутствие "ERROR" является для нас условием успеха. Мы можем использовать failed_when, чтобы переопределить, что считается ошибкой. Мы сообщим Ansible, что ошибка возникает только в том случае, если код возврата команды больше 1. Код возврата 1 (шаблон не найден) теперь будет считаться успехом. Нам также нужно register результат задачи, чтобы проверить ее код возврата (rc).
Измените playbook.yml в последний раз.
nano playbook.yml
Обновите плейбук с помощью register и failed_when.
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (with failed_when)
ansible.builtin.command: grep ERROR status.txt
register: grep_result
failed_when: grep_result.rc > 1
changed_when: false
Мы также добавили changed_when: false, потому что grep является операцией только для чтения и не изменяет систему.
Сохраните и выйдите. Запустите финальный плейбук.
ansible-playbook -i inventory playbook.yml
Успех! Задача теперь сообщает ok, потому что ее код возврата был 1, что не соответствует нашему новому условию ошибки (rc > 1). Плейбук успешно завершается.
...
TASK [Check for ERROR in status file (with failed_when)] ***********************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
Теперь вы узнали, как использовать changed_when и failed_when для точного определения состояний успеха, изменения и ошибки ваших задач, что приводит к более надежной и интеллектуальной автоматизации.