Обработчики: выполнение операций при изменении
Иногда необходимо, чтобы задача выполнялась только при внесении изменений на машине. Например, вы можете захотеть перезапустить службу, если задача обновила конфигурацию этой службы, но не если конфигурация не изменилась. Ansible использует обработчики для решения этой задачи. Обработчики — это задачи, которые выполняются только при уведомлении.
- Пример обработчика
- Уведомление обработчиков
- Именование обработчиков
- Управление выполнением обработчиков
- Определение, когда задачи меняются
- Использование переменных с обработчиками
- Обработчики в ролях
- Включения и импорты в обработчиках
- Мета-задачи как обработчики
- Ограничения
Пример обработчика
Этот плейбук, verify-apache.yml, содержит единственный плей с обработчиком.
---
- name: Verify apache installation
hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: Ensure apache is at the latest version
ansible.builtin.yum:
name: httpd
state: latest
- name: Write the apache config file
ansible.builtin.template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify:
- Restart apache
- name: Ensure apache is running
ansible.builtin.service:
name: httpd
state: started
handlers:
- name: Restart apache
ansible.builtin.service:
name: httpd
state: restarted
В этом примере плейбука сервер Apache перезапускается обработчиком после завершения всех задач в плее.
Уведомление обработчиков
Задачи могут инструктировать один или несколько обработчиков на выполнение, используя ключевое слово notify. Ключевое слово notify может быть применено к задаче и принимает список имен обработчиков, которые уведомляются при изменении задачи. В качестве альтернативы также можно указать строку, содержащую единственное имя обработчика. Следующий пример демонстрирует, как можно уведомить несколько обработчиков одной задачей:
tasks:
- name: Template configuration file
ansible.builtin.template:
src: template.j2
dest: /etc/foo.conf
notify:
- Restart apache
- Restart memcached
handlers:
- name: Restart memcached
ansible.builtin.service:
name: memcached
state: restarted
- name: Restart apache
ansible.builtin.service:
name: apache
state: restarted
В приведенном выше примере обработчики выполняются при изменении задачи в следующем порядке: Restart memcached, Restart apache. Обработчики выполняются в порядке их определения в разделе handlers, а не в порядке, указанном в инструкции notify. Уведомление одного и того же обработчика несколько раз приведет к выполнению обработчика только один раз независимо от того, сколько задач его уведомляют. Например, если несколько задач обновляют файл конфигурации и уведомляют обработчик о перезапуске Apache, Ansible перезапустит Apache только один раз, чтобы избежать ненужных перезапусков.
Именование обработчиков
Обработчики должны иметь имена, чтобы задачи могли уведомить их, используя ключевое слово notify.
В качестве альтернативы обработчики могут использовать ключевое слово listen. Используя это ключевое слово обработчика, обработчики могут подписываться на темы, которые могут группировать несколько обработчиков следующим образом:
tasks:
- name: Restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
handlers:
- name: Restart memcached
service:
name: memcached
state: restarted
listen: "restart web services"
- name: Restart apache
service:
name: apache
state: restarted
listen: "restart web services"
Уведомление темы restart web services приводит к выполнению всех обработчиков, подписанных на эту тему, независимо от того, как они названы.
Это использование значительно упрощает запуск нескольких обработчиков. Оно также отвязывает обработчики от их имен, что упрощает совместное использование обработчиков между плейбуками и ролями (особенно при использовании сторонних ролей из общего источника, такого как Ansible Galaxy).
Каждый обработчик должен иметь глобально уникальное имя. Если несколько обработчиков определены с одинаковым именем, только последний обработчик, загруженный в плей, может быть уведомлен и выполнен, фактически затмевая все предыдущие обработчики с тем же именем.
Существует только одна глобальная область видимости для обработчиков (имена обработчиков и темы подписки), независимо от места определения обработчиков. Это также относится к обработчикам, определенным в ролях.
Управление выполнением обработчиков
По умолчанию обработчики выполняются после завершения всех задач в конкретном плее. Уведомленные обработчики выполняются автоматически после каждого из следующих разделов в следующем порядке: pre_tasks, roles/tasks и post_tasks. Этот подход эффективен, так как обработчик выполняется только один раз, независимо от того, сколько задач его уведомляет. Например, если несколько задач обновляют файл конфигурации и уведомляют обработчик о перезапуске Apache, Ansible перезапустит Apache только один раз, чтобы избежать ненужных перезапусков.
Если вам нужны обработчики, выполняемые до завершения плей, добавьте задачу для их сброса с помощью модуля метамодуля, который выполняет действия Ansible:
tasks:
- name: Some tasks go here
ansible.builtin.shell: ...
- name: Flush handlers
meta: flush_handlers
- name: Some other tasks
ansible.builtin.shell: ...
Задача meta: flush_handlers запускает все уведомленные обработчики на этом этапе плей.
После того, как обработчики выполнены, либо автоматически после каждого упомянутого раздела, либо вручную задачей flush_handlers мета-задачи, они могут быть уведомлены и снова выполнены в более поздних разделах плей.
Определение, когда задачи меняются
Можно управлять тем, когда обработчики уведомляются об изменениях в задачах, используя ключевое слово changed_when.
В следующем примере обработчик перезапускает службу каждый раз, когда копируется файл конфигурации:
tasks:
- name: Copy httpd configuration
ansible.builtin.copy:
src: ./new_httpd.conf
dest: /etc/httpd/conf/httpd.conf
# The task is always reported as changed
changed_when: True
notify: Restart apache
См. Определение «изменено» для получения дополнительной информации об changed_when.
Использование переменных с обработчиками
Возможно, вы захотите, чтобы ваши обработчики Ansible использовали переменные. Например, если имя службы незначительно варьируется в зависимости от дистрибутива, вы хотите, чтобы ваш вывод отображал точное имя перезапущенной службы для каждой целевой машины. Избегайте размещения переменных в имени обработчика. Поскольку имена обработчиков шаблонизируются на ранней стадии, Ansible может не иметь доступного значения для имени обработчика такого типа:
handlers:
# This handler name may cause your play to fail!
- name: Restart "{{ web_service_name }}"
Если переменная, используемая в имени обработчика, недоступна, весь плей завершается ошибкой. Изменение этой переменной в середине плей не приведет к созданию нового обработчика.
Вместо этого размещайте переменные в параметрах задачи вашего обработчика. Вы можете загрузить значения, используя include_vars следующим образом:
tasks:
- name: Set host variables based on distribution
include_vars: "{{ ansible_facts.distribution }}.yml"
handlers:
- name: Restart web service
ansible.builtin.service:
name: "{{ web_service_name | default('httpd') }}"
state: restarted
В то время как имена обработчиков могут содержать шаблон, темы listen не могут.
Обработчики в ролях
Обработчики из ролей не просто содержатся в их ролях, а вставляются в глобальную область видимости вместе со всеми другими обработчиками из плей. В связи с этим их можно использовать вне роли, в которой они определены. Это также означает, что их имя может конфликтовать с обработчиками извне роли. Чтобы убедиться, что обработчик из роли уведомляется, а не обработчик извне роли с тем же именем, уведомляйте обработчик, используя его имя в следующем формате: role_name : handler_name.
Обработчики, уведомленные в разделе roles, автоматически сбрасываются в конце раздела tasks, но до любых обработчиков tasks.
Включения и импорты в обработчиках
Уведомление динамического включения, такого как include_task, в качестве обработчика приводит к выполнению всех задач из включения. Уведомление обработчика, определенного внутри динамического включения, невозможно.
Использование статического включения, такого как import_task, в качестве обработчика приводит к тому, что этот обработчик фактически переписывается обработчиками из этого импорта до выполнения плей. Само статическое включение не может быть уведомлено; задачи из этого включения, с другой стороны, могут быть уведомлены индивидуально.
Мета-задачи как обработчики
Начиная с Ansible 2.14, мета-задачи разрешается использовать и уведомлять как обработчики. Обратите внимание, что, однако, flush_handlers не может использоваться в качестве обработчика для предотвращения непредвиденного поведения.
Ограничения
Обработчик не может выполнить import_role или include_role.
© 2012–2018 Michael DeHaan
© 2018–2024 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html