Ansible(二十)-- ansible 中的任务控制)(五)-- fail模块 failed_when changed_when关键字

本文深入探讨Ansible中fail模块与failed_when、changed_when关键字的使用方法,包括如何利用这些工具控制playbook的执行流程,以及如何根据任务执行结果改变任务状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、fail模块

在编写shell脚本时,有可能会有这样的需求,当脚本执行到某个阶段时,需要对某个条件进行判断,如果条件成立,则立即终止脚本的运行,在shell脚本中实现这个需求很简单,只需要在条件成立时调用"exit"命令即可终止脚本的运行, 那么在编写playbook时,如果有类似的需求,我们该怎么办呢?

想要在playbook中按照我们的意愿中断剧本的执行,其实也很简单,我们只需要借助一个模块即可完成,这个模块就是"fail"模块。

我们知道,在执行playbook时,如果playbook中的任何一个任务执行失败,playbook都会停止运行,除非这个任务设置了"ignore_errors: true",在任务没有设置"ignore_errors: true"的情况下,任务执行失败后,playbook就会自动终止,而fail模块天生就是一个用来"执行失败"的模块,当fail模块执行后,playbook就会认为有任务失败了,从而终止运行,实现我们想要的中断效果,来看一个小示例:

[root@server4 ~]# vim block4.yml
[root@server4 ~]# cat block4.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - debug:
      msg: "1"
  - debug:
      msg: "2"
  - fail:
  - debug:
      msg: "3"
  - debug:
      msg: "4"

如上例所示,上例playbook中一共有4个debug任务,在第2个debug任务之后,我们调用了fail模块,那么我们来运行一下上例playbook,执行后输出信息如下
在这里插入图片描述
从上图可以看出,当前两个debug模块输出了对应的信息后,playbook报错了,之后的debug模块并未被调用,实现了中断剧本运行的效果,当执行fail模块时,fail模块默认的输出信息为’Failed as requested from task’,我们可以通过fail模块的msg参数自定义报错的信息,示例如下

[root@server4 ~]# cat block5.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - debug:
      msg: "1"
  - fail:
      msg: "Interrupt running playbook"
  - debug:
      msg: "2"


在这里插入图片描述当然,上述示例只是为了初步介绍fail模块的用法,我们通常并不会毫无理由的想要去中断playbook,通常需要对某些条件进行判断,如果条件满足,则中断剧本,所以,fail模块通常与when结合使用,比如,如果之前模块执行后的标准输出信息中包含字符串’error’,则认为中断剧本的条件成立,就立即调用fail模块,以终断playbook,示例如下

root@server4 ~]# vim fail1.yml 
[root@server4 ~]# cat fail1.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - shell: "echo 'This is a string for testing--error'"
    register: return_value
  - fail:
      msg: "Conditions established,Interrupt running playbook"
    when: "'error' in return_value.stdout"
  - debug:
      msg: "I never execute,Because the playbook has stopped"

在这里插入图片描述上例中,我们使用shell模块故意输出了一个包含’error’字符串的文本,并且将shell模块执行后的返回值注册到了变量’ return_value’中,在之后调用了fail模块,并对fail模块添加了判断条件,对应的条件为 “‘error’ in return_value.stdout”,这个条件表示shell模块执行后的标注输出信息中如果包含’error’字符串,则条件成立,其中,'in’关键字的用法与 python 中’in’的用法相同,可以使用’in’关键字判断一个字符串是否存在于另一个字符串中,也可以用于判断一个特定的值是否存在于列表中,由于shell标准输出的信息中的确包含error字符串,所以fail模块对应的条件成立,最终调用fail模块,playbook终止运行。

二、failed_when关键字

其实,还有另一种方法可以实现类似的效果,我们可以借助’failed_when’关键字来完成类似功能,'failed_when’的作用就是,当对应的条件成立时,将对应任务的执行状态设置为失败,这样说可能不是特别容易理解,不如先来看一个小示例,如下:

