ansible条件判断与错误处理

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

我们知道,在执行playbook时,如果playbook中的任何一个任务执行失败,playbook都会停止运行,除非这个任务设置了”ignore_errors: true”,在任务没有设置”ignore_errors: yes”的情况下,任务执行失败后,playbook就会自动终止,而fail模块天生就是一个用来”执行失败”的模块,当fail模块执行后,playbook就会认为有任务失败了,从而终止运行,实现我们想要的中断效果,fail模块默认的输出信息为’Failed as requested from task’,我们可以通过fail模块的msg参数自定义报错的信息,示例如下:

[root@localhost ~]# cat 1.yml
---
- hosts: test70
  remote_user: root
  tasks:
  - debug:
      msg: "1"
  - debug:
      msg: "2"
  - fail:
      msg: "Interrupt running playbook"
  - debug:
      msg: "3"
  - debug:
      msg: "4"
[root@localhost ~]# ansible-playbook -i test_hosts 1.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [debug] ****************************************************************************************************************************************************************************************************
ok: [test70] => {
    "msg": "1"
}

TASK [debug] ****************************************************************************************************************************************************************************************************
ok: [test70] => {
    "msg": "2"
}

TASK [fail] *****************************************************************************************************************************************************************************************************
fatal: [test70]: FAILED! => {"changed": false, "msg": "Interrupt running playbook"}

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=3    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

下例中,我们使用shell模块故意输出了一个包含’error’字符串的文本,并且将shell模块执行后的返回值注册到了变量’ return_value’中,在之后调用了fail模块,并对fail模块添加了判断条件,对应的条件为 “‘error’ in return_value.stdout”,这个条件表示shell模块执行后的标注输出信息中如果包含’error’字符串,则条件成立,其中,’in’关键字的用法与python中’in’的用法相同,可以使用’in’关键字判断一个字符串是否存在于另一个字符串中,也可以用于判断一个特定的值是否存在于列表中,由于shell标准输出的信息中的确包含error字符串,所以fail模块对应的条件成立,最终调用fail模块,playbook终止运行。不过需要注意的是,当使用”in”或者”not in”进行条件判断时,整个条件需要用引号引起,并且,需要判断的字符串也需要使用引号引起,所以,使用’in’或者’not in’进行条件判断时,如下两种语法是正确的:

when: ' "successful" not in return_value.stdout '
when: " 'successful' not in return_value.stdout "
[root@localhost ~]# cat 2.yml
---
- hosts: test70
  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"
[root@localhost ~]# ansible-playbook -i test_hosts 2.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [shell] ****************************************************************************************************************************************************************************************************
changed: [test70]

TASK [fail] *****************************************************************************************************************************************************************************************************
fatal: [test70]: FAILED! => {"changed": false, "msg": "Conditions established,Interrupt running playbook"}

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

另一种方法,借助’failed_when’关键字来完成类似功能,’failed_when’的作用就是,当对应的条件成立时,将对应任务的执行状态设置为失败

[root@localhost ~]# cat 3.yml
---
- hosts: test70
  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"
[root@localhost ~]# ansible-playbook -i test_hosts 3.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [debug] ****************************************************************************************************************************************************************************************************
ok: [test70] => {
    "msg": "I execute normally"
}

TASK [shell] ****************************************************************************************************************************************************************************************************
fatal: [test70]: FAILED! => {"changed": true, "cmd": "echo 'This is a string for testing error'", "delta": "0:00:00.002354", "end": "2023-05-05 16:41:47.355355", "failed_when_result": true, "rc": 0, "start": "2023-05-05 16:41:47.353001", "stderr": "", "stderr_lines": [], "stdout": "This is a string for testing error", "stdout_lines": ["This is a string for testing error"]}

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

上例中,一共有三个任务,第一个任务通过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模块并不会被执行。

需要注意的时,’ failed_when’虽然会将任务的执行状态设置为失败,但是并不代表任务真的失败了,就以上例来说,上例的shell模块的确是完全正常的执行了,只不过在执行之后,’ failed_when’对应的条件成立了,’ failed_when’将shell模块的执行状态设置为失败而已,所以,’ failed_when’并不会影响shell模块的执行过程,只会在条件成立时影响shell模块最终的执行状态,以便停止playbook的运行。

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

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

[root@localhost ~]# cat 4.yml
---
- hosts: test70
  remote_user: root
  tasks:
  - debug:
      msg: "test message"
    #changed_when: 2 > 1
[root@localhost ~]# ansible-playbook -i test_hosts 4.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [debug] ****************************************************************************************************************************************************************************************************
ok: [test70] => {
    "msg": "test message"
}

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@localhost ~]# vim 4.yml
[root@localhost ~]# ansible-playbook -i test_hosts 4.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [debug] ****************************************************************************************************************************************************************************************************
changed: [test70] => {
    "msg": "test message"
}

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


debug模块在正常执行的情况下只能是”ok”状态,上例中,我们使用’changed_when’关键字将debug模块的执行后的状态定义为了”changed”

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

---
- hosts: test70
  remote_user: root
  tasks:
  - shell: "ls /opt"
    changed_when: false

当将’changed_when’直接设置为false时,对应任务的状态将不会被设置为’changed’,如果任务原本的执行状态为’changed’,最终则会被设置为’ok’,所以,上例playbook执行后,shell模块的执行状态最终为’ok’

[root@localhost ~]# cat 5.yml
---
- hosts: test70
  remote_user: root
  tasks:
  - shell: "ls /opt"
    #changed_when: false
[root@localhost ~]# ansible-playbook -i test_hosts 5.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [shell] ****************************************************************************************************************************************************************************************************
changed: [test70]

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[root@localhost ~]# vim 5.yml
[root@localhost ~]# ansible-playbook -i test_hosts 5.yml

PLAY [test70] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [test70]

TASK [shell] ****************************************************************************************************************************************************************************************************
ok: [test70]

PLAY RECAP ******************************************************************************************************************************************************************************************************
test70                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


参考链接:https://www.zsythink.net/archives/2846

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. playbook基本语法 Ansible的playbook文件格式为YAML语法,所以对于编写剧本的初学者,...
    阿丧小威阅读 3,860评论 0 0
  • 简介 架构 原理 组成 ANSIBLE PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置...
    毛利卷卷发阅读 4,731评论 0 2
  • When语句有时候用户有可能需要某一个主机越过某一个特定的步骤.这个过程就可以简单的像在某一个特定版本的系统上少装...
    GoGooGooo阅读 14,583评论 0 0
  • 获取执行命令的输出 --Register 在刚开始使用 ansible-playbook 做应用程序部署的时候,因...
    GoGooGooo阅读 10,043评论 1 3
  • 3.1 Ansible 的配置 3.1.1 可以配置什么 安装好Ansible后,通过 /etc/ansible/...
    super_pcm阅读 3,237评论 0 0