Обработка ошибок в плейбуках
Когда Ansible получает код возврата, отличный от нуля, от команды или ошибку от модуля, по умолчанию он останавливает выполнение на этом хосте и продолжает на других хостах. Однако в некоторых случаях вам может потребоваться другое поведение. Иногда код возврата, отличный от нуля, указывает на успех. Иногда вы хотите, чтобы ошибка на одном хосте остановила выполнение на всех хостах. Ansible предоставляет инструменты и настройки для обработки этих ситуаций и помогает вам получить желаемое поведение, вывод и отчеты.
- Игнорирование ошибок команд
- Игнорирование ошибок недоступных хостов
- Сброс недоступных хостов
- Обработчики и ошибки
- Определение ошибки
- Определение «изменений»
- Обеспечение успеха для команд и оболочки
- Управление ошибками в блоках
Игнорирование ошибок команд
По умолчанию Ansible останавливает выполнение задач на хосте, когда задача на этом хосте завершается ошибкой. Вы можете использовать ignore_errors для продолжения выполнения несмотря на ошибку:
- name: Do not count this as a failure ansible.builtin.command: /bin/false ignore_errors: yes
Директива ignore_errors работает только тогда, когда задача может быть выполнена и возвращает значение ‘failed’. Она не заставляет Ansible игнорировать ошибки неопределенных переменных, ошибки подключения, проблемы с выполнением (например, отсутствующие пакеты) или синтаксические ошибки.
Игнорирование ошибок недоступных хостов
Новое в версии 2.7.
Вы можете игнорировать ошибку задачи из-за того, что хост отмечен как «НЕДОСТУПНЫЙ», с помощью ключевого слова ignore_unreachable. Ansible игнорирует ошибки задачи, но продолжает выполнение последующих задач на недоступном хосте. Например, на уровне задачи:
- name: This executes, fails, and the failure is ignored ansible.builtin.command: /bin/true ignore_unreachable: yes - name: This executes, fails, and ends the play for this host ansible.builtin.command: /bin/true
И на уровне плейбука:
- hosts: all
ignore_unreachable: yes
tasks:
- name: This executes, fails, and the failure is ignored
ansible.builtin.command: /bin/true
- name: This executes, fails, and ends the play for this host
ansible.builtin.command: /bin/true
ignore_unreachable: no
Сброс недоступных хостов
Если Ansible не может подключиться к хосту, он помечает этот хост как «НЕДОСТУПНЫЙ» и удаляет его из списка активных хостов для выполнения. Вы можете использовать meta: clear_host_errors для повторной активации всех хостов, чтобы последующие задачи могли снова попытаться подключиться к ним.
Обработчики и ошибки
Ansible запускает обработчики в конце каждого плейбука. Если задача оповещает обработчик, но другая задача завершается ошибкой позже в плейбуке, по умолчанию обработчик не выполняется на этом хосте, что может привести к неожиданному состоянию хоста. Например, задача может обновить файл конфигурации и оповестить обработчик о перезапуске некоторой службы. Если задача позже в том же плейбуке завершится ошибкой, конфигурационный файл может быть изменён, но служба не будет перезапущена.
Вы можете изменить это поведение с помощью опции командной строки --force-handlers, включив force_handlers: True в плейбук или добавив force_handlers = True в ansible.cfg. Когда обработчики принудительно запускаются, Ansible выполнит все оповещенные обработчики на всех хостах, даже на хостах с ошибками задач. (Обратите внимание, что некоторые ошибки всё ещё могут помешать выполнению обработчика, например, если хост станет недоступным.)
Определение ошибки
Ansible позволяет определять, что означает «ошибка» в каждой задаче, используя условное выражение failed_when. Как и все условные выражения в Ansible, списки из нескольких failed_when условий соединяются с неявным and, что означает, что задача завершается ошибкой только в том случае, когда все условия выполнены. Если вы хотите, чтобы задача завершалась ошибкой, когда выполняется любое из условий, вы должны определить условия в строке с явным оператором or.
Вы можете проверить на ошибку, найдя слово или фразу в выводе команды:
- name: Fail task when the command error output prints FAILED ansible.builtin.command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr"
или на основе кода возврата:
- name: Fail task when both files are identical ansible.builtin.raw: diff foo/file1 bar/file2 register: diff_cmd failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2
Вы также можете объединить несколько условий для определения ошибки. Эта задача завершится ошибкой, если оба условия верны:
- name: Check if a file exists in temp and fail task if it does
ansible.builtin.command: ls /tmp/this_should_not_be_here
register: result
failed_when:
- result.rc == 0
- '"No such" not in result.stdout'
Если вы хотите, чтобы задача завершалась ошибкой, когда выполняется только одно условие, измените определение failed_when на:
failed_when: result.rc == 0 or "No such" not in result.stdout
Если у вас слишком много условий, чтобы поместить их в одну строку, вы можете разбить их на несколько строк yaml с помощью >:
- name: example of many failed_when conditions with OR
ansible.builtin.shell: "./myBinary"
register: ret
failed_when: >
("No such file or directory" in ret.stdout) or
(ret.stderr != '') or
(ret.rc == 10)
Определение «изменений»
Ansible позволяет определять, когда конкретная задача произвела «изменения» на удалённом узле, используя условное выражение changed_when. Это позволяет определить, исходя из кодов возврата или вывода, следует ли сообщать об изменении в статистике Ansible и следует ли запускать обработчик или нет. Как и все условные выражения в Ansible, списки из нескольких changed_when условий соединяются с неявным and, что означает, что задача сообщает об изменении только в том случае, когда все условия выполнены. Если вы хотите сообщить об изменении, когда выполняется любое из условий, вы должны определить условия в строке с явным оператором or. Например:
tasks:
- name: Report 'changed' when the return code is not equal to 2
ansible.builtin.shell: /usr/bin/billybass --mode="take me to the river"
register: bass_result
changed_when: "bass_result.rc != 2"
- name: This will never report 'changed' status
ansible.builtin.shell: wall 'beep'
changed_when: False
Вы также можете объединить несколько условий для изменения результата «changed»:
- name: Combine multiple conditions to override 'changed' result
ansible.builtin.command: /bin/fake_command
register: result
ignore_errors: True
changed_when:
- '"ERROR" in result.stderr'
- result.rc == 2
См. Определение ошибки для дополнительных примеров синтаксиса условных выражений.
Обеспечение успеха для команд и оболочки
Модули command и shell учитывают коды возврата, поэтому если у вас есть команда, чей успешный код выхода не равен нулю, вы можете сделать так:
tasks:
- name: Run this command and ignore the result
ansible.builtin.shell: /usr/bin/somecommand || /bin/true
Прерывание плейбука на всех хостах
Иногда вы хотите, чтобы ошибка на одном хосте или ошибки на определённом проценте хостов прервали весь плейбук на всех хостах. Вы можете остановить выполнение плейбука после первой ошибки с помощью any_errors_fatal. Для более точного управления вы можете использовать max_fail_percentage для прерывания выполнения после достижения заданного процента ошибок на хостах.
Прерывание при первой ошибке: any_errors_fatal
Если вы установите any_errors_fatal и задача возвращает ошибку, Ansible завершает задачу с ошибкой на всех хостах в текущей группе, а затем останавливает выполнение плейбука на всех хостах. Последующие задачи и плейбуки не будут выполнены. Вы можете восстановиться после критических ошибок, добавив раздел rescue в блок. Вы можете установить any_errors_fatal на уровне плейбука или блока:
- hosts: somehosts
any_errors_fatal: true
roles:
- myrole
- hosts: somehosts
tasks:
- block:
- include_tasks: mytasks.yml
any_errors_fatal: true
Вы можете использовать эту функцию, когда все задачи должны быть на 100% успешными, чтобы продолжить выполнение плейбука. Например, если вы запускаете службу на машинах в нескольких центрах обработки данных с балансировщиками нагрузки для передачи трафика от пользователей к службе, вы хотите, чтобы все балансировщики были отключены, прежде чем остановить службу на техническое обслуживание. Чтобы гарантировать, что любая ошибка в задаче, отключающей балансировщики, остановит все остальные задачи:
---
- hosts: load_balancers_dc_a
any_errors_fatal: true
tasks:
- name: Shut down datacenter 'A'
ansible.builtin.command: /usr/bin/disable-dc
- hosts: frontends_dc_a
tasks:
- name: Stop service
ansible.builtin.command: /usr/bin/stop-software
- name: Update software
ansible.builtin.command: /usr/bin/upgrade-software
- hosts: load_balancers_dc_a
tasks:
- name: Start datacenter 'A'
ansible.builtin.command: /usr/bin/enable-dc
В этом примере Ansible начинает обновление программного обеспечения на фронт-эндах только если все балансировщики были успешно отключены.
Установление максимального процента ошибок
По умолчанию Ansible продолжает выполнять задачи, пока есть хосты, которые ещё не завершились ошибкой. В некоторых ситуациях, таких как выполнение развертывания в режиме переключения, вы можете прервать плейбук, когда будет достигнута определённая граница ошибок. Для этого вы можете установить максимальный процент ошибок на плейбуке:
--- - hosts: webservers max_fail_percentage: 30 serial: 10
Настройка max_fail_percentage применяется к каждой группе, когда вы используете её с последовательным режимом. В примере выше, если более 3 из 10 серверов в первой (или любой) группе серверов завершились ошибкой, остальная часть плейбука будет прервана.
Примечание
Установленный процент должен быть превышен, а не равен. Например, если последовательность была установлена на 4, и вы хотите, чтобы задача прервала плейбук, когда 2 системы завершились ошибкой, установите max_fail_percentage в 49, а не 50.
Управление ошибками в блоках
Вы также можете использовать блоки для определения ответов на ошибки задач. Этот подход похож на обработку исключений во многих языках программирования. Подробности и примеры см. в разделе Обработка ошибок с помощью блоков.
См. также
- Введение в плейбуки
-
Введение в плейбуки
- Советы и хитрости
-
Советы и хитрости для плейбуков
- Условные выражения
-
Условные операторы в плейбуках
- Использование переменных
-
Всё о переменных
- Список рассылки пользователей
-
Есть вопрос? Заходите на форум!
- irc.freenode.net
-
Канал IRC-чата #ansible
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.10/user_guide/playbooks_error_handling.html