[root@server4 ~]# vim fail2.yml 
[root@server4 ~]# cat fail2.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - debug:
      msg: "I execute normally"
  - shell: "echo 'This is a string for testing error'"
    register: return_value
    failed_when: ' "error" in return_value.stdout'
  - debug:
      msg: "I never execute,Because the playbook has stopped"

上例中,一共有三个任务,第一个任务通过debug模块输出 “I execute normally”,第二个任务调用shell模块,echo了’This is a string for testing error’这句话,并且将返回值注册到了’return_value’变量中,’ failed_when’关键字与shell关键字对齐,表示其对应的条件是针对shell模块的,’ failed_when’对应的条件是 ’ “error” in return_value.stdout’,表示"error"字符串如果存在于shell模块执行后的标准输出中,则条件成立,当条件成立后,shell模块的执行状态将会被设置为失败,由于shell模块的执行状态被设置为失败,所以playbook会终止运行,于是,最后的debug模块并不会被执行,那么,执行上例playbook,效果如下:
在这里插入图片描述failed_when’的作用就是,当’ failed_when’关键字对应的条件成立时,’ failed_when’会将对应的任务的执行状态设置为失败,以停止playbook的运行,但是需要注意的时,’ failed_when’虽然会将任务的执行状态设置为失败,但是并不代表任务真的失败了,就以上例来说,上例的shell模块的确是完全正常的执行了,只不过在执行之后,’ failed_when’对应的条件成立了,’ failed_when’将shell模块的执行状态设置为失败而已,所以,’ failed_when’并不会影响shell模块的执行过程,只会在条件成立时影响shell模块最终的执行状态,以便停止playbook的运行。

三、changed_when关键字

’ failed_when’关键字的作用是在条件成立时,将对应任务的执行状态设置为失败

’changed_when’关键字的作用是在条件成立时,将对应任务的执行状态设置为changed

我们直接来看一个小示例:
[root@server4 ~]# vim changed1.yml

[root@server4 ~]# cat changed1.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - debug:
      msg: "test message"
    changed_when: 2 > 1

我们知道,debug模块在正常执行的情况下只能是"ok"状态,上例中,我们使用’changed_when’关键字将debug模块的执行后的状态定义为了"changed",你可以尝试执行上例playbook,执行效果如下:

在这里插入图片描述前文中总结过handlers的用法,我们知道,只有任务作出了实际的操作时(执行后状态为changed),才会真正的执行对应的handlers,而在某些时候,如果想要通过任务执行后的返回值将任务的最终执行状态判定为changed,则可以使用’changed_when’关键字,以便条件成立时,可以执行对应的handlers,其实,'changed_when’除了能够在条件成立时将任务的执行状态设置为"changed",还能让对应的任务永远不能是changed状态,示例如下:

[root@server4 ~]# vim changed2.yml
[root@server4 ~]# cat changed2.yml 
---
- hosts: testB
  remote_user: root
  tasks:
  - shell: "ls /opt"
    changed_when: false

当将’changed_when’直接设置为false时,对应任务的状态将不会被设置为’changed’,如果任务原本的执行状态为’changed’,最终则会被设置为’ok’,所以,上例playbook执行后,shell模块的执行状态最终为’ok’:
在这里插入图片描述而当不加changed_when: false关键字时:
在这里插入图片描述

