ansible 条件判断 循环 handlers 任务失败

目录

条件判断

有条件地运行任务

 条件任务语法

测试多个条件

循环和有条件任务

handlers

 处理任务失败

管理play中的任务错误

忽略任务失败

任务失败后强制执行处理程序

指定任务失败条件

指定何时任务报告“changed”结果当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。


条件判断

有条件地运行任务

Ansible可使用conditionals在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。

我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。

以下场景说明了在Ansible中使用条件的情况:

  • 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
  • Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
  • 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
  • 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
  • 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。

 条件任务语法

when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。

可以测试的一个最简单条件是某一布尔变量是True还是False。以下示例中的when语句导致任务仅在run_my_taskTrue时运行:

[root@ansible opt]# cat test/test.yml 
---
- name:
  hosts: apache  //受控主机为apache
  vars: 
    run_my_task: ture  //设置测试变量值为true
  tasks: 
    - name: 
      yum: 
        name: vim 
      when: run_my_task  //使用when来测试它得值
      

//测试
[root@ansible opt]# ansible-playbook test/test.yml 
[WARNING]: Could not match supplied host pattern, ignoring: apache

PLAY [apache] ************************************************************************
skipping: no hosts matched

PLAY RECAP ***************************************************************************

测试多个条件

一个when语句可用于评估多个条件。使用andor关键字组合条件,并使用括号分组条件。

如果任一条件为真时满足条件语句,则应当使用or语句。例如,如果计算机上运行的是红帽企业linux或Fedora,则下述条件得到满足:

when: ansible_distribution == "Redhat" or ansible_distribution == "Fedora"

使用and运算时,两个条件都必须为真,才能满足整个条件语句。例如,如果远程主机是红帽企业Linux7.5主机,并且安装的内核是指定版本,则将满足以下条件:

when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

when关键字还支持使用列表来描述条件列表。向when关键字提供列表时,将使用and运算组合所有条件。下面的示例演示了使用and运算符组合多个条件语句的另一方式:

when:
  - ansible_distribution_version == "7.5"
  - ansible_kernel == "3.10.0-327.el7.x86_64"

这种格式提高了可读性,而可读性是良好编写Ansible Playbook的关键目标。

通过使用括号分组条件,可以表达更复杂的条件语句。例如,如果计算机上运行的是红帽企业Linux7或Fedora28,则下述条件语句得到满足。此示例使用大于字符,这样长条件就可以在playbook中分成多行,以便于阅读。

when: >
  ( ansible_distribution == "Redhat" and
    ansible_distribution_major_version == "7" )
  or
  ( ansible_distribution == "Fedora" and
    ansible_distribution_major_version == "28" )

循环和有条件任务

循环和条件可以组合使用。

在下例中,yum模块将安装mariadb-server软件包,只要/上挂载的文件系统具有超过300MB的可用空间。ansible_mounts事实是一组字典,各自代表一个已挂载文件系统的相关事实。循环迭代列表中每一字典,只有找到了代表两个条件都为真的已挂载文件系统的字典时,条件语句才得到满足。

挂载到根目录 和 文件大小大于100000000 (没有就跳过)
[root@ansible opt]# cat test/test.yml 
---
- hosts: apache
  tasks: 
    - name: 
      yum: 
        name: mariadb
        state: installed
      loop: "{{ ansible_mounts }}"
      when: item.mount == "/" and item.size_available > 100000000
      
[root@ansible opt]# ansible-playbook test/test.yml

PLAY [apache] ************************************************************************

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

TASK [yum] ***************************************************************************
changed: [192.168.75.150] 

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

对某个任务结合使用whenloop时,将对每个项检查when语句。

下面是组合使用条件和注册变量的另一个示例。

//当vsftpd运行时,重启httpd
[root@ansible opt]# cat test/test.yml
---
- hosts: apache
  tasks: 
    - name: 
      shell: systemctl status vsftpd
      ignore_errors: yes  //略过错误
      register: result

    - name: 
      service:
        name: httpd
        state: restarted
      when: result.rc == 0
[root@ansible opt]# ansible-playbook --syntax-check test/test.yml

playbook: test/test.yml
[root@ansible opt]# ansible-playbook test/test.yml

PLAY [apache] ************************************************************************

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

TASK [shell] *************************************************************************
ok: [192.168.75.150]


TASK [service] ***********************************************************************
skipping: [192.168.75.150]

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

handlers

Ansible模块设计为具有幂等性。这表示,在正确编写的playbook中,playbook及其任务可以运行多次而不会改变受管主机,除非需要进行更改使受管主机进入所需的状态

但在时候,在任务确实更改系统时,可能需要运行进一步的任务。例如,更改服务配置文件时可能要求重新加载该服务以便使其更改的配置生效。

处理程序是响应由其他任务触发的通知的任务。仅当任务在受管主机上更改了某些内容时,任务才通知其处理程序。每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。因为处理程序就是任务,所以可以在处理程序中使用他们将用于任何其他任务的模块。通常而言,处理程序被用于重新引导主机和重启服务。

[root@ansible opt]#cat test/test.yml
- hosts: apache
  tasks:
    - name:
      lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: "Listen"
        line: "Listen 8080"

     - name:
       service:
         name: httpd
         state: restarted

[root@ansible opt]# ansible-playbook test/test.yml 

PLAY [192.168.75.150] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.75.150]

TASK [test] *****************************************************************************************************************************
changed: [192.168.75.150]

TASK [service] *************************************************************************************************************************
changed: [192.168.75.150]

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

//在执行一遍
[root@ansible opt]#cat test/test.yml

PLAY [192.168.75.150] ******************************************************************************************************************

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

