环境
- 控制节点:Ubuntu 22.04
- Ansible 2.10.8
- 管理节点:CentOS 8
block
顾名思义,通过block可以把task按逻辑划分到不同的“块”里面,实现“块操作”。此外,block还提供了错误处理功能。
task分组
下面的例子,把3个task放到一个block里面。
创建文件 testBlock1.yml
如下:
---
- name: testBlock1hosts: alltasks:- name: My task 1block:- name: Part1debug:msg: "Hello Zhang San"- name: Part2debug:msg: "Hello Li Si"- name: Part3debug:msg: "Hello Wang Wu"when: 2 > 1
运行结果如下:
➜ temp ansible-playbook testBlock1.ymlPLAY [testBlock1] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Zhang San"
}TASK [Part2] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Li Si"
}TASK [Part3] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Wang Wu"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
如果把block的判断条件 when: 2 > 1
改为 when: 2 == 1
,则运行结果如下:
➜ temp ansible-playbook testBlock1.ymlPLAY [testBlock1] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
skipping: [192.168.1.55]TASK [Part2] ***************************************************************************************
skipping: [192.168.1.55]TASK [Part3] ***************************************************************************************
skipping: [192.168.1.55]PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
可见,由于条件不满足,block里的3个task都没有执行。
错误处理
如果block里的某个task出错了,则后面的task不再运行。
创建文件 testBlock2.yml
如下:
---
- name: testBlock2hosts: alltasks:- name: My task 1block:- name: Part1debug:msg: "Hello Zhang San"- name: Part2command: /bin/false # will trigger an error- name: Part3debug:msg: "Hello Li Si"
运行结果如下:
➜ temp ansible-playbook testBlock2.ymlPLAY [testBlock2] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Zhang San"
}TASK [Part2] ***************************************************************************************
fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001904", "end": "2023-10-26 08:50:36.850526", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 08:50:36.848622", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可见,由于Part2出错,Part3并没有运行。
Ansible的错误处理有两个关键字:
rescue
:类似于catch
always
:类似于finally
先加上 always
看看效果:
---
- name: testBlock2hosts: alltasks:- name: My task 1block:- name: Part1debug:msg: "Hello Zhang San"- name: Part2command: /bin/false # will trigger an error- name: Part3debug:msg: "Hello Li Si"always:- name: Always do thisdebug:msg: "End End End"
➜ temp ansible-playbook testBlock2.ymlPLAY [testBlock2] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Zhang San"
}TASK [Part2] ***************************************************************************************
fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.002734", "end": "2023-10-26 08:52:19.329781", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 08:52:19.327047", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}TASK [Always do this] ******************************************************************************
ok: [192.168.1.55] => {"msg": "End End End"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=3 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可见,Part2出错, always
也会运行(当然,Part3不会运行)。
注意:加上 always
,failed仍然是1。
现在来试一下 rescue
:
---
- name: testBlock2hosts: alltasks:- name: My task 1block:- name: Part1debug:msg: "Hello Zhang San"- name: Part2command: /bin/false # will trigger an error- name: Part3debug:msg: "Hello Li Si"always:- name: Always do thisdebug:msg: "End End End"rescue:- name: Rescue tasksdebug:msg: "Something is wrong!"
运行结果如下:
➜ temp ansible-playbook testBlock2.ymlPLAY [testBlock2] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
ok: [192.168.1.55] => {"msg": "Hello Zhang San"
}TASK [Part2] ***************************************************************************************
fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001726", "end": "2023-10-26 09:00:01.785445", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 09:00:01.783719", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}TASK [Rescue tasks] ********************************************************************************
ok: [192.168.1.55] => {"msg": "Something is wrong!"
}TASK [Always do this] ******************************************************************************
ok: [192.168.1.55] => {"msg": "End End End"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
注意,always是在rescue之后运行的(Part3仍然不会运行)。
注:如果task没有出错, rescue
不会被触发。
rescue与handler
我们知道,当task运行成功,状态改变时,可以用 notify
来触发handler。但如果后续的task出错了,则当前task的handler并不会触发。如果有 rescue
,则handler仍然会被触发(在 always
之后)。在 rescue
中可以通过 meta: flush_handlers
来立即触发handler(在 always
之前)。
---
- name: testBlock2hosts: alltasks:- name: My task 1block:- name: Part1debug:msg: "Hello Zhang San"changed_when: truenotify: Run me even after an error- name: Part2command: /bin/false # will trigger an error- name: Part3debug:msg: "Hello Li Si"always:- name: Always do thisdebug:msg: "End End End"rescue:- name: Rescue tasks#debug:# msg: "Something is wrong!"meta: flush_handlershandlers:- name: Run me even after an errordebug:msg: 'This handler runs even on error'
运行结果如下:
➜ temp ansible-playbook testBlock2.ymlPLAY [testBlock2] **********************************************************************************TASK [Gathering Facts] *****************************************************************************
ok: [192.168.1.55]TASK [Part1] ***************************************************************************************
changed: [192.168.1.55] => {"msg": "Hello Zhang San"
}TASK [Part2] ***************************************************************************************
fatal: [192.168.1.55]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.002172", "end": "2023-10-26 09:11:26.530609", "msg": "non-zero return code", "rc": 1, "start": "2023-10-26 09:11:26.528437", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}RUNNING HANDLER [Run me even after an error] *******************************************************
ok: [192.168.1.55] => {"msg": "This handler runs even on error"
}TASK [Always do this] ******************************************************************************
ok: [192.168.1.55] => {"msg": "End End End"
}PLAY RECAP *****************************************************************************************
192.168.1.55 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
本例中,Part1运行成功,且改变了状态,所以触发了handler Run me even after an error
。但由于Part2出错,如果没有 rescue
,则Part1的handler不会触发。加上 rescue
之后,就会触发Part1的handler。本例中加上了 meta: flush_handlers
,所以会立即触发handler。
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html