如何编写带有多个任务的Ansible处理程序?

93

针对变化,我有多个相关任务需要运行。如何编写具有多个任务的Ansible处理程序?

例如,我想要一个仅在服务已启动时才重新启动服务的处理程序:

- name: Restart conditionally
  shell: check_is_started.sh
  register: result

- name: Restart conditionally step 2
  service: name=service state=restarted
  when: result
3个回答

116

从 Ansible 2.2 开始,此问题已有适当的解决方案。

处理程序也可以“监听”通用主题,并且任务可以按以下方式通知这些主题:

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"

tasks:
    - name: restart everything
      command: echo "this task will restart the web services"
      notify: "restart web services"

使用此方法可以更轻松地触发多个处理程序。它还将处理程序与其名称解耦,使在playbooks和roles之间共享处理程序变得更加容易。

具体到问题,这应该可行:

    - name: Check if restarted
      shell: check_is_started.sh
      register: result
      listen: Restart processes
    
    - name: Restart conditionally step 2
      service: name=service state=restarted
      when: result
      listen: Restart processes

在任务中,通过“重启进程”通知处理程序。

https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html#naming-handlers


2
这个解决方案是否允许使用 block: 和 rescue: 来通过启动命令来处理错误? - user1767316
3
这些任务是否按照列表顺序执行?如果一个任务依赖于另一个任务,我应该在处理程序内使用notify-listen吗? - user26767
1
来自链接文档的@user26767:通知处理程序始终按照定义顺序运行,而不是按照通知语句中列出的顺序运行。这也适用于使用listen的处理程序。 - swenzel
1
很不幸,当与include_role一起使用时,listen存在缺陷,处理程序会被执行多次而不是一次。该问题在Ansible核心版本2.11.4中仍然存在。请参见:https://github.com/ansible/ansible/issues/49371 - Person
在处理程序中为每个任务命名不同的名称。如果不这样做,只有第一个唯一名称的任务会被执行,其他具有相同名称的任务会被默默地忽略。listen:参数可以相同,但- Name:必须不同。 - undefined

60
在您的处理程序文件中,使用notify将不同的步骤链接在一起。
- name: Restart conditionally
  debug: msg=Step1
  changed_when: True
  notify: Restart conditionally step 2

- name: Restart conditionally step 2
  debug: msg=Step2
  changed_when: True
  notify: Restart conditionally step 3

- name: Restart conditionally step 3
  debug: msg=Step3

然后在一个任务中使用notify: Restart conditionally进行引用。

请注意,您只能通知当前处理程序以下的处理程序。例如,Restart conditionally step 2无法通知Restart conditionally

来源:在irc.freenode.net上的#ansible频道。我不确定这是否将来会继续有效,因为它在官方文档中没有被提及作为一个特性。


4
这种方法解决了一个似乎很少有文献涉及的事实:处理程序在收到通知后,即使其中一个处理程序失败,也将被执行。如果您不希望在前一个处理程序失败时运行某些处理程序,则可以为它们使用不同的“notify”标签,这是一个“修复”的好方法。 - fbicknel

29

编辑:如果您拥有 Ansible 2.2 或以上版本,请使用 mkadan 的答案。下面的答案不适用于较新版本的 Ansible。另请注意,根据 Enis Afgan 在下面的评论中所述,由于一个错误,该答案在 2.0.2 到 2.1.2 版本的 Ansible 中无效。


从 Ansible 2.0 开始,您可以在处理程序中使用 include 动作来运行多个任务。

例如,将您的任务放入单独的文件 restart_tasks.yml 中(如果您使用角色,则会放入 tasks 子目录中,而不是 handlers 子目录中):

- name: Restart conditionally step 1
  shell: check_is_started.sh
  register: result

- name: Restart conditionally step 2
  service: name=service state=restarted
  when: result

你的处理程序将会是:

- name: Restart conditionally
  include: restart_tasks.yml

来源:GitHub 上的问题线程:https://github.com/ansible/ansible/issues/14270


5
请注意,Ansible 2.0.2到2.1.2版本之间存在一个错误,导致此操作无法正常工作:https://github.com/ansible/ansible/issues/15915 - Enis Afgan
2
对于未来的读者 - 在 Ansible 2.9.2 上,这对我没有起作用。解决方法是将 include 替换为 include_tasks - Martin Melka
@MartinMelka 谢谢,我已经在我的答案顶部添加了一个警告,说明它不适用于 Ansible 版本 >= 2.2。 - Alexander Klauer
太好了,谢谢 :) 当设计新的处理程序时,另一个答案更好。但是当Ansible清单代码过旧且只需要进行小改动(就像我所做的那样)时,您的方法仍然可以通过这个小改进变得有用。 - Martin Melka
1
如果您有一个复杂的顺序,必须让事情下降/回升,“include_tasks”是唯一明智的方法。链接处理程序是有效的解决方案,但往往情况下,“include_tasks”在功能上等效,并且更容易理解。这并不是没有副作用,因此不是一刀切的解决方案,但个人使用仅处理程序已解决了混乱和不必要的逻辑问题。 - evillive

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接