文章目录
Playbook中的错误处理
摘要
当Ansible从一个命令接收到一个非零的返回码或从一个模块接收到一个故障时,默认情况下它会停止在该主机上执行,并在其他主机上继续执行。
然而,在某些情况下,您可能需要不同的行为。有时,非零返回码表示成功。有时,您希望一台主机上的故障停止所有主机上的执行。Ansible提供了处理这些情况的工具和设置,并帮助您获得所需的行为、输出和报告。
- Ignoring failed commands 忽略命令失败
- Ignoring unreachable host errors 忽略不可达的主机错误
- Resetting unreachable hosts 重新设置不可到达的主机
- Handlers and failure 处理程序和失败
- Defining failure 定义失败
- Defining “changed”定义“改变”
- Ensuring success for command and shell 确保成功的命令和shell
- Aborting a play on all hosts 在所有主机上终止一个play
- Aborting on the first error: any_errors_fatal 在第一个错误时中止:any_errors_fatal
- Setting a maximum failure percentage 设置最大失败百分比
- Controlling errors in blocks 在blocks区块上控制errors
一、 忽略命令失败
默认情况下,当主机上的任务失败时,Ansible会停止执行该主机上的任务。使用ignore_errors
,即使碰到任务失败,仍会继续下面的任务:
- name: Do not count this as a failure
shell: /bin/false
ignore_errors: yes
ignore_errors
指令仅在任务能够运行并返回值为failed
时有效。它不会使Ansible忽略未定义的变量错误、连接失败、执行问题(例如,丢失包)或语法错误。
二、忽略不可达的主机错误
您可以使用ignore_unreachable
关键字忽略由于主机实例为UNREACHABLE
而导致的任务失败。Ansible忽略任务错误,但继续对不可达的主机执行后续的任务。
1)在task中使用:
# task1中忽略不可达的主机继续执行;task2不忽略不可达主机,且该不可达主机终止执行
tasks:
- name: task1
command: /bin/true
ignore_unreachable: yes
- name: task2
command: /bin/true
2)在play中使用:
# 所有tasks忽略不可达的主机,task1:忽略不可达主机继续执行play,tasks2:不忽略不可达主机且该不可达主机终止执行
- hosts: all
ignore_unreachable: yes
tasks:
- name: task1
command: /bin/true
- name: task2
command: /bin/true
ignore_unreachable: no
三、重新设置不可到达的主机
如果Ansible无法连接到某个主机,它会将该主机标记为unreachable
,并将其从运行的活动主机列表中删除。您可以使用meta: clear_host_errors
重新激活所有主机,以便后续任务可以尝试再次访问它们。
四、处理程序和失败
如果一个任务通知了一个handler
,但另一个任务在稍后的运行中失败,默认情况下handler
不会在该主机上运行,这可能会使主机处于意外状态。
例如,一个任务可以更新配置文件并通知handler
重新启动某些服务。如果同一task中稍后的任务失败,则可能只会更改配置文件,而不会重新启动服务。
你可以通过--force-handlers
命令行选项来改变这种行为,方法是在play中包含force_handlers: True
,或者在ansible.cfg
中添加force_handlers = True
。
当handler
被强制执行时,Ansible将在所有主机上运行所有通知的handler
,甚至是任务失败的主机。
(注意,某些错误仍然会阻止处理程序运行,比如主机变得不可访问。)
五、定义失败
Ansible允许你在每个任务中使用failed_when
条件定义“failure
”的含义。
多个failed_when
条件的列表使用隐式的and连接,这意味着任务只有在满足所有条件时才会失败。如果希望在满足任何条件时触发失败,则必须使用显式或操作符在字符串中定义条件。
- 您可以通过在命令的输出中搜索一个单词或短语来检查是否失败:
- name: Fail task when the command error output prints FAILED
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
- 基于返回码:
- name: Fail task when both files are identical
raw: diff foo/file1 bar/file2
register: diff_cmd
failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2
- 还可以组合多个失败条件。如果两个条件都为真,该任务将失败:
# 检查某个文件是否存在
- name: Check if a file exists in temp and fail task if it does
command: ls /tmp/file1
register: result
failed_when:
- result.rc == 0
- '"No such" not in result.stdout'
# 如果你想让任务在只满足任何一个条件时失败,将failed_when的定义修改为:
failed_when: result.rc == 0 or "No such" not in result.stdout
- 如果有太多的条件不能整齐地放在一行中,可以使用“>”将其分割为多行yaml值:
- name: example of many failed_when conditions with OR
shell: "./myBinary"
register: ret
failed_when: >
("No such file or directory" in ret.stdout) or
(ret.stderr != '') or
(ret.rc == 10)
六、定义“改变”
Ansible允许你使用条件changed_when
来定义一个特定的任务何时“changed
”了一个远程节点。这让您可以根据返回代码或输出来决定是否应该在Ansible统计中报告更改,以及是否应该触发处理程序。
与Ansible中的所有条件一样,多个changed_when
条件的列表使用隐式的“and
”连接,这意味着任务只在满足所有条件时报告更改。
- 如果希望在满足任何条件时报告更改,则必须使用显式“
or
“在字符串中定义条件。例如:
tasks:
- name: Report 'changed' when the return code is not equal to 2
shell: /usr/bin/billybass --mode="take me to the river"
register: bass_result
changed_when: "bass_result.rc != 2"
- name: This will never report 'changed' status
shell: wall 'beep'
changed_when: False
- 你也可以组合多个条件来覆盖"
changed
"结果:
- name: Combine multiple conditions to override 'changed' result
command: /bin/fake_command
register: result
ignore_errors: True
changed_when:
-'"ERROR" in result.stderr'
-result.rc == 2
七、 确保命令和shell成功
command
和shell
模块关心返回码,所以如果你有一个成功退出码不为零的命令,你可以这样做:
tasks:
- name: Run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
八、在所有主机上终止一个play
有时,您希望单个主机或一定百分比的主机出现failure
,从而中止所有主机上的整个play。使用any_errors_fatal
可以在第一次失败发生后停止play执行。对于更细粒度的控制,您可以使用max_fail_percentage
在给定百分比的主机失败后中止运行。
- 在第一个错误时中止:
any_errors_fatal
如果你设置了any_errors_fatal
并且一个任务返回了一个错误,Ansible会在当前批处理的所有主机上完成致命任务,然后停止在所有主机上执行剧本。后续的任务和剧本不会被执行。你可以在play或block级别设置any_errors_fatal
:
- hosts: somehosts
any_errors_fatal: true
roles:
-myrole
通过向块中添加一个拯救部分,可以从致命错误中恢复运行。
- hosts: somehosts
tasks:
- block:
-include_tasks: mytasks.yml
any_errors_fatal: true
当所有任务必须100%成功才能继续执行剧本时,您可以使用此特性。例如,如果您在多个数据中心的机器上运行一个服务,使用负载平衡器将流量从用户传递到服务,那么您希望在停止服务进行维护之前禁用所有负载平衡器。为了确保任务中任何禁用负载均衡器的失败都会停止所有其他任务:
---
- hosts: load_balancers_dc_a
any_errors_fatal: true
tasks:
- name: Shut down datacenter 'A'
command: /usr/bin/disable-dc
- hosts: frontends_dc_a
tasks:
- name: Stop service
command: /usr/bin/stop-software
- name: Update software
command: /usr/bin/upgrade-software
- hosts: load_balancers_dc_a
tasks:
- name: Start datacenter 'A'
command: /usr/bin/enable-dc
在这个例子中,只有当所有的负载均衡器都被成功禁用时,Ansible才会在前端启动软件升级。
- 设置最大失败百分比:
max_fail_percentage
默认情况下,只要有主机没有发生故障,Ansible就会继续执行任务。在某些情况下,例如在执行滚动更新时,当达到一定的失败阈值时,您可能想要中止play。为了实现这一点,你可以设置play的最大失败百分比:
---
- hosts: webservers
max_fail_percentage: 30
serial: 10
max_fail_percentage
设置在与serial
一起使用时适用于每个批处理。在上面的例子中,如果第一批(或任何一批)服务器中的10个服务器中有3个以上失败,那么剩下的play将被中止。
九、在block上处理错误
此处详细信息可参阅《 block》。