Spec-Zone.ru › Ansible

Обработка ошибок в плейбуках

Когда Ansible получает ненулевой код возврата от команды или сообщение об ошибке от модуля, по умолчанию он прекращает выполнение на этом хосте и продолжает работу на других хостах. Однако в некоторых случаях может потребоваться другое поведение. Иногда ненулевой код возврата означает успешное выполнение. Иногда нужно, чтобы ошибка на одном хосте останавливала выполнение на всех хостах. Ansible предоставляет инструменты и настройки для обработки таких ситуаций и помогает получить желаемое поведение, вывод и отчётность.

  • Игнорирование ошибок команд
  • Игнорирование ошибок недоступных хостов
  • Повторная активация недоступных хостов
  • Обработчики и ошибки
  • Определение ошибки
  • Определение состояния «изменено»
  • Обеспечение успешного выполнения команд и shell
  • Прерывание выполнения плейбука на всех хостах

    • Прерывание при первой ошибке: any_errors_fatal
    • Установка максимального процента ошибок
  • Управление ошибками в блоках

Игнорирование ошибок команд

По умолчанию Ansible прекращает выполнение задач на хосте, если задача на этом хосте завершается с ошибкой. Чтобы продолжить выполнение несмотря на ошибку, можно использовать ignore_errors.

- name: Do not count this as a failure
  ansible.builtin.command: /bin/false
  ignore_errors: true

Директива ignore_errors работает только в том случае, если задача может быть запущена и возвращает значение «failed». Она не заставляет Ansible игнорировать ошибки неопределённых переменных, сбои подключения, проблемы выполнения (например, отсутствие пакетов) или синтаксические ошибки.

Игнорирование ошибок недоступных хостов

Добавлено в версии 2.7.

Можно игнорировать ошибку задачи, вызванную тем, что экземпляр хоста недоступен («UNREACHABLE»), с помощью ключевого слова ignore_unreachable. Ansible игнорирует ошибки задачи, но продолжает выполнять последующие задачи на недоступном хосте. Например, на уровне задачи:

- name: This executes, fails, and the failure is ignored
  ansible.builtin.command: /bin/true
  ignore_unreachable: true

- name: This executes, fails, and ends the play for this host
  ansible.builtin.command: /bin/true

А также на уровне плейбука:

- hosts: all
  ignore_unreachable: true
  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: false

Повторная активация недоступных хостов

Если Ansible не может подключиться к хосту, он помечает его как «UNREACHABLE» и удаляет из списка активных хостов на время выполнения. С помощью 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 either condition is met
  ansible.builtin.command: /usr/bin/example-command
  register: command_result
  failed_when: command_result.rc != 0 or 'ERROR' in command_result.stdout

Можно проверить наличие слова или фразы в выводе команды

- 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.stderr'

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

failed_when: result.rc == 0 or "No such" not in result.stderr

Если условий слишком много, чтобы уместить их в одной строке, можно разбить их на несколько строк в значении 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

  - name: This task will always report 'changed' status
    ansible.builtin.command: /path/to/command
    changed_when: True

Для переопределения результата «изменено» можно также объединить несколько условий.

- 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

В условиях можно ссылаться на простые переменные, чтобы избежать повторения определённых выражений, как в следующем примере:

- name: Example playbook
  hosts: myHosts
  vars:
    log_path: /home/ansible/logfolder/
    log_file: log.log

  tasks:
    - name: Create empty log file
      ansible.builtin.shell: mkdir {{ log_path }} || touch {{ log_path }}{{ log_file }}
      register: tmp
      changed_when:
        - tmp.rc == 0
        - 'tmp.stderr != "mkdir: cannot create directory ‘" ~ log_path ~ "’: File exists"'

Примечание

Обратите внимание: вокруг переменной log_path в выражении changed_when отсутствуют двойные фигурные скобки {{ }}.

Как и when, эти два условия не требуют разделителей шаблонов ({{ }}), поскольку являются необработанными выражениями Jinja2.

Если вы всё же используете их, Ansible выдаст предупреждение о том, что условные выражения не должны содержать разделители шаблонов Jinja2.

Дополнительные примеры синтаксиса условий см. в разделе Определение ошибки.

Обеспечение успешного выполнения command и shell

Модули 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

Эту возможность можно использовать, когда для продолжения выполнения плейбука все задачи должны завершиться успешно. Например, если вы запускаете службу на машинах в нескольких центрах обработки данных, а балансировщики нагрузки направляют пользовательский трафик к службе, перед остановкой службы для обслуживания нужно отключить все балансировщики нагрузки. Чтобы любая ошибка в задаче отключения балансировщиков нагрузки останавливала все остальные задачи:

---
- 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 применяется к каждой группе, если используется вместе с параметром serial. В приведённом выше примере, если в первой (или любой другой) группе более 3 из 10 серверов завершат работу с ошибкой, оставшаяся часть плейбука будет прервана.

Примечание

Указанный процент должен быть превышен, а не достигнут. Например, если для serial задано значение 4 и нужно прервать выполнение плейбука при сбое 2 систем, установите max_fail_percentage равным 49, а не 50.

Управление ошибками в блоках

Для определения реакции на ошибки задач можно также использовать блоки. Этот подход похож на обработку исключений во многих языках программирования. Подробности и примеры см. в разделе Обработка ошибок с помощью блоков.

См. также

Плейбуки Ansible

Введение в плейбуки

Общие советы

Советы и рекомендации по работе с плейбуками

Условные выражения

Условные операторы в плейбуках

Использование переменных

Всё о переменных

Общение

Есть вопросы? Нужна помощь? Хотите поделиться идеями? Посетите руководство по общению сообщества Ansible

© 2012–2018 Michael DeHaan
© 2018–2025 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_error_handling.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API