TASK [test] *****************************************************************************************************************************
ok: [192.168.75.150]

TASK [service] *************************************************************************************************************************
changed: [192.168.75.150]

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

---
- hosts: apache
  tasks:
    - name: test
      lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: "^Listen"
        line: "Listen 8080"
      notify:
        restart httpd

  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted

//运行可以发现没有发生任何变化 因为lineinfile没有改变所以不会重启httpd
[root@master opt]# ansible-playbook test/test.yml 

PLAY [192.168.75.150] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.75.150]

TASK [test] *****************************************************************************************************************************
ok: [192.168.75.150]

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


 处理任务失败

管理play中的任务错误

Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务。

但有些时候,可能希望即使在任务失败时也继续执行play。例如,或许预期待定任务有可能会失败,并且希望通过有条件地运行某项其他任务来修复。

Ansible有多种功能可用于管理任务错误。

忽略任务失败

默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。

下列代码片段演示了如何在任务中使用ignore_errors,以便在任务失败时也继续在主机上执行playbook。例如,如果notapkg软件包不存在,则yum模块将失败,但若将ignore_errors设为yes,则执行将继续。

[root@ansible opt]# cat test/test.yml
---
- hosts: apache
  tasks: 
    - name:
      yum:
        name: notapk
        state: latest
      ignore_errors: yes  //跳过错误继续执行 

//执行
[root@ansible opt]# ansible-playbook test/test.yml 

PLAY [apache] ************************************************************************

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

TASK [yum] ***************************************************************************
fatal: [192.168.75.150]: FAILED! => {"changed": false, "failures": ["No package notapk available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring

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

任务失败后强制执行处理程序

通常而言,如果任务失败并且play在该主机上中止,则收到play中早前任务通知的处理程序将不会运行。如果在play中设置force_handlers: yes关键字,则即使play因为后续任务失败而中止也会调用被通知的处理程序。

下列代码片段演示了如何在play中使用force_handlers关键字,以便在任务失败时也强制执行相应的处理程序

[root@ansible opt]# cat test/test.yml
---
- hosts: apache
  force_handlers: yes
  tasks:
    - name:
      command: echo "wuhu"
      notify: restart

    - name:
      yum:
        name: qifei
        srate: present

  handlers:  //handlers程序,错误后重启httpd服务
    - name: restart
      service:
        name: httpd
        state: restarted


//执行
[root@master test]# ansible-playbook test/test.yml 

PLAY [192.168.75.150] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.75.150]

TASK [command] *************************************************************************************************************************
changed: [192.168.75.150]

TASK [yum] *****************************************************************************************************************************
fatal: [192.168.75.150]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (dnf) module: srate Supported parameters include: allow_downgrade, autoremove, bugfix, conf_file, disable_excludes, disable_gpg_check, disable_plugin, disablerepo, download_dir, download_only, enable_plugin, enablerepo, exclude, install_repoquery, install_weak_deps, installroot, list, lock_timeout, name, releasever, security, skip_broken, state, update_cache, update_only, validate_certs"}

RUNNING HANDLER [restart] **************************************************************************************************************
changed: [192.168.75.150]

PLAY RECAP *****************************************************************************************************************************
192.168.75.150

指定任务失败条件

可以在任务中使用failed_when关键字来指定表示任务已失败的条件。这通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败。

例如,可以运行输出错误消息的脚本,并使用该消息定义任务的失败状态。下列代码片段演示了如何在任务中使用failed_when关键字

[root@master opt]# cat test/test.yml 
---
- hosts: apache
  tasks:
    - name:
      script: yang.sh
      register: result
      failed_when: "'莫得这个东西' in result.stdout"
    - debug:
        var: result

[root@master opt]# cat test/test.yml 

PLAY [192.168.75.150] ******************************************************************************************************************

PLAY [192.168.75.150] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
PLAY [192.168.75.150] 

TASK [script] **************************************************************************************************************************
fatal: [192.168.75.150]: FAILED! => {"changed": true, "failed_when_result": true, "msg": "non-zero return code", "rc": 2, "stderr": "Shared connection to 192.168.72.137 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.72.137 closed."], "stdout": "ls: 无法访问'777': 莫得这个东西\r\n", "stdout_lines": ["ls: 无法访问'777': 莫得这个东西"]}

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


//也可以使用fail模块来完成


[root@master xm]# cat sb.yml 
---
- hosts: 192.168.72.137
  tasks:
    - name:
      script: yang.sh
      register: result
      ignore_errors: yes

    - name:
      fail:
        msg: "ang"
      when: "'莫得' in result.stdout"

[root@master test]# ansible-playbook  test/test.yml 
PLAY [192.168.75.150] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.75.150] 

TASK [script] **************************************************************************************************************************
fatal: [192.168.72.137]: FAILED! => {"changed": true, "msg": "non-zero return code", "rc": 2, "stderr": "Shared connection to 192.168.72.137 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.72.137 closed."], "stdout": "ls: 无法访问'777': 莫得\r\n", "stdout_lines": ["ls: 无法访问'777': 莫得"]}
...ignoring

TASK [fail] ****************************************************************************************************************************
fatal: [192.168.75.150]: FAILED! => {"changed": false, "msg": "ang"}

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

指定何时任务报告“changed”结果
当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。

changed_when关键字可用于控制任务在何时报告它已进行了更改。例如,下一示例中的shell模块将用于获取供后续任务使用的Kerberos凭据。它通常会在运行时始终报告changed。为抵制这种更改,应设置changed_when: false,以便它仅报告ok或failed

- name: get Kerberos credentials as "admin"
  shell: echo "{{ krb_admin_pass }}" | kinit -f admin
  changed_when: false

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值