目录
指定何时任务报告“changed”结果当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。
条件判断
有条件地运行任务
Ansible可使用conditionals在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。
我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
以下场景说明了在Ansible中使用条件的情况:
- 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
- Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。
- 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
- 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
- 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
条件任务语法
when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。
可以测试的一个最简单条件是某一布尔变量是True还是False。以下示例中的when语句导致任务仅在run_my_task为True时运行:
[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语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。
如果任一条件为真时满足条件语句,则应当使用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
对某个任务结合使用when和loop时,将对每个项检查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