对整个playbook只运行一次Ansible处理程序

时间:2017-01-09 20:41:06

标签: ansible ansible-handlers

我想在整个剧本中只运行一次处理程序。

我尝试在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

以下是处理程序/ 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

如何让剧本只对整个剧本执行一次处理程序?

4 个答案:

答案 0 :(得分:10)

答案

标题中问题的字面答案是:否。

Playbook是一个播放列表。 Playbook没有命名空间,没有变量,没有状态。所有配置,逻辑和任务都在播放中定义。

处理程序是一个具有不同调用计划的任务(不是顺序的,而是有条件的,一旦在游戏结束时,或由meta: flush_handlers任务触发)。

处理程序属于一个游戏,而不是一个剧本,并且无法在游戏之外触发它(即在剧本的末尾)。

<强>解决方案

可以在不参考处理程序的情况下解决问题。

您可以使用group_by module根据每个游戏底部的任务结果创建一个ad-hoc群组。

然后,你可以在剧本的末尾定义一个单独的游戏,重新启动属于上述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

答案 1 :(得分:2)

可能的解决方案

使用处理程序将主机添加到内存清单中。然后添加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

答案 2 :(得分:0)

我不清楚你的处理程序应该做什么。无论如何,至于https://www.dll-files.com/,处理程序

  

在游戏中的每个任务块结束时触发,   并且即使被多个不同的通知也只会触发一次   任务 [...]从Ansible 2.2开始,处理程序也可以“监听”通用主题,任务可以按如下方式通知这些主题:

因此,每个任务块都会通知/执行一次处理程序。 可能是你的目标只是在“所有”目标主机之后保留处理程序,但它似乎并不是处理程序的干净利用。

答案 3 :(得分:0)

binary crossentropy中触发的处理程序将在所有其他操作之后运行。并且可以将处理程序设置为post_tasks