Запустите обработчик 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, обработчики могут также "прослушивать" общие темы, а задачи могут уведомить эти темы следующим образом:
Таким образом, обработчики уведомляются / выполняются один раз для каждого блока задач. Может быть, ваша цель состоит в том, чтобы оставить обработчики после "всех" целевых хостов, но это не кажется чистым использованием обработчиков.,