Пишем роли ansible не ломая прод — особенности check_mode или как правильно его готовить

от автора

В данном опусе я попытаюсь рассказать как можно писать роли и плэйбуки такими, чтобы они отыгрывали без падений при запуске с флагом --check. Зачем вот это всё: вы в команде адептов инфраструктуры как код и не только раскатываете свою инфраструктуру, но и обновляете ее и хотите быстро восстанавливать, а это значит что вы должны обеспечивать одну из ключевых концепций ansible — идемпотентность повторных запусков. Для этого вы вынуждены не только писать роли, применяя их в лабораторных условиях, но и применения их на реальной инфраструктуре, о том как дебажить при этом ямлы написано например здесь. Применять код который сделает множество изменений в продакшн — такое себе удовольствие не для слабонервных, поэтому и мы будем пускать его предварительно с флагом —check — в холостую, желая посмотреть те изменения которые будут внесены в целевую инфраструктуру. То есть, если вы собираетесь реконфигурировать сервис в одном конфиге и перезапустить-перегрузить его вы должны увидеть только 2 изменения (changed) по итогах запуска.

Итак, как этого добиться.

Игнорируем игнорирование

Конечно же можно заигнорить таски с ошибками выставив ignore_errors: true, но это путь к непредсказуемому поведению на целевом хосте и пропуску не только единичных задач, но и блоков и плэйбуков, в рамках холостого запуска. К чему это приведет — это приведет к потенциальной необработанной ошибке. Как это исправить — определить логическую переменную и использовать ее в качестве флага игнорирования:

- set_fact:     your_vars_ignore: true - debug:     var: your_vars_ignore   ignore_errors: "{{ your_vars_ignore }}" 

Использовать в качестве таковых переменных встроенные переменные ansible, например ansible_check_mode, то есть при запуске с флагом --check игнорировать ошибки — поможет вам в тех случаях когда нецелесообразно вычислять промежуточную переменную и выполнение игнорируемого кода предсказуемо.

- debug:     msg: "no errors in check mode"   ignore_errors: "{{ ansible_check_mode }}"

Никаких холостых прогонов

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

--- - set_fact:     always_var: "this var is defined always"   check_mode: false

Хороший shell — он как модуль

Мы все частенько пренебрегаем использованием модулей command и shell не искав найдя нужного модуля ansible или используя специфичные утилиты командной строки. Так вот использование этих модулей с флагом check будет практически всегда выдавать изменение. Этим можно и нужно гибко управлять.

Учимся правильно падать

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

Учимся правильно изменяться

Ansible позволяет определить, когда конкретная задача “изменила” удаленный узел, используя changed_when условие. Это позволяет вам определить, на основе кодов возврата или выходных данных, следует ли сообщать об изменении в статистике Ansible и следует ли запускать обработчик или нет. Как и во всех условных обозначениях в Ansible, списки из нескольких changed_when условий объединены неявным and.

--- - 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: 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

Выводы.

Использование описанных выше способов позволяет выполнить следующие требования к скриптам конфигурирования:

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

  • при запуске скрипта с флагом —check выполняются все задачи

  • запуск скрипта с флагом check не приводит к изменению на целевой инфраструктуре

З.Ы. данный текст целиком и полностью написан на телефоне.


ссылка на оригинал статьи https://habr.com/ru/articles/746864/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *