Ansible如何重播通知

时间:2014-02-03 21:47:18

标签: provisioning ansible ansible-playbook

目前我正在从木偶转为 Ansible ,我对某些概念或至少是如何运作感到困惑。

有关设置的一些信息:

我正在使用Ansible Best Practices中的示例,并将我的项目与几个角色(剧本)等结构化。

我正在使用Vagrant进行配置,盒子是Saucy64 VBox。

混乱来自哪里:

当我配置并运行ansible时,任务开始执行,然后是一堆通知。

示例:

上一个任务:

TASK: [mysql | delete anonymous MySQL server user for localhost] ************** 
<127.0.0.1> REMOTE_MODULE mysql_user user='' state=absent 
changed: [default] => {"changed": true, "item": "", "user": ""}

然后是第一次通知:

NOTIFIED: [timezone | update tzdata] ****************************************** 
<127.0.0.1> REMOTE_MODULE command /usr/sbin/dpkg-reconfigure --frontend noninteractive tzdata
changed: [default] => {"changed": true, "cmd": ["/usr/sbin/dpkg-reconfigure", "--frontend", "noninteractive", "tzdata"], "delta": "0:00:00.224081", "end": "2014-02-03 22:34:48.508961", "item": "", "rc": 0, "start": "2014-02-03 22:34:48.284880", "stderr": "\nCurrent default time zone: 'Europe/Amsterdam'\nLocal time is now:      Mon Feb  3 22:34:48 CET 2014.\nUniversal Time is now:  Mon Feb  3 21:34:48 UTC 2014.", "stdout": ""}

现在一切都很好。随着角色的增加,越来越多的通知陷入困境。

现在出现了问题。

当通知失败时,配置会照常停止。但是通知堆栈是空的! 这意味着在故障之后的所有通知都不会被执行!

如果是这样,那么如果您更改了apache的vhosts设置并且有关于重新加载的apache服务的通知,那么这将丢失。

让我们举个例子(伪郎):

- name: Install Apache Modules
  notify: Restart Apache

- name: Enable Vhosts
  notify: Reload Apache

- name: Install PHP
  command: GGGGGG # throws an error

执行以上操作时:

  1. 安装了Apache模块
  2. 启用虚拟主机
  3. PHP尝试istall并失败
  4. 脚本退出
  5. (通知在哪里?)
  6. 现在这一切似乎都是合乎逻辑的但是Ansible再次试图聪明(没有!*)堆栈通知,因此重新加载和重启apache将导致在配置结束时单次重启apache运行。这意味着所有通知都将失败!!!

    现在对某些人来说这也很好。他们会说他们只是重新运行配置并且通知将启动,因此apache将最终重新加载并且站点将再次启动。 情况并非如此。

    在更正安装php的代码后,在脚本的第二次运行中,由于设计,通知将无法运行。为什么呢?

    这就是为什么: Ansible将具有成功执行的任务,标记为“完成/绿色”,因此不会为这些任务注册任何通知。配置将成功,为了触发通知,因此apache重新启动,您可以执行以下操作之一:

    1. 通过ansible或ssh
    2. 向服务器运行直接命令
    3. 编辑脚本以触发任务
    4. 为该
    5. 添加单独的任务
    6. 销毁箱子的实例并重新配置
    7. 这非常令人沮丧,因为需要彻底清理盒子,或者我对Ansible没有正确理解?

      还有另一种'回收'/重播/强制执行通知的方法吗?

      • 聪明人要么将任务标记为不完整,要么重新启动通知,要么保留一个单独的队列,并将通知作为自己的任务。*

2 个答案:

答案 0 :(得分:3)

是的,与Puppet相比,这是Ansible的缺点之一。 Puppet是声明性的,并且不会像Ansible(或Chef)那样出错。它有正面和负面的,例如Puppet在开始运行之前需要一点时间,因为它需要编译它的目录。

因此,如果您的Ansible脚本出错,那么您就是对的,那么您的通知更新就不会发生。我们解决它的唯一方法是使用条件语句。在你的剧本中你可以做这样的事情:

- name: My cool playbook
  hosts: all

  vars:
      force_tasks: 0

  tasks:
    - name: Apache install
      action: apt pkg=$item state=latest
      with_items:
       - apache2
       - apache2-mpm-prefork

    - name: Restart apache
      action: service name=apache2 state=restart
      when: force_tasks

然后,当您运行Playbook时,您可以将force_tasks作为环境变量传递:

ansible-playbook -i my_inventory -e "force_tasks=True" my_ansible_playbook.yml

您可以使用与标签类似的方式完成此操作。

答案 1 :(得分:0)

使用--force-handlers标志运行ansible-playbook。这告诉Ansible即使任务失败并且进一步处理停止也会运行任何排队的处理程序。 Ansible开发人员计划将此作为选项添加到ansible.cfg文件中,以便可以全局设置并将其遗忘。我不知道那个时间框架是什么。