Ansible处理程序无法运行多个处理程序任务

22
我们有一个Ansible角色需要在handlers/main.yml任务文件中运行三个任务,但它只运行第一个任务。我如何强制它运行其他两个任务?如果第一个任务失败,我确实在其中加入了ignore标记。
tasks/main.yml文件如下:
- name: openfire | Copy plugins into openfire/plugins
  copy: src={{ srcdir }}/xmpp/{{ item }} dest=${bindir}/openfire/plugins/{{ item }}
  with_items:
   - x.jar
   - y.jar
  sudo: yes
  sudo_user: ${tomcat_user}
  notify: restart openfire

- name: openfire | Copy jars into openfire/lib
  copy: src={{ srcdir }}/xmpp/{{ item }} dest=${bindir}/openfire/lib/{{ item }}
  with_items:
   - a.jar
   - b.jar
  sudo: yes
  sudo_user: ${tomcat_user}
  notify: restart openfire

handlers/main.yml 文件如下所示:

- name: restart openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: restart openfire
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes

只有第一个处理程序任务(关闭openfire)运行。


我想它会运行与第一个匹配的内容,然后从那个playbook中退出。你尝试过将servicefile模块合并到一个单独的块中吗?这样做会使故障排除更加困难,而且非常丑陋,但它仍然应该能够工作。 - Mxx
以前它是可以工作的。我在想我们的负责人是否安装了一些ansible库...我们正在使用的可执行文件没有改变。我认为我将完全消除对这个openfire安装使用处理程序,并在正常playbook结束时强制启动服务。 - Nova
等一下。我刚刚看了你的 playbook,它看起来非常奇怪。为什么你要停止一个服务,然后删除其pid文件,再重新启动它呢?为什么不只用一个 state=restarted 语句呢?那样会真正“重启”(停止和启动)你的服务。 - Mxx
我不知道。我需要从原始开发人员那里找出他为什么这样做。当新的jar文件放入openfire时,playbook中调用处理程序,之后的所有内容都只是微小的调整,不会影响tomcat。我认为在playbook本身中只需添加一个常规的state=restarted就可以安全地实现,而不必将其作为处理程序。 - Nova
处理程序是在某些变化发生时运行的,如果您将处理程序移动到任务中,似乎会更好。 - dalore
我已经按照您所说的做了。我不明白为什么一开始要使用handler。我删除了两个“notify”语句,并添加了一个最终任务来启动Openfire服务,现在一切都正常工作。 - Nova
4个回答

28

处理程序可以调用另一个通知。多个通知调用也是允许的:

---
- name: restart something
  command: shutdown.sh 
  notify:
    - wait for stop
    - start something
    - wait for start

- name: wait for stop
  wait_for: port={{port}} state=stopped

- name: start something
  command: startup.sh

- name: wait for start
  wait_for: port={{port}} state=started

1
这正是我需要的。谢谢。 - Jonathan

23

从 Ansible 2.2 开始,您现在可以使用 listen 指令同时通知多个处理程序:

- name: stop openfire
  listen: restart openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: remove openfire pid file
  listen: restart openfire
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  listen: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes

使用“topic”与listen指令在处理程序中运行多个任务是一种官方记录的方式。我认为这是最好的答案。 - luqo33

9
也许已经晚了,因为您的帖子是1月份的,但是...为什么您会给所有不同的处理程序命名相同的名称?理应根据它们的name在任务中调用处理程序,因此您可能需要以不同的方式对它们进行命名。尝试将处理程序文件更改为以下内容:
- name: stop openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: remove openfire pid
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes

无论如何,我同意Mxx的观点,就是这个handlers文件很奇怪。使用一个state=restarted应该就足够了。

8
上面的示例代码中使用Ansible中的notify方式并不是官方支持的,所以我不会感到惊讶它不起作用(如果它真的能够起作用,我会感到惊讶)。在您的特定情况下,使用一个任务或一个处理程序来简单地使用state=restarted重启服务将是更好的选择:
- service: name=openfire state=restarted enabled=yes

然而,如果您需要在一次操作中运行多个处理程序,则最好的方法是通知链中的每个单独命令。请注意,这几乎总是表示存在更深层次的问题...但偶尔,我不得不在某个处理程序完成后通知另一个处理程序,如下所示:
# Inside handlers/main.yml:
- name: import database
  mysql_db: name=database state=import target=/path/to/dump.sql
  notify: run shell script

- name: run shell script
  shell: /path/to/some/shell/script.sh

这种情况应该很少见,但对于某些场景来说并不是太糟糕的选择(在我的案例中,我需要导入一个数据库转储文件,然后在完成后运行一个shell脚本,使该操作具有幂等性的最佳方法是通知导入数据库处理程序,而不是尝试在我的playbook中直接执行导入)。


1
我必须反对。上面的“notify”指令是正确使用的,与最新文档和我的许多playbook一致。您可以在“handlers/main.yml”文件中定义任务,并通过“tasks/*”文件中的“notify”调用它们,没有任何问题,实际上,这是正确的方法。如果您想要一个简单的例子,请查看此存储库 :) - José L. Patiño
4
我并没有暗示你不能从tasks/playbooks中调用handlers,只是你不能定义多个完全相同名称的handlers,并期望所有这些handlers都被调用。这个答案简单地展示了如果需要,你可以如何依次调用多个handlers。 - geerlingguy
我对此感到非常惊讶,因为这使得处理程序在可重用角色中变得极其不实用。你必须为一个通知拥有且只能有一个监听器?真的吗? - Craig Ringer
问题4943指出:
如果你想触发多个处理程序,处理程序按名称唯一。 @CraigRinger,文档中肯定还没有明确说明。
- Marc Tamsky
@CraigRinger - 你可能不想承认情况并不像你所描述的那样糟糕,但现实是,处理程序存在于全局命名空间中,不相关的角色可能会声明重叠的名称;请参见mdehaan的讨论。通过声明一个唯一命名的“事件”handler,它仅仅是“分发”更多的notify_events_到其他几个唯一命名的handlers,你所描述的OO _event_模型是可行的。 - Marc Tamsky
显示剩余2条评论

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