![如果可执行文件不存在,Ansible 任务如何失败?](https://linux22.com/image/793506/%E5%A6%82%E6%9E%9C%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8CAnsible%20%E4%BB%BB%E5%8A%A1%E5%A6%82%E4%BD%95%E5%A4%B1%E8%B4%A5%EF%BC%9F.png)
我的 Ansible 剧本的一部分是 K3S 集群创建。
对于服务器节点我有以下任务:
<...>
- name: Retrieve K3S installation status
command: which k3s
changed_when: false
failed_when: false
register: k3s_installed
- name: Install K3S unless already installed
ansible.builtin.shell: |
curl -sfL https://get.k3s.io | sh -
async: 300
poll: 5
retries: 3
when: k3s_installed.rc not in [0]
<...>
第一个任务检查主机上是否已安装 K3S,并将结果捕获到变量中。如果命令缺失,k3s_installed
则第二个任务安装 K3S 。k3s
我想更进一步,更新第二个任务,检查k3s
安装后的可执行文件是否存在。如果不存在,它应该会失败并重试(我已经尝试过了retries: 3
)。类似这样的:
failed_when: <condition that checks if k3s executable still not exists>
我发现的所有 Ansible 示例都有failed_when
基于当前任务执行结果(如任务输出或退出代码)的条件。实现此检查的正确方法是什么?
答案1
问:更新第二个任务,检查安装后的 k3s 可执行文件是否存在。
答:创建一个检查所需内容的脚本,然后使用模块脚本代替壳. 使用参数使此任务幂等创建。 例如,
- script:
cmd: "{{ playbook_dir }}/bin/install_k3s.sh"
creates: /usr/local/bin/k3s
(未经测试)
使用异步如果脚本耗时过长。请参见ansible:将循环(until)与条件(when)结合起来关于如何记录结果、测试结果并重复脚本直到满足条件。
您可以使用模块执行相同操作壳. 模块的优势脚本测试的简单性。您可以先在远程主机上轻松测试独立脚本。当脚本按您的要求执行时,使用模块脚本。
答案2
好的 Ansible 任务会让其参数所要求的事情发生,或者失败。也许你会用额外的任务来补充各种事情,但要让任务不做的事情显而易见。快速失败是件好事。
在这种情况下,安装 k3s 软件。通常我会建议使用包管理器。标准化软件档案的安装、升级、审核和回滚方式。Ansible 包模块可以为各种包管理器执行此操作,如果包不存在,则安装该包,如果无法完成,则出错。
不幸的是,这个脚本不是一个合适的软件包。我不喜欢软件安装脚本。它不受软件包管理器的跟踪。有时会从互联网上下载随机脚本和二进制文件。不符合我首选发行版的惯例。并且在错误情况下或再次运行时它们的行为不可靠。
无论如何,您无法真正将“文件存在于远程主机上”任务添加到运行某些任意脚本的任务中。 Ansible 在每个任务中运行一个执行实际工作的低级脚本。 shell 模块仅具有要工作的脚本的返回代码(如果您编写了一个巧妙的 failed_when 表达式,则还有 stdout 或 stderr)。
相反,在安装任务之后执行另一个任务,运行一个简单的 k3s 命令。获取版本或使用文本,或使用它进行一些实际工作,或其他操作。如果它在 $PATH 上不存在,Ansible 将像您预期的那样出错。替换实际不执行任何操作但返回代码为零的选项。
# Install K3S goes here
- name: Check K3S installed
command: k3s
Ansible 没有很好的方法来重试一组任务,例如安装软件后的这些额外检查。此外,我想看看故障模式,以评估重试是否有用。所以现在不要使用until关键字。
相反,你应该集中精力改进脚本,或者将其构建成合适的软件包存档。无论哪种方式,你都可能想要下载并自定义自己的构建,而不是从互联网上下载。只需打包维护者的东西。