Ansible核心技巧:循环条件与错误处理
一、 循环 (Loops)
目的: 避免代码重复,高效地对一组值进行迭代操作。
迭代列表: 对简单的字符串列表进行循环。
迭代字典列表: 对更复杂的数据结构进行循环,可以访问每个项的多个属性。
常用循环关键字: loop (现代写法), with_<lookup> (如 with_items, with_dict 等传统写法)。
二、 条件 (Conditionals)
目的: 控制任务或整个Play是否执行,实现逻辑分支。
基本条件语句: 使用 when 关键字。
when: ansible_facts['os_family'] == "Debian"
条件来源:
变量 (when: my_var is defined)
Ansible 事实 (when: ansible_facts['distribution'] == 'CentOS')
之前任务的执行结果 (when: result.stdout == "success")
其他任务的 changed 状态 (when: task_result is changed)
三、 处理程序 (Handlers)
目的: 实现“触发-执行”机制,通常用于服务重启、配置重载等需要幂等性的操作。
特殊任务: 在Play的末尾执行,且只在被通知时执行。
通知机制: 使用 notify 指令。只有当通知它的任务报告了状态变更 (changed) 时,处理程序才会被触发。
关键特性: 幂等性。即使被多个任务通知,也只在Play末尾执行一次。
四、 错误处理 (Error Handling)
目的: 精细控制任务的成功与失败状态,增强Playbook的健壮性。
忽略错误:
ignore_errors: yes # 任务失败不会导致整个Playbook中止。
强制失败/成功:
failed_when: 自定义任务失败的条件(即使命令返回码为0)。
changed_when: 覆盖任务的“已更改”状态。可以强制将其设置为 false 或 true。
块错误处理 (Blocks):
block: 将多个任务逻辑上分组。
rescue: 如果 block 中的任何任务失败,则执行 rescue 块中的任务(类似于 try-catch)。
always: 无论 block 成功还是失败,最后都会执行 always 块中的任务(类似于 finally)。
1.基于“循环”的知识点:
loop 关键字是现代Ansible中迭代列表的首选方法,替代了传统的 with_<lookup> 模式。
可以使用 loop_control 扩展功能来管理循环,例如用 label 项简化输出,或使用 pause 项控制循环迭代间的延迟。
ansible.builtin.debug 模块常在循环开发中用于调试,通过 msg: "Processing {{ item }}" 来显示当前迭代项。
查询 register 变量的 results 子属性可以获取循环中每个任务的执行结果列表。
循环不仅可以遍历静态列表,还可以遍历一个变量,该变量的值来自 set_fact 或 register 另一个任务的结果。
2.基于“条件”的知识点:
when 语句支持使用Jinja2表达式,可以结合 and, or, not 逻辑运算符以及 ==, !=, >, < 比较运算符来构建复杂条件。
常见的条件判断包括检查变量是否已定义 (when: my_var is defined)、是否为真 (when: my_var)、是否在某个列表中 (when: item in list_of_items)。
条件可以基于Ansible事实(facts),实现跨平台兼容的任务,例如 when: ansible_facts['os_family'] == "RedHat"。
条件可以应用于整个 block,从而一次性控制一组任务的执行。
条件可以检查之前任务的 registered 变量,例如根据命令输出的内容决定是否执行:when: "'ERROR' in cmd_result.stdout"。
3.基于“处理程序”的知识点:
处理程序的名字具有全局作用域,如果在多个地方定义了同名处理程序,只有最后一个会被执行。
使用 listen 关键字可以让多个处理程序监听同一个通知主题,从而实现一个通知触发多个处理程序。
可以使用 meta: flush_handlers 任务在play中间强制立即运行所有已被通知的处理程序,而不必等到play结束。
如果某个任务失败了但仍需要触发处理程序(例如在失败后进行清理),可以使用 notify 配合 ignore_errors: yes。
处理程序本身也可以包含 notify,从而链式触发其他处理程序。
4.基于“错误处理”的知识点:
ignore_errors: yes 会使Ansible继续执行后续任务,但整个Play的最终状态仍会被标记为失败。
failed_when 通常与 register 结合使用,通过检查命令的 stdout, stderr 或 rc (return code) 来定义失败条件。
changed_when: false 常用于那些总是报告“已更改”的信息性命令(如 debug 或 command),以保持Playbook的幂等性。
changed_when: true 可用于强制将总是返回“成功”且无变化的脚本或命令标记为“已更改”,从而能正常触发处理程序。
any_errors_fatal 和 max_fail_percentage 是Play级别的指令,用于控制一个主机上的失败如何影响整个批量的执行。
5.基于“块”的知识点:
block 结构必须至少包含一个任务,而 rescue 和 always 部分是可选的。
rescue 块中的任务只有在 block 中有任务失败时才会执行。如果 block 成功,则跳过 rescue。
always 块中的任务无论 block 成功还是失败都会执行,是进行清理操作(如关闭连接、删除临时文件)的理想位置。
block 本身可以包含循环和条件,并且错误处理(rescue)的范围是整个块,而不是单个任务。
可以在 rescue 块中使用 fail_module 来重新抛出错误,或者在处理完错误后让Playbook继续执行。