目录python
在有的时候play的结果依赖于变量、fact或者是前一个任务的执行结果,或者有的时候,咱们会基于上一个task执行返回的结果而决定如何执行后续的task。这个时候就须要用到条件判断。linux
条件语句在Ansible中的使用场景:shell
在ansible中,使用条件判断的关键字就是when。apache
如在安装包的时候,须要指定主机的操做系统类型,或者是当操做系统的硬盘满了以后,须要清空文件等,可使用when语句来作判断 。when关键字后面跟着的是python的表达式,在表达式中你可以使用任何的变量或者fact,当表达式的结果返回的是false,便会跳过本次的任务ubuntu
下面是一个基本的用法示例:vim
--- - name: Install vim hosts: all tasks: - name:Install VIM via yum yum: name: vim-enhanced state: installed when: ansible_os_family =="RedHat" - name:Install VIM via apt apt: name: vim state: installed when: ansible_os_family =="Debian" - name: Unexpected OS family debug: msg="OS Family {{ ansible_os_family }} is not supported" fail=yes when: not ansible_os_family =="RedHat" or ansible_os_family =="Debian"
在上面的示例当中,咱们使用了"=="的比较运算符,在ansible中,还支持以下比较运算符:ide
==
:比较两个对象是否相等,相等则返回真。可用于比较字符串和数字!=
:比较两个对象是否不等,不等则为真。>
:比较两个对象的大小,左边的值大于右边的值,则为真<
:比较两个对象的大小,左边的值小于右边的值,则为真>=
:比较两个对象的大小,左边的值大于等于右边的值,则为真<=
:比较两个对象的大小,左边的值小于等于右边的值,则为真下面是一些简单的示例:oop
when: ansible_machine == "x86_64" when: max_memory <= 512
在Ansible中,除了比较运算符,还支持逻辑运算符:post
示例:性能
# 逻辑或 when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora" # 逻辑与 when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64" when: - ansible_distribution_version == "7.5" - ansible_kernel == "3.10.0-327.el7.x86_64" # 组合 when: => ( ansible_distribution == "RedHat" and ansible_distribution_major_version == "7" ) or ( ansible_distribution == "Fedora" and ansible_distribution_major_version == "28")
一个完整的例子:
# 判断register注册变量的返回结果 - name: restart httpd if postfix is running hosts: test tasks: - name: get postfix server status command: /usr/bin/systemctl is-active postfix ignore_errors: yes register: result - name: restart apache httpd based on postfix status service: name: httpd state: restarted when: result.rc == 0
在shell当中,咱们可以使用test命令来进行一些经常使用的判断操做,以下:
# 判断/test文件是否存在 test -e /test # 判断/testdir是否存在且为一个目录 test -d /testdir
事实上,在ansible中也有相似的用法,只不过ansible没有使用linux的test命令,而是jinja2模板的tests。
下面是一个简单示例:
# 经过条件语句判断testpath的路径是否存在 - hosts: test vars: testpath: /testdir tasks: - debug: msg: "file exist" when: testpath is exists
上面的示例中,咱们使用了is exists
用于路径存在时返回真,也可使用is not exists
用于路径不存在时返回真。也能够在整个条件表达式的前面使用not以取反:
- hosts: test vars: testpath: /testdir1 tasks: - debug: msg: "file not exist" when: not testpath is exists
在ansible中,除了可以使用exists这种tests以外,还有一些别的tests。接下来咱们详细说一说。
示例:
- hosts: test gather_facts: no vars: testvar: "test" testvar1: tasks: - debug: msg: "testvar is defined" when: testvar is defined - debug: msg: "testvar2 is undefined" when: testvar2 is undefined - debug: msg: "testvar1 is none" when: testvar1 is none
示例:
- hosts: test gather_facts: no vars: doshell: true tasks: - shell: 'cat /testdir/aaa' when: doshell register: result ignore_errors: true - debug: msg: "success" when: result is success - debug: msg: "failed" when: result is failure - debug: msg: "changed" when: result is change - debug: msg: "skip" when: result is skip
特别注意:关于路径的全部判断均是判断主控端上的路径,而非被控端上的路径
示例:
- hosts: test gather_facts: no vars: testpath1: "/testdir/test" testpath2: "/testdir" tasks: - debug: msg: "file" when: testpath1 is file - debug: msg: "directory" when: testpath2 is directory
- hosts: test gather_facts: no vars: str1: "abc" str2: "ABC" tasks: - debug: msg: "str1 is all lowercase" when: str1 is lower - debug: msg: "str2 is all uppercase" when: str2 is upper
示例:
- hosts: test gather_facts: no vars: num1: 6 num2: 8 num3: 15 tasks: - debug: msg: "num1 is an even number" when: num1 is even - debug: msg: "num2 is an odd number" when: num2 is odd - debug: msg: "num3 can be divided exactly by" when: num3 is divisibleby(3)
version
可用于对比两个版本号的大小,或者与指定的版本号进行对比,使用语法为version("版本号","比较操做符")
- hosts: test vars: ver1: 1.2 ver2: 1.3 tasks: - debug: msg: "ver1 is greater than ver2" when: ver1 is version(ver2,">") - debug: msg: "system version {{ ansible_distribution_version }} greater than 7.3" when: ansible_distribution_version is version("7.3","gt")
superset
判断一个list是否是另外一个list的父集"
- hosts: test gather_facts: no vars: a: - 2 - 5 b: [1,2,3,4,5] tasks: - debug: msg: "A is a subset of B" when: a is subset(b) - debug: msg: "B is the parent set of A" when: b is superset(a)
in
判断一个字符串是否存在于另外一个字符串中,也可用于判断某个特定的值是否存在于列表中
- hosts: test vars: supported_distros: - RedHat - CentOS tasks: - debug: msg: "{{ ansible_distribution }} in supported_distros" when: ansible_distribution in supported_distros
number
判断对象是否为一个数字,是则为真
- hosts: test gather_facts: no vars: var1: 1 var2: "1" var3: a tasks: - debug: msg: "var1 is a number" when: var1 is number - debug: msg: "var2 is a string" when: var2 is string - debug: msg: "var3 is a string" when: var3 is string
咱们在前面使用when作条件判断时,若是条件成立则执行对应的任务。但这就面临一个问题,当咱们要使用同一个条件判断执行多个任务的时候,就意味着咱们要在某一个任务下面都写一下when语句,并且判断条件彻底同样。这种方式不只麻烦并且显得low。Ansible提供了一种更好的方式来解决这个问题,即block。
在ansible中,使用block将多个任务进行组合,看成一个总体。咱们能够对这一个总体作条件判断,当条件成立时,则执行块中的全部任务:
- hosts: test tasks: - debug: msg: "task1 not in block" - block: - debug: msg: "task2 in block1" - debug: msg: "task3 in block1" when: 2 > 1
下面是一个稍微有用点儿的例子:
- hosts: test tasks: - name: set /etc/resolv.conf template: src: resolv.conf.j2 dest: /etc/resolv.conf owner: root group: root mode: 0644 - block: - name: ensure /etc/resolvconf/resolv.conf.d/base file for ubuntu 16.04 template: src: resolv.conf.j2 dest: /etc/resolvconf/resolv.conf.d/base - name: config dns for ubuntu 16.04 template: src: resolv.conf.j2 dest: /etc/resolv.conf when: ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "16"
使用block注意事项:
block除了能和when一块儿使用以外,还能做错误处理。这个时候就须要用到rescue关键字:
- hosts: test tasks: - block: - shell: 'ls /testdir' rescue: - debug: msg: '/testdir is not exists'
在上面的例子中,当block中的任务执行失败时,则运行rescue中的任务。若是block中的任务正常执行,则rescue的任务就不会被执行。若是block中有多个任务,则任何一个任务执行失败,都会执行rescue。block中能够定义多个任务,一样rescue当中也能够定义多个任务。
当block执行失败时,rescue中的任务才会被执行;而不管block执行成功仍是失败,always中的任务都会被执行:
- hosts: test tasks: - block: - shell: 'ls /testdir' rescue: - debug: msg: '/testdir is not exists' always: - debug: msg: 'This task always executes'
在上面讲block的使用方法的时候,咱们说block除了能够将多个任务组合到一块儿,还有错误处理的功能。接下来咱们继续说一说错误处理。
在shell中,可能会有这样的需求:当脚本执行至某个阶段时,须要对某个条件进行判断,若是条件成立,则当即终止脚本的运行。在shell中,能够直接调用"exit"便可执行退出。事实上,在playbook中也有相似的模块能够作这件事。即fail模块。
fail模块用于终止当前playbook的执行,一般与条件语句组合使用,当知足条件时,终止当前play的运行。
选项只有一个:
示例:
# 使用fail模块中断playbook输出 - hosts: test tasks: - shell: echo "Just a test--error" register: result - fail: msg: "Conditions established,Interrupt running playbook" when: "'error' in result.stdout" - debug: msg: "Inever execute,Because the playbook has stopped"
事实上,当fail和when组合使用的时候,还有一个更简单的写法,即failed_when
,当知足某个条件时,ansible主动触发失败。
# 若是在command_result存在错误输出,且错误输出中,包含了`FAILED`字串,即返回失败状态: - name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr"
也能够直接经过fail
模块和when
条件语句,写成以下:
- name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result ignore_errors: True - name: fail the play if the previous command did not succeed fail: msg="the command failed" when: " command_result.stderr and 'FAILED' in command_result.stderr"
ansible一旦执行返回失败,后续操做就会停止,因此failed_when一般能够用于知足某种条件时主动停止playbook运行的一种方式。
ansible默认处理错误的机制是遇到错误就中止执行。但有些时候,有些错误是计划之中的。咱们但愿忽略这些错误,以让playbook继续往下执行。这个时候就可使用
ignore_errors
忽略错误,从而让playbook继续往下执行。
当咱们控制一些远程主机执行某些任务时,当任务在远程主机上成功执行,状态发生更改时,会返回changed状态响应,状态未发生更改时,会返回OK状态响应,当任务被跳过期,会返回skipped状态响应。咱们能够经过changed_when
来手动更改changed
响应状态。示例以下:
- shell: /usr/bin/billybass --mode="take me to the river" register: bass_result changed_when: "bass_result.rc != 2" #只有该条task执行之后,bass_result.rc的值不为2时,才会返回changed状态 # this will never report 'changed' status - shell: wall 'beep' changed_when: False #当changed_when为false时,该条task在执行之后,永远不会返回changed状态
# 只打印大于5的值 tasks: - command: echo {{ item }} loop: [ 0, 2, 4, 6, 8, 10 ] when: item > 5
# 确保将mariadb-server安装到根分区且根分区的可用空间要大于300M - name: install mariadb-server if enough space on root yum: name: mariadb-server state;拉特st loop: "{{ ansible_mounts }}" when: item.mount == "/" and item.size_available > 300000000