【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