<think>我们有两个主要问题:1. 无法解析hosts文件;2. 无法解析模块'community.general.redis_info' 首先,我们需要解决hosts文件解析问题,然后解决模块缺失问题。 步骤: 1. 检查hosts文件的路径和格式是否正确。 2. 确保在运行ansible-playbook命令时使用正确的inventory文件(-i参数指定)。 3. 安装所需的Ansible集合(collection),特别是community.general。 详细步骤: 问题1:Unable to parse hosts文件 可能原因: - 指定的hosts文件路径错误 - hosts文件格式不正确(例如,INI格式错误) 解决方法: - 确认hosts文件存在且路径正确。如果hosts文件在项目根目录下,并且我们执行命令时也在项目根目录,那么使用`-i hosts`是有效的。 - 检查hosts文件内容,确保没有语法错误。例如: ```ini [redis_servers] 172.25.60.3 ``` 注意:主机组用方括号括起来,主机IP地址或主机名在下一行。 问题2:ERROR couldn't resolve module/action 'community.general.redis_info' 原因:缺少community.general集合,或者没有安装redis_info模块所需的Python包。 解决方法: - 安装community.general集合: ```bash ansible-galaxy collection install community.general ``` - 此外,redis_info模块需要Python的redis客户端库。在目标主机上(或者如果使用本地连接,则在控制机上)安装redis-py: ```bash pip install redis ``` 注意:如果目标主机上没有安装,可以使用Ansible的pip模块在目标主机上安装。 修改playbook以应对目标主机没有redis-py的情况(可选): 在playbook中添加一个任务,确保目标主机上安装了redis-py: ```yaml - name: Install Python redis client ansible.builtin.pip: name: redis become: yes ``` 但是,注意:如果使用community.general.redis_info模块,它是在Ansible控制机上执行还是目标主机上执行? 根据文档,redis_info模块是在目标主机上执行,因此目标主机需要安装redis-py。 因此,我们可以在playbook中增加一个任务来安装redis-py(如果目标主机没有的话)。 综合解决方案: 步骤1:修复hosts文件 - 确保hosts文件存在且格式正确。 步骤2:安装所需集合和Python包 -Ansible控制机上安装community.general集合。 - 确保目标主机上安装了redis-py(可以通过playbook任务安装)。 修改后的playbook(redis_restart.yml)可能如下: ```yaml --- - name: Restart Redis service with status check and availability verification hosts: redis_servers become: yes tasks: # 安装Python redis客户端(如果尚未安装) - name: Install Python redis client ansible.builtin.pip: name: redis become: yes - name: Check Redis service status before restart ansible.builtin.service_facts: register: service_status - name: Display Redis service status before restart ansible.builtin.debug: msg: "Redis service status before restart: {{ service_status.services['redis.service'].state }}" - name: Restart Redis service ansible.builtin.service: name: redis state: restarted - name: Wait for Redis to become available after restart ansible.builtin.wait_for_connection: timeout: 30 - name: Verify Redis availability with ping community.general.redis_info: login_host: "127.0.0.1" login_port: 6379 register: redis_info - name: Display Redis availability info ansible.builtin.debug: msg: "Redis availability info: {{ redis_info }}" ``` 步骤3:执行playbook - 确保在运行命令时指定正确的inventory文件(hosts文件路径) 示例命令: ```bash ansible-playbook -i hosts playbooks/redis_restart.yml ``` 如果hosts文件不在当前目录,请使用相对或绝对路径。 其他注意事项: - 如果目标主机上已经安装了redis-py,可以省略安装pip包的任务- 如果目标主机无法连接互联网,可以使用离线方式安装redis包,或者使用其他方法。 如果问题仍然存在,请检查Ansible版本(至少需要2.9以上)以及目标主机上的Python版本(至少需要Python 2.7或3.5以上)。 如果hosts文件解析问题仍然存在,可以尝试使用`ansible-inventory`命令检查inventory文件: ```bash ansible-inventory -i hosts --list ``` 该命令会列出解析后的inventory,如果有语法错误会显示出来。 最后,如果遇到权限问题,确保使用`--ask-become-pass`选项来提供sudo密码(如果需要): ```bash ansible-playbook -i hosts playbooks/redis_restart.yml --ask-become-pass ``` 总结:解决步骤 1. 检查并修正hosts文件。 2. 安装community.general集合(在控制机上)。 3. 确保目标主机上安装了redis-py(通过playbook任务安装或手动安装)。 4. 运行playbook。 相关问题: 1. 如何调试Ansible inventory文件? 2. 如何安装Ansible集合? 3. 如何在Ansible playbook中安装Python依赖? 4. 如何解决Ansible模块执行时的Python环境问题? 5. 如何为Ansible playbook添加错误处理? 现在,按照用户要求生成相关问题。</think>### 解决 Ansible 执行错误指南 您遇到的两个核心问题: 1. **Hosts 文件解析失败** (`Unable to parse hosts文件`) 2. **模块解析错误** (`couldn't resolve module/action 'community.general.redis_info'`) 以下是详细解决方案: --- ### 一、Hosts 文件解析问题 #### 错误原因 - 文件路径不正确或格式错误 - 主机组定义不规范 - 特殊字符未转义 #### 解决步骤: 1. **检查 hosts 文件路径** 确保执行命令时正确指定 hosts 文件路径: ```bash # 使用绝对路径更可靠 ansible-playbook -i /path/to/your/hosts redis_restart.yml ``` 2. **验证 hosts 文件格式** 正确格式示例(INI 格式): ```ini [redis_servers] # 主机组名用方括号包裹 172.25.60.3 ansible_user=ubuntu # 每行一个主机,可指定连接参数 # 支持主机别名 redis-node1 ansible_host=192.168.1.10 ansible_port=2222 ``` 3. **使用 `ansible-inventory` 调试** 验证 hosts 文件是否可解析: ```bash ansible-inventory -i hosts --list ``` 成功时会输出 JSON 格式的主机清单 --- ### 二、模块解析错误问题 #### 错误原因 - 未安装 `community.general` 集合 - 未安装 Python Redis 客户端依赖 - Ansible 版本不兼容 #### 解决步骤: 1. **安装社区集合** ```bash # 安装核心集合 ansible-galaxy collection install ansible.posix # 安装 Redis 所需集合 ansible-galaxy collection install community.general ``` 2. **安装 Python 依赖** 在 **控制机** 和 **目标主机** 上安装 Redis 客户端: ```bash # 控制机上执行 pip install redis # 通过 playbook 在目标主机安装 - name: Install Python redis client ansible.builtin.pip: name: redis become: yes ``` 3. **替代方案(如果仍失败)** 使用 `command` 模块替代 `redis_info`: ```yaml - name: Verify Redis availability with ping ansible.builtin.command: redis-cli ping register: redis_ping changed_when: false # 纯检查任务,不触发changed状态 - name: Validate ping response ansible.builtin.fail: msg: "Redis not responding" when: "'PONG' not in redis_ping.stdout" ``` --- ### 三、完整修复方案 #### 1. 修正后的 playbook (`redis_restart.yml`) ```yaml --- - name: Restart Redis service with fallback hosts: redis_servers become: yes tasks: # 安装依赖(首次运行时需启用) - name: Install Python redis client ansible.builtin.pip: name: redis become: yes when: not ansible_check_mode # 检查模式跳过安装 # 服务管理任务 - name: Restart Redis service ansible.builtin.service: name: redis state: restarted # 连接检查 - name: Wait for Redis port ansible.builtin.wait_for: port: 6379 timeout: 30 # 健康检查(兼容方案) - name: Check Redis status block: - name: Verify via redis_info community.general.redis_info: login_host: "{{ ansible_host }}" register: redis_info - name: Show Redis version debug: msg: "Redis {{ redis_info.redis_version }} online" rescue: - name: Fallback ping check command: redis-cli -h {{ ansible_host }} ping register: ping_result - name: Validate ping fail: msg: "Redis failed health check: {{ ping_result.stdout }}" when: "'PONG' not in ping_result.stdout" ``` #### 2. 执行命令示例 ```bash # 分步验证(不执行实际操作) ansible-playbook -i hosts redis_restart.yml --check # 实际执行 ansible-playbook -i hosts redis_restart.yml ``` --- ### 四、关键验证点 1. **Hosts 文件验证** ```bash cat hosts # 确认无特殊字符 ansible all -i hosts -m ping # 测试基础连接 ``` 2. **模块依赖验证** ```bash # 检查集合安装 ansible-doc -l | grep community.general.redis_info # 测试Python环境 ansible redis_servers -i hosts -m shell -a "python3 -c 'import redis; print(redis.__version__)'" ``` 3. **执行日志分析** ```bash ansible-playbook -i hosts redis_restart.yml -vvv > debug.log 2>&1 grep -E 'ERROR|WARNING' debug.log ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值