【问题标题】:A play with multiple hosts has block/always. How to let the playbook exit once the play fails on either host?与多个主机一起玩的游戏有阻塞/总是。一旦在任一主机上播放失败,如何让剧本退出?
【发布时间】:2020-01-09 11:57:00
【问题描述】:

我的剧本中有两个剧本(1 和 2)。 首先播放 play1 有两个任务 (A/B)。 如果任务 A 失败,我需要任务 B 也被执行,然后剧本退出。 换句话说,将跳过播放 2。 所以我使用了 block/always 方法。 当主机是单主机时它工作正常。 但是当我指定多个主机播放时, play2 仍然被执行。 虽然 play2 只针对一台主机执行,但我希望 playbook 在 play2 之前退出。

我尝试将 any_errors_fatal 添加到任务 A,但它不起作用。

# 单主机剧本

  • 名称:测试块 1

    主机:pltB

    gather_facts:没有

    任务:

    • 块:

      • 命令:“/usr/bin/hostname1”

      注册:hostname_res

      any_errors_fatal: true

      总是:

      • debug: msg="from always block 1"
  • 名称:测试块 2

    主机:pltB

    gather_facts:没有

    任务:

    • 块:

      • debug: msg="result is {{ hostname_res.stdout }} "

      总是:

      • debug: msg="from always block 2" ...

单主机输出

ansible-playbook test.yml -i ../inventory/serverhosts

播放 [测试块 1] ******************************************* ******************************************************

TASK [命令] ******************************************* ************************************************ 致命:[192.168.111.25]:失败! => {"changed": false, "cmd": "/usr/bin/hostname1", "msg": "[Errno 2] 没有这样的文件或目录", "rc": 2}

任务[调试] ******************************************* ****************************************** 好的:[192.168.111.25] => { "msg": "从总是块 1" } 要重试,请使用:--limit @/home/playbooks/test.retry

播放回顾 ************************************************ ****************************************** 192.168.111.25 : ok=1 改变=0 unreachable=0 failed=1

主机中有多个服务器


  • 名称:测试块 1

    主机:pltB,pltA

    gather_facts:没有

    任务:

    • 块:

      • 命令:“/usr/bin/hostname1”

      注册:hostname_res

      any_errors_fatal: true

      总是:

      • debug: msg="from always block 1"
  • 名称:测试块 2

    主机:pltB,pltA

    gather_facts:没有

    任务:

    • 块:

      • debug: msg="result is {{ hostname_res.stdout }} "

      总是:

      • debug: msg="from always block 2" ...

多台服务器的输出

播放 [测试块 1] ******************************************* ************************************************

TASK [命令] ******************************************* ************************************************ 致命:[192.168.111.25]:失败! => {"changed": false, "cmd": "/usr/bin/hostname1", "msg": "[Errno 2] 没有这样的文件或目录", "rc": 2} 更改:[192.168.111.24]

任务[调试] ******************************************* ************************************************ 好的:[192.168.111.25] => { "msg": "从总是块 1" } 好的:[192.168.111.24] => { "msg": "从总是块 1" }

播放[测试块2] ***************************************** ************************************************

任务[调试] ******************************************* ************************************************ 好的:[192.168.111.24] => { “味精”:“结果是 plt001” }

任务[调试] ******************************************* ******************************************* 好的:[192.168.111.24] => { "msg": "从总是块 2" } 要重试,请使用:--limit @/home/playbooks/test.retry

播放回顾 ************************************************ ****************************************************** ******** 192.168.111.24:ok=4 改变=1 不可达=0 失败=0 192.168.111.25 : ok=1 改变=0 unreachable=0 failed=1

【问题讨论】:

    标签: ansible


    【解决方案1】:

    我认为这种行为是 Ansible 中的一个错误,但是我将从一种解决方法开始,以获得我认为您所追求的行为。

    解决方法

    ansible_play_batch 中在block 之前注册一个事实,并在阻塞之后有一个任务/总是有一个任务在活动主机数量减少时失败。

    来自 Ansible 特殊变量文档

    ansible_play_batch 当前播放运行中的活动主机列表受串行限制,也称为“批处理”。失败/无法访问的主机不被视为“活动”。

    https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html

    ---
    - hosts: all
      gather_facts: no
      tasks:
        - name: set fact with play batch size
          local_action:
            module: set_fact
            play_batch_size: "{{ ansible_play_batch|length|int }}"
          run_once: yes
        - block:
          - name: failing task on some hosts
            command: "cat test.txt"
            any_errors_fatal: true
          always:
          - name: message from always section
            debug:
              msg: "Debug task success"
    
        - name: fail if the batch size has decreased
          local_action:
            module: fail
            msg: "Halting playbook execution due to prior error, when {{ ansible_play_batch|length|int }} < {{ play_batch_size }}"
          when: ansible_play_batch|length|int < play_batch_size
          run_once: true
    
        - name: this should never run
          debug:
            msg: "Epic fail"
    
    

    除了在控制台 PLAY RECAP 中正确识别故障主机之外,该剧本按预期工作。

    问题说明

    您所看到的并且我正在使用 Ansible v2.8.1 重现的行为是成功完成的 always 部分正在擦除错误状态而不触发 any_errors_fatal 条件。

    删除错误状态是使用rescue 块的一个记录功能。根据当前最新的有关 Blocks 的 Ansible 文档,

    always 部分运行,无论之前在 blockrescue 部分中发生或未发生的错误。应该注意的是,如果 rescue 部分成功完成,因为它“擦除”错误状态(但不是报告),则播放继续,这意味着它不会触发 max_fail_percentageany_errors_fatal 配置,但会出现在剧本统计。

    https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#id4

    但是,根据我们双方观察到的行为,文档应为“...如果 rescuealways 部分成功完成,则播放继续”或更可能是 Ansible 的行为不正确,或者至少与块/救援/始终不像 java 的 try/catch/finally 行为不一致。由于 always 部分等同于 java 的 finally,我不希望 always 部分中有任何内容来防止在启用 any_errors_fatal 时停止 playbook 失败。在 playbook 和 Ansible 默认级别启用 any_errors_fatal 对观察到的行为没有影响。

    【讨论】:

    • 非常感谢您如此详细的解释,安德鲁。但是我已经找到了另一种解决方法,我认为它更简单 - 名称:测试块 1 主机:所有 max_fail_percentage:0 任务:-块:-命令:“/usr/bin/hostname1”注册:主机名_res始终:-调试: msg="from always block 1" - 失败:when: hostname_res.rc != 0
    • 没问题,罗杰。这两种解决方法之间的区别在于您从一个失败的命令中检查特定的已知错误代码。如果您从一个命令中只有一次失败(我承认这是您最初的问题),那没关系。如果您有多个可能失败的命令,那么我的解决方法将捕获块中任何任务的任何失败。顺便说一句,您仍然可以在解决方法中使用 any_errors_fatal 而不是 max_fail_percentage。
    • 是的,您的解决方案更通用。我的只有在我们知道检查条件的情况下才能使用。
    • any_errors_fatal: true 也可以直接添加到playbook中,检测任务中的“失败”之类的语句
    猜你喜欢
    • 2015-12-14
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2017-07-17
    相关资源
    最近更新 更多