Spec-Zone.ru › Ansible

Обработчики: выполнение операций при изменении

Иногда требуется, чтобы задача выполнялась только при внесении изменений на компьютере. Например, может понадобиться перезапустить службу, если задача обновляет её конфигурацию, но не перезапускать её, если конфигурация не изменилась. Для этого 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 только один раз, чтобы избежать ненужных перезапусков.

Уведомления и циклы

Задачи могут использовать циклы для уведомления обработчиков. Это особенно полезно в сочетании с переменными, чтобы создавать несколько динамических уведомлений.

Обратите внимание: обработчики запускаются, если задача в целом завершилась с изменениями. При использовании цикла состояние «изменено» устанавливается, если изменился хотя бы один элемент цикла. То есть любое изменение запускает все обработчики.

tasks:
- name: Template services
  ansible.builtin.template:
    src: "{{ item }}.j2"
    dest: /etc/systemd/system/{{ item }}.service
  # Note: if *any* loop iteration triggers a change, *all* handlers are run
  notify: Restart {{ item }}
  loop:
    - memcached
    - apache

handlers:
  - name: Restart memcached
    ansible.builtin.service:
      name: memcached
      state: restarted

  - name: Restart apache
    ansible.builtin.service:
      name: apache
      state: restarted

В приведённом выше примере memcached и 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).

Имя каждого обработчика должно быть уникальным в глобальной области видимости. Если определено несколько обработчиков с одинаковым именем, уведомить и выполнить можно будет только последний загруженный в сценарий обработчик (см. handlers_insertion_order), который фактически затенит все предыдущие обработчики с таким же именем.

Порядок добавления обработчиков в сценарий

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

  1. Обработчики из ролей в разделе roles:.
  2. Обработчики из раздела handlers:.
  3. Обработчики из ролей, статически импортированных с помощью задач import_role.
  4. Обработчики из ролей, динамически включённых с помощью задач include_role (становятся доступны во время выполнения только после выполнения задачи include_role).

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

Управление временем запуска обработчиков

По умолчанию обработчики запускаются после завершения всех задач определённого сценария. Уведомлённые обработчики автоматически выполняются после каждого из следующих разделов в указанном порядке: pre_tasks, roles/tasks и post_tasks. Такой подход эффективен, поскольку обработчик запускается только один раз независимо от количества уведомивших его задач. Например, если несколько задач обновляют файл конфигурации и уведомляют обработчик о необходимости перезапустить Apache, Ansible перезапустит Apache только один раз, чтобы избежать ненужных перезапусков.

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

Включения и импорты в обработчиках

Если уведомить динамическое включение, например include_task, как обработчик, будут выполнены все задачи внутри этого включения. Уведомить обработчик, определённый внутри динамического включения, невозможно.

Если использовать статическое включение, например import_task, в качестве обработчика, перед выполнением сценария этот обработчик фактически будет заменён обработчиками из импорта. Само статическое включение нельзя уведомить; однако отдельные задачи внутри него можно уведомлять по отдельности.

Мета-задачи в качестве обработчиков

Начиная с Ansible 2.14, мета-задачи можно использовать и уведомлять как обработчики. Однако обратите внимание, что flush_handlers нельзя использовать в качестве обработчика, чтобы избежать непредвиденного поведения.

Ограничения

Обработчик не может запускать import_role и include_role. Обработчики игнорируют теги.

© 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_handlers.html

Spec-Zone.ru

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