Определение
Хендлер (handler
) — это тип таски в Ansible, который предназначен для выполнения после вызова другими тасками
Основные отличия таски от хендлера:
- Хендлеры выполняются в самом конце группы тасок и могут быть вызваны до 3 раз (см. предыдущий пост про pre_tasks/post_tasks), при этом порядок выполнения будет соответствовать порядку записи
- Хендлеры вызываются директивой
notify: <имя_хендлера>
и выполняются только если результат таски имеет статусCHANGED
- Хендлер будет выполнен один раз, даже если он был вызвал несколько раз
Согласно официальной документации хендлеры стоит применять для перезапуска или перезагрузки служб, но на этом область их применения не заканчивается, в общем виде использование хендлера выглядит так:
tasks:
- name: Configure network
ansible.builtin.template:
dest: /etc/network/interfaces
src: networking.j2
owner: root
group: root
mode: "0644"
backup: true
notify: Restart networking
handlers:
- name: Restart networking
ansible.builtin.systemd:
name: networking
state: restarted
Практика
Логически таска ниже равносильна таске выше, но использование when: <some_var>.changed
— очень плохая практика:
tasks:
- name: Configure network
ansible.builtin.template:
dest: /etc/network/interfaces
src: networking.j2
owner: root
group: root
mode: "0644"
backup: true
register: network_config
- name: Restart networking
ansible.builtin.systemd:
name: networking
state: restarted
when: network_config.changed
Но на этом не все, хендлеры умеют многое другое, например:
Хендлер может вызывать другие хендлеры или даже группу задач через include_tasks
или import_tasks
:
tasks:
- name: Always changed
ansible.builtin.command: /bin/true
notify:
- First handler
handlers:
- name: First handler
ansible.builtin.command: /bin/true
notify: Inlcude tasks
- name: Inlcude tasks
ansible.builtin.include_tasks: tasks/main.
Можно изменить имя для вызова хендлера путем использования Jinja2 шаблона в имени хендлера, либо использовав директиву listen:
, но для listen:
можно использовать только статичные строки:
vars:
service: apache2
tasks:
- name: Always changed
ansible.builtin.command: /bin/true
notify:
- Restart {{ service }}
- Reboot
handlers:
- name: Restart {{ service }}
ansible.builtin.systemd:
name: "{{ service }}"
state: restarted
- name: Reboot task
ansible.builtin.reboot:
listen: Reboot
Используя модуль ansible.builtin.meta: flush_handlers
можно выполнить все ранее вызванные хендлеры и сбросить их счетчик, что позволит вызвать их снова:
tasks:
- name: Configure network
ansible.builtin.template:
dest: /etc/network/interfaces
src: networking.j2
owner: root
group: root
mode: "0644"
backup: true
notify: Restart networking
- name: Restart right away
ansible.builtin.meta: flush_handlers
- name: Notify again
ansible.builtin.command: /bin/true
notify: Restart networking
handlers:
- name: Restart networking
ansible.builtin.systemd:
name: networking
state: restarted
Поскольку roles
просто “включается” в tasks
, то можно вызвать хендлеры из роли (пример можно также найти в предыдущем посте), при этом для удобства можно использовать конструкцию имя_роли/FQCN_роли : имя хендлера
, например:
- name: Always change
ansible.builtin.command: /bin/true
notify: 'k3s.orchestration.raspberrypi : Reboot Pi'
Исходя из 3 пунтка единственное условия для вызова хендлера это статус CHANGED
, и, как следствие, можно самому определить условие изменение путем changed_when: <условие>
:
tasks:
- name: Run sample task
ansible.builtin.command: /bin/true
changed_when: false
notify: Say hello
# Не будет вызван из-за 'changed_when: false'
handlers:
- name: Say hello
ansible.builtin.debug:
msg: Hello guys