运行 整个剧本只有一次 Ansible 处理程序
Run an Ansible handler only once for the entire playbook
我想 运行 一个处理程序在整个剧本中只出现一次。
我尝试在剧本文件的以下内容中使用 include 语句,但这导致处理程序 运行 多次,每次播放一次:
- 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
如何让剧本对整个剧本只执行一次处理程序?
我不清楚你的处理程序应该做什么。总之,至于official documentation,handlers
are triggered at the end of each block of tasks in a play,
and will only be triggered once even if notified by multiple different
tasks [...] As of Ansible 2.2, handlers can also “listen” to generic topics, and tasks can notify those topics as follows:
因此,每个任务块都会通知/执行一次处理程序。
也许您只是在 "all" 目标主机之后保留处理程序而达到了目标,但这似乎并不是对处理程序的干净使用。
.
答案
标题中问题的字面答案是:没有。
剧本是剧本列表。 Playbook 没有命名空间、没有变量、没有状态。所有配置、逻辑和任务都在 plays 中定义。
处理程序是一个具有不同调用计划的任务(不是顺序的,而是有条件的,在播放结束时一次,或由 meta: flush_handlers
任务触发)。
一个处理程序属于一个剧本,而不是一个剧本,并且没有办法在剧本之外触发它(即在剧本的末尾)。
解决方案
无需参考处理程序即可解决问题。
您可以使用 group_by
module 根据每个游戏底部的任务结果创建一个 ad-hoc 组。
然后您可以在 playbook 的末尾定义一个单独的 play,在属于上述 ad-hoc 组的目标上重新启动服务。
请参考以下存根的想法:
- 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
任务只 运行 整个播放一次,即使在处理程序中,另请参阅 documentation。但是,如果收到通知,它将在标记完成后 运行 从处理程序命令中暗示。
处理程序循环执行任务 运行 的主机,并检查主机服务是否需要重启,如果需要,添加到特殊的 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
.
我想 运行 一个处理程序在整个剧本中只出现一次。
我尝试在剧本文件的以下内容中使用 include 语句,但这导致处理程序 运行 多次,每次播放一次:
- 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
如何让剧本对整个剧本只执行一次处理程序?
我不清楚你的处理程序应该做什么。总之,至于official documentation,handlers
are triggered at the end of each block of tasks in a play, and will only be triggered once even if notified by multiple different tasks [...] As of Ansible 2.2, handlers can also “listen” to generic topics, and tasks can notify those topics as follows:
因此,每个任务块都会通知/执行一次处理程序。 也许您只是在 "all" 目标主机之后保留处理程序而达到了目标,但这似乎并不是对处理程序的干净使用。 .
答案
标题中问题的字面答案是:没有。
剧本是剧本列表。 Playbook 没有命名空间、没有变量、没有状态。所有配置、逻辑和任务都在 plays 中定义。
处理程序是一个具有不同调用计划的任务(不是顺序的,而是有条件的,在播放结束时一次,或由 meta: flush_handlers
任务触发)。
一个处理程序属于一个剧本,而不是一个剧本,并且没有办法在剧本之外触发它(即在剧本的末尾)。
解决方案
无需参考处理程序即可解决问题。
您可以使用 group_by
module 根据每个游戏底部的任务结果创建一个 ad-hoc 组。
然后您可以在 playbook 的末尾定义一个单独的 play,在属于上述 ad-hoc 组的目标上重新启动服务。
请参考以下存根的想法:
- 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
任务只 运行 整个播放一次,即使在处理程序中,另请参阅 documentation。但是,如果收到通知,它将在标记完成后 运行 从处理程序命令中暗示。
处理程序循环执行任务 运行 的主机,并检查主机服务是否需要重启,如果需要,添加到特殊的 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
.