【Ansible】如果有任何一台主机(ansible_play_hosts)失败,我希望停止playbook执行

首先

ansible的版本是2.9.1.

在Ansible中,是否有以下功能?
(1)只有所有主机都没有失败,才能继续执行下一个任务
(2)想要确定已执行到最后的任务有多少台主机
在这种情况下,可以使用ansible_play_hosts和ansible_play_hosts_all变量来成功实现。
根据Ansible文档(特殊变量),似乎如下所示:
ansible_play_hosts_all:最初要执行的主机列表
ansible_play_hosts:当前正在执行的主机列表

玩法介绍1-确认ansible_play_hosts/ansible_play_hosts_all的内容。

作为例子,我们将在两台设备junos_router_1和junos_router_2上执行playbook。
在第二个任务中,我们将只将junos_router_2强制设为failed,并观察ansible_play_hosts/ansible_play_hosts_all的变化。

---
- name: play hosts TEST
  hosts: all
  connection: local
  gather_facts: no
  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: 'debug1'
      debug:
        msg: >-
             ansible_play_hosts_all : {{ ansible_play_hosts_all }},
             ansible_play_hosts : {{ ansible_play_hosts }}

    - name: 'fail router_2'
      fail:
        msg: 'router_2 is failed'  # junos_router_2を強制的にエラーにする
      when:
        - ('router_2' in inventory_hostname)

    - name: 'debug2'
      debug:
        msg: >-
             ansible_play_hosts_all : {{ ansible_play_hosts_all }},
             ansible_play_hosts : {{ ansible_play_hosts }}

执行结果1

通过将junos_router_2在第二个任务中强制设为failed,我们可以看到在下一个任务中,ansible_play_hosts只包含junos_router_1。请注意,输出结果带有u”(Unicode转义)。

PLAY [play hosts TEST] *************************************************************************************************************************************************

TASK [debug1] **********************************************************************************************************************************************************
ok: [junos_router_2] => {
    "msg": "ansible_play_hosts_all : [u'junos_router_1', u'junos_router_2'], ansible_play_hosts : [u'junos_router_1', u'junos_router_2']"
}
ok: [junos_router_1] => {
    "msg": "ansible_play_hosts_all : [u'junos_router_1', u'junos_router_2'], ansible_play_hosts : [u'junos_router_1', u'junos_router_2']"  
}

TASK [fail router_2] ***************************************************************************************************************************************************
skipping: [junos_router_1]
fatal: [junos_router_2]: FAILED! => {"changed": false, "msg": "router_2 is failed"}

TASK [debug2] **********************************************************************************************************************************************************
ok: [junos_router_1] => {
    "msg": "ansible_play_hosts_all : [u'junos_router_1', u'junos_router_2'], ansible_play_hosts : [u'junos_router_1']"  
} # ansible_play_hostsの内容が変化

PLAY RECAP *************************************************************************************************************************************************************
junos_router_1             : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
junos_router_2             : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

如果在执行Playbook的过程中出现了一次失败,即使只有一个节点出现失败,Playbook也会提前终止。

ansible_play_hosts和ansible_play_hosts_all都是以列表形式存在的,所以使用set_fact来获取元素数量,并且如果在主机发生错误并导致元素数量不同,则任务将终止执行。
要点:
(1) 使用set_fact来获取列表的元素数量
(2) 如果元素数量不同,则会产生错误
(3) 如果在主机中发生任何错误,则该任务将不会被执行

---
- name: play hosts TEST
  hosts: all
  connection: local
  gather_facts: no
  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: 'fail router_2'
      fail:
        msg: 'router_2 is failed'
      when:
        - ('router_2' in inventory_hostname)

    - block:
        - name: 'set_fact'
          set_fact:
            ansible_play_hosts_all_cnt : "{{ ansible_play_hosts_all | count }}"  #ポイント(1)
            ansible_play_hosts_cnt : "{{ ansible_play_hosts | count }}"

        - name: 'set_fact_result'
          debug:
            msg: >-
                 ansible_play_hosts_all_cnt: {{ ansible_play_hosts_all_cnt }},
                 ansible_play_hosts_cnt: {{ ansible_play_hosts_cnt }}

        - name: 'failed host'
          fail:
            msg: 'failed host exists'
          when:
            - (ansible_play_hosts_all_cnt != ansible_play_hosts_cnt)  #ポイント(2)

        - name: 'debug - all OK'  # ポイント(3)
          debug:
            msg: 'no failed host'
          when:
            - (ansible_play_hosts_all_cnt == ansible_play_hosts_cnt)
      run_once: true

执行结果2

由于强行将 Junos 路由器 2 设置为失败状态,我们可以看到最后一个任务(任务名:debug – all OK)未被执行。

PLAY [play hosts TEST] *************************************************************************************************************************************************

TASK [fail router_2] ***************************************************************************************************************************************************
skipping: [junos_router_1]
fatal: [junos_router_2]: FAILED! => {"changed": false, "msg": "router_2 is failed"}

TASK [set_fact] ********************************************************************************************************************************************************
ok: [junos_router_1]

TASK [set_fact_result] *************************************************************************************************************************************************
ok: [junos_router_1] => {
    "msg": "ansible_play_hosts_all_cnt: 2, ansible_play_hosts_cnt: 1"
}

TASK [failed host] *****************************************************************************************************************************************************
fatal: [junos_router_1]: FAILED! => {"changed": false, "msg": "failed host exists"}

NO MORE HOSTS LEFT *****************************************************************************************************************************************************

PLAY RECAP *************************************************************************************************************************************************************
junos_router_1             : ok=2    changed=0    unreachable=0    failed=1    skipped=1    rescued=0    ignored=0
junos_router_2             : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
广告
将在 10 秒后关闭
bannerAds