Ansible处理任务失败要这样来学才牢固
本章节介绍如何在ansilbe中处理任务失败的情况,分不同情形进行讲述。
文章目录
- Ansible处理任务失败要这样来学才牢固
- 1. 管理play中任务错误
- 2. 忽略任务失败
- 3. 任务失败也强制执行处理程序(handlers)
- 4. 指定任务失败的条件
- 方法一: 使用failed_when关键字
- 方法二:使用fail模块进行报错条件
- 5. 指定任务何时报告“changed”结果
- 演示一:
- 演示二:
- 6. Ansible块(block)和错误处理
- 总结
1. 管理play中任务错误
Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务,但有些时候,可能希望即使在任务失败时也继续执行play。
2. 忽略任务失败
默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。
[student@servera example]$ vim ignore_errors.yml
---
- name: test
hosts: servera
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum:
name: packages # 没有这个包
state: present
ignore_errors: yes # 可选{yes、no}
- name: show some massage
debug:
msg: "hello word"
[student@servera example]$ ansible-playbook ignore_errors.yml
PLAY [test] ****************************************************************************
TASK [install httpd] *******************************************************************
fatal: [servera]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "No package matching 'packages' found available, installed or updated", "rc": 126, "results": ["No package matching 'packages' found available, installed or updated"]}
...ignoring
TASK [show some massage] ***************************************************************
ok: [servera] => {
"msg": "hello word"
}
PLAY RECAP *****************************************************************************
servera: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
观察执行可发现跳过了报告错误的任务。
3. 任务失败也强制执行处理程序(handlers)
通常任务失败,playbook 会终止,那么收到 play 中之前任务通知的处理程序将不会运行,如果要运行,需要在剧本中使用关键字:force_handlers:yes
[student@servera example]$ cat force_handlers.yml
---
- name: test
hosts: servera
remote_user: root
force_handlers: yes # 强制执行handlers
tasks:
- name: show the msg
debug:
msg: "test the force_handlers"
notify:
- xxx
changed_when: yes
- name: error task
command: ls /abc
handlers:
- name: xxx
debug:
msg: "the task is failed,but also print the msg."
[student@servera example]$ ansible-playbook force_handlers.yml
PLAY [test] ****************************************************************************
TASK [Gathering Facts] *****************************************************************
ok: [servera]
TASK [show the msg] ********************************************************************
changed: [servera] => {
"msg": "test the force_handlers"
}
TASK [error task] **********************************************************************
fatal: [servera]: FAILED! => {"changed": true, "cmd": ["ls", "/abc"], "delta": "0:00:00.007170", "end": "2021-12-16 12:20:06.136278", "msg": "non-zero return code", "rc": 2, "start": "2021-12-16 12:20:06.129108", "stderr": "ls: cannot access /abc: No such file or directory", "stderr_lines": ["ls: cannot access /abc: No such file or directory"], "stdout": "", "stdout_lines": []}
RUNNING HANDLER [xxx] ******************************************************************
ok: [servera] => {
"msg": "the task is failed,but also print the msg."
}
PLAY RECAP *****************************************************************************
servera : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
因为处理程序会在任务报告changed结果时获得通知,而在任务报告ok或failed结果时不会获得通知。
除了可在剧本中指定强制执行外,还可以在命令行中使用 –force-handlers 选项参数,例如上述例子中,在后面加上对应的选项即可:ansible-playbook force_handlers.yml --force-handlers
还可在配置文件中添加对应配置:force_handlers = True
4. 指定任务失败的条件
方法一: 使用failed_when关键字
在任务中使用failed_when关键字来指定表示任务已失败的条件;通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败
# cat test.sh
#!/bin/bash
cat /root # 这句肯定会出错
echo "hello word"
# 注意:在playbook中执行脚本会以最后一个命令作为错误判断标准,中间错误命令不会影响整体的出错,同样也不会因为中间出错而报错
# cat playbook.yaml
---
- name: test conditions
hosts: servera
remote_user: root
tasks:
- name: test
script:
test.sh
register: result
failed_when: "'Is a directory' in result['stdout']" # 加上报错的条件
[student@servera ~]$ ansible-playbook -i hosts playbook.yml
PLAY [test conditions] ******************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [servera]
TASK [test] *****************************************************************************
fatal: [servera]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to servera closed.\r\n", "stderr_lines": ["Shared connection to servera closed."], "stdout": "cat: /root: Is a directory\r\nhello word\r\n", "stdout_lines": ["cat: /root: Is a directory", "hello word"]}
to retry, use: --limit @/home/student/playbook.retry
PLAY RECAP ******************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=1
方法二:使用fail模块进行报错条件
fail模块也可用于强制任务失败(主要是将杂乱的提示信息通过自己设置提示方式,达到简单、明了的目的)
---
- name: test conditions
hosts: servera
remote_user: root
tasks:
- name: test
script:
test.sh
register: result
- name: fail modules
fail:
msg: "There have a failed"
when: "'Is a directory' in result['stdout']"
[student@servera ~]$ ansible-playbook -i hosts playbook.yml
PLAY [test conditions] ****************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [servera]
TASK [test] ***************************************************************************
changed: [servera]
TASK [fail modules] *******************************************************************
fatal: [servera]: FAILED! => {"changed": false, "msg": "There have a failed"}
to retry, use: --limit @/home/student/playbook.retry
PLAY RECAP ****************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=1
5. 指定任务何时报告“changed”结果
当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。
changed_when关键字可用于控制任务在何时报告它已进行了更改。
演示一:
---
- name: test conditions
hosts: servera
tasks:
- name: test
shell: echo "hello word"
changed_when: false #可选{true、false}
True,无论是否成功执行,报告返回结果都为changed。如果为False,在task没有错误的情况下,始终返回ok。
演示二:
---
- name: test conditions
hosts: servera
tasks:
- name: test
command: echo "hello word"
register: result
changed_when: "'hello word' in result.stdout"
# changed_when: "'hello word' not in result.stdout"
# 因为在result[‘stdout’]中有hello word ,所以被认定为是true,所以就显示changed;如果是不在,即为false,就会显示OK。
6. Ansible块(block)和错误处理
在playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式。也可结合rescue和always语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障才运行)运行之后,always子句中的任务才运行。
- block:定义要运行的主要任务
- rescue:定义要在block子句中定义的任务失败时运行的任务
- always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败
[student@servera example]$ cat block.yml
---
- name: test block
hosts: servera
vars:
file_name: test
tasks:
- name: test block
block:
- name: block1
command: ls /tmp
- name: block2
command: "ls /tmp/{{ file_name }}" # 若文件不存在,执行rescue
rescue:
- name: "touch the {{ file_name }}" # 创建此文件
file:
name: "/tmp/{{ file_name }}"
state: touch
always: # 无论block成功与否,都执行always
- name: print
command: echo "\(@^0^@)/"
register: result
- debug:
msg: "{{ result.stdout }}"
block中的when条件也会应用到其rescue和always子句(若存在)
[student@servera example]$ ansible-playbook block.yml
PLAY [test block] *********************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [servera]
TASK [block1] **************************************************************************
changed: [servera]
TASK [block2] **************************************************************************
fatal: [servera]: FAILED! => {"changed": true, "cmd": ["ls", "/tmp/test"], "delta": "0:00:00.008167", "end": "2021-12-16 14:48:40.867397", "msg": "non-zero return code", "rc": 2, "start": "2021-12-16 14:48:40.859230", "stderr": "ls: cannot access /tmp/test: No such file or directory", "stderr_lines": ["ls: cannot access /tmp/test: No such file or directory"], "stdout": "", "stdout_lines": []}
TASK [touch the test] ******************************************************************
changed: [servera]
TASK [print] ***************************************************************************
changed: [servera]
TASK [debug] ***************************************************************************
ok: [servera] => {
"msg": "\(@^0^@)/"
}
PLAY RECAP *****************************************************************************
servera: ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
总结
- 介绍如何忽略任务失败而继续进行任务。
- 使用相关设置让任务失败也强制执行处理程序。
- 可指定任务失败的条件。
- 可指定任务何时报告“changed”结果。
- 介绍了如何使用块(block)来进行错误处理。