Запустите обработчик Ansible только один раз для всей пьесы

Я хотел бы запустить обработчик только один раз во всей пьесе.

Я попытался использовать оператор include в файле playbook, но это привело к тому, что обработчик запускался несколько раз, по одному для каждой игры:

- name: Configure common config
  hosts: all
  become: true
  vars:
        OE: "{{ ansible_hostname[5] }}"
  roles:
    - { role: common }
  handlers:
    - include: handlers/main.yml

- name: Configure metadata config
  hosts: metadata
  become: true
  vars:
        OE: "{{ ansible_hostname[5] }}"
  roles:
    - { role: metadata }
  handlers:
    - include: handlers/main.yml

Вот содержимое handlers/main.yml:

- name: restart autofs
  service:
    name: autofs.service
    state: restarted

Вот пример одной из задач, которая уведомляет обработчик:

- name: Configure automount - /opt/local/xxx in /etc/auto.direct
  lineinfile:
     dest: /etc/auto.direct
     regexp: "^/opt/local/xxx"
     line: "/opt/local/xxx   -acdirmin=0,acdirmax=0,rdirplus,rw,hard,intr,bg,retry=2  nfs_server:/vol/xxx"
  notify: restart autofs

Как я могу заставить playbook выполнять обработчик только один раз для всего playbook?

4 ответа

Решение

Ответ

Дословный ответ на вопрос в названии: нет.

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

Обработчик - это задача с другим расписанием вызовов (не последовательным, а условным, один раз в конце воспроизведения или запущенная meta: flush_handlers задача).

Обработчик принадлежит пьесе, а не пьесе, и нет способа вызвать его за пределами пьесы (то есть в конце пьесы).


Решение

Решение проблемы возможно без обращения к обработчикам.

Ты можешь использовать group_by Модуль для создания специальной группы на основе результатов задач в нижней части каждой игры.

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

Обратитесь к заглушке ниже для идеи:

- hosts: all
  roles:
    # roles declaration
  tasks:
    - # an example task modifying Nginx configuration
      register: nginx_configuration

    # ... other tasks ...

    - name: the last task in the play
      group_by:
        key: hosts_to_restart_{{ 'nginx' if nginx_configuration is changed else '' }}

# ... other plays ...

- hosts: hosts_to_restart_nginx
  gather_facts: no
  tasks:
    - service:
        name: nginx
        state: restarted

Возможное решение

Используйте обработчики для добавления хостов в инвентарь в памяти. Затем добавьте play запустить службу перезапуска только для этих хостов. Смотрите этот пример:

Если задача изменена, она уведомляет mark to restart установить факт, что хосту требуется перезапуск сервиса.

Второй обработчик add host совершенно особенный, потому что add_host задание выполняется только один раз для всей игры, даже в обработчике, см. также документацию. Но если получено уведомление, оно будет запущено после того, как будет выполнена маркировка, подразумеваемая из порядка обработчиков. Обработчик зацикливается на узлах, на которых выполнялись задачи, и проверяет, нужно ли перезапускать службу узла, если да, добавьте в специальную hosts_to_restart группа.

Поскольку факты являются постоянными во всех играх, уведомите третьего обработчика clear mark для затронутых хостов.

Многие строки вы прячете с помощью перемещаемых обработчиков в отдельный файл и включаете их.

инвентарный файл

10.1.1.[1:10]
[primary]
10.1.1.1
10.1.1.5

test.yml

---

- hosts: all
  gather_facts: no
  tasks:
      - name: Random change to notify trigger
        debug: msg="test"
        changed_when: "1|random == 1"
        notify:
            - mark to restart
            - add host
            - clear mark
  handlers:
      - name: mark to restart
        set_fact: restart_service=true
      - name: add host
        add_host:
            name: "{{item}}"
            groups: "hosts_to_restart"
        when: hostvars[item].restart_service is defined and hostvars[item].restart_service
        with_items: "{{ansible_play_batch}}"
      - name: clear mark
        set_fact: restart_service=false

- hosts: primary
  gather_facts: no
  tasks:
      - name: Change to notify trigger
        debug: msg="test"
        changed_when: true
        notify:
            - mark to restart
            - add host
            - clear mark
  handlers:
      - name: mark to restart
        set_fact: restart_service=true
      - name: add host
        add_host:
            name: "{{item}}"
            groups: "hosts_to_restart"
        when: hostvars[item].restart_service is defined and hostvars[item].restart_service
        with_items: "{{ansible_play_batch}}"
      - name: clear mark
        set_fact: restart_service=false


- hosts: hosts_to_restart
  gather_facts: no
  tasks:
      - name: Restart service
        debug: msg="Service restarted"
        changed_when: true

Обработчик запущен в post_tasksбудет работать после всего остального. И обработчик может быть установлен на run_once: true.

Мне не ясно, что должен делать ваш обработчик. Во всяком случае, что касается официальной документации, обработчики

запускаются в конце каждого блока задач в игре и будут запускаться только один раз, даже если они уведомлены несколькими различными задачами [...] Начиная с Ansible 2.2, обработчики могут также "прослушивать" общие темы, а задачи могут уведомить эти темы следующим образом:

Таким образом, обработчики уведомляются / выполняются один раз для каждого блока задач. Может быть, ваша цель состоит в том, чтобы оставить обработчики после "всех" целевых хостов, но это не кажется чистым использованием обработчиков.,

Другие вопросы по тегам