Ответ
В Ansible я управляю ошибками через комбинацию директив ignore_errors, failed_when, changed_when и блоков rescue. Это позволяет писать идемпотентные и отказоустойчивые плейбуки.
1. Игнорирование ожидаемых ошибок (ignore_errors):
Использую, когда неудача задачи не должна останавливать выполнение всего плейбука.
- name: Остановить сервис, если он запущен
ansible.builtin.systemd:
name: my-old-service
state: stopped
ignore_errors: yes # Не падать, если сервис уже остановлен или не существует
register: stop_result
2. Кастомные условия неудачи (failed_when):
Позволяет определить, что считать ошибкой, на основе вывода задачи. Это мощнее простого ignore_errors.
- name: Проверить, что порт 8080 свободен
ansible.builtin.shell: netstat -tln | grep ':8080'
register: port_check
failed_when: port_check.rc == 0 # Считаем ошибкой, если порт занят (команда grep нашла совпадение)
changed_when: false
3. Блоки обработки ошибок (block / rescue / always):
Аналогично try-catch-finally в языках программирования. Основной инструмент для сложных сценариев.
- name: Развертывание с откатом при ошибке
block:
- name: Копировать новую конфигурацию
ansible.builtin.copy:
src: /tmp/new_nginx.conf
dest: /etc/nginx/nginx.conf
- name: Проверить синтаксис nginx
ansible.builtin.command: nginx -t
register: nginx_test
- name: Перезагрузить nginx
ansible.builtin.systemd:
name: nginx
state: reloaded
rescue:
- name: Восстановить старую конфигурацию при ошибке
ansible.builtin.copy:
src: /tmp/backup_nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Записать ошибку в лог
ansible.builtin.debug:
msg: "Развертывание провалилось на шаге '{{ ansible_failed_task.name }}'. Конфигурация откачена."
always:
- name: Всегда удалять временные файлы
ansible.builtin.file:
path: /tmp/new_nginx.conf
state: absent
Практический пример из CI/CD: При развертывании в Kubernetes может потребоваться проверить, что новый под запустился, прежде чем удалять старый.
- name: Развернуть новую версию приложения
kubernetes.core.k8s:
definition: "{{ lookup('file', 'deployment.yaml') }}"
wait: yes
wait_timeout: 60
register: deployment_result
failed_when: not deployment_result.resources[0].status.availableReplicas Ответ 18+ 🔞
А, ну так вот, слушай, про управление ошибками в Ansible. Это ж, блядь, целая наука, если честно. Ты представь: пишешь плейбук, запускаешь его на десятке серверов, а он на первом же падает, как подкошенный, из-за какой-нибудь ерунды. И вся автоматизация коту под хвост. Так что тут надо хитрить, как лиса, и предвидеть всякое.
1. Игнорирование ожидаемых ошибок (ignore_errors):
Это как раз для тех случаев, когда ты знаешь, что может пойти по пизде, но тебе похуй. Ну, не совсем похуй, но ты готов к этому. Например, пытаешься остановить сервис, а его уже нету. Без этой директивы плейбук просто накроется медным тазом.
- name: Остановить сервис, если он запущен
ansible.builtin.systemd:
name: my-old-service
state: stopped
ignore_errors: yes # Не падать, если сервис уже остановлен или не существует
register: stop_result
Смотри, тут главное — register. Потому что если ты ошибку проигнорировал, то тебе же надо знать, что там произошло, а? А то остановил ты его или нет, нихуя не понятно. Так что всегда регистрируй результат, чувак, доверия ебать ноль ко всему.
2. Кастомные условия неудачи (failed_when):
Вот это уже поинтереснее. ignore_errors — это тупой молоток, а failed_when — хирургический скальпель. Ты сам решаешь, что считать пиздецом, а что — нормой.
- name: Проверить, что порт 8080 свободен
ansible.builtin.shell: netstat -tln | grep ':8080'
register: port_check
failed_when: port_check.rc == 0 # Считаем ошибкой, если порт занят (команда grep нашла совпадение)
changed_when: false
Понимаешь прикол? Команда grep возвращает код 0, если нашла совпадение. То есть если порт занят. А нам это как раз не надо! Вот мы и говорим: «Ансибл, ёпта, если команда выполнилась успешно (rc == 0), то это и есть наша ошибка! Падай!» А changed_when: false — это чтобы он не считал, что что-то изменил, просто проверка.
3. Блоки обработки ошибок (block / rescue / always):
Это, блядь, высший пилотаж. Прямо как в нормальных языках: try — catch — finally. Охуенно удобная штука для сложных операций, где надо иметь план «Б».
- name: Развертывание с откатом при ошибке
block:
- name: Копировать новую конфигурацию
ansible.builtin.copy:
src: /tmp/new_nginx.conf
dest: /etc/nginx/nginx.conf
- name: Проверить синтаксис nginx
ansible.builtin.command: nginx -t
register: nginx_test
- name: Перезагрузить nginx
ansible.builtin.systemd:
name: nginx
state: reloaded
rescue:
- name: Восстановить старую конфигурацию при ошибке
ansible.builtin.copy:
src: /tmp/backup_nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Записать ошибку в лог
ansible.builtin.debug:
msg: "Развертывание провалилось на шаге '{{ ansible_failed_task.name }}'. Конфигурация откачена."
always:
- name: Всегда удалять временные файлы
ansible.builtin.file:
path: /tmp/new_nginx.conf
state: absent
Смотри как красиво. В block ты делаешь рискованную операцию — замена конфига nginx. Если на любом этапе (копирование, проверка синтаксиса, перезагрузка) случается пиздец, выполнение прыгает сразу в rescue. Там ты откатываешь всё нахуй к старой конфигурации и пишешь в лог, что всё плохо. А секция always выполнится в любом случае — хоть всё прошло удачно, хоть нет. Идеально для уборки за собой, чтобы не оставлять временные файлы, как распиздяй какой-нибудь.
Практический пример из CI/CD: Ну и куда же без этого. Вот типичная задача: развернуть в кубере и убедиться, что под поднялся, прежде чем старый удалять.
- name: Развернуть новую версию приложения
kubernetes.core.k8s:
definition: "{{ lookup('file', 'deployment.yaml') }}"
wait: yes
wait_timeout: 60
register: deployment_result
failed_when: not deployment_result.resources[0].status.availableReplicas
Тут failed_when опять рулит. Мы ждём 60 секунд (wait_timeout), и если за это время количество доступных реплик не станет больше нуля, то считаем, что развертывание не удалось. И плейбук упадёт, не дав тебе удалить старую версию и оставить сервис в полной жопе. Умно, да? Э бошка думай, прежде чем что-то ломать.
Короче, суть в чём: не надейся, что всё всегда будет гладко. Предполагай худшее, обрабатывай ошибки явно, и тогда твои плейбуки будут не просто скриптами, а надёжными, ебать, инструментами, которые не подведут в самый ответственный момент. Иначе будет вам хиросима и нигерсраки на продакшене, а тебя потом спросят: «Ну и какого хуя?»