在 ansible 中,使用 when 关键字来做条件判断,when 关键字即为当条件成功就执行此条任务。在 when 判断中不需要加 {{}}

字符串判断

判断符 说明
== 判断字符串是否相同,相同为真,不同为假
lower 是否全是小写,是为真,不是为假
upper 是否是纯大写,是为真,不是为假
in 判断字符串是否在另一个字符串中,是为真,不是为假

判断系统,不支持的系统直接报错退出

ansible_distribution 是 ansible 自带变量,查看变量可以用 ansible localhost -m setup 命令。

1
2
3
4
5
---
- hosts: all
tasks:
- fail: msg="this playbook don't support CentOS"
when: ansible_distribution == "CentOS"

判断字符串大小写

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: all
vars:
str1: "abc"
str2: "ABC"
tasks:
- debug:
msg: "This string is all lowercase"
when: str1 is lower
- debug:
msg: "This string is all uppercase"
when: str2 is upper

判断字符串的包含关系

1
2
3
4
5
---
tasks:
- name: check wsl
fail: msg="this playbook don't support wsl"
when: 'WSL' in ansible_kernel

运算符判断

在 ansible 中,我们可以使用如下比较运算符:

比较运算符 说明
== 比较两个对象是否相等,相等为真
!= 比较两个对象是否不等,不等为真
> 比较两个值的大小,如果左边的值大于右边的值,则为真
< 比较两个值的大小,如果左边的值小于右边的值,则为真
>= 比较两个值的大小,如果左边的值大于右边的值或左右相等,则为真
<= 比较两个值的大小,如果左边的值小于右边的值或左右相等,则为真

我们总结的这些运算符其实都是 jinja2 的运算符,ansible 使用 jinja2 模板引擎,在 ansible 中也可以直接使用 jinja2 的这些运算符。

说完了比较运算符,再来说说逻辑运算符,可用的逻辑运算符如下

逻辑运算符 说明
and 逻辑与,当左边与右边同时为真,则返回真
or 逻辑或,当左边与右边有任意一个为真,则返回真
not 取反,对一个操作体取反
( ) 组合,将一组操作体包装在一起,形成一个较大的操作体

例 1:输出大于 2 的数字。

1
2
3
4
5
6
7
8
---
- hosts: all
gather_facts: no
tasks:
- debug:
var: item
when: item > 2
with_items: [ 1, 2, 3 ]

例 2:判断客户机系统是否是 CentOS 7。

1
2
3
4
5
6
---
- hosts: all
tasks:
- debug:
msg: "System release is centos7"
when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"

这里的 when 条件也可写为如下:

1
2
3
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"

其含义为列表中每一项结果都为 true 时才执行。

例 3:判断任务是否成功执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts: localhost
gather_facts: no
tasks:
- name: check folder exists
shell: "ls /test_folder"
register: check_test_folder
ignore_errors: true
- debug:
msg: "Command execution successful"
when: check_test_folder.rc == 0
- debug:
msg: "Command execution failed"
when: check_test_folder.rc != 0

例 4:判断系统是 Ubuntu 或 LinuxMint 且不是虚拟机

1
2
3
4
5
6
7
8
9
10
11
---
- name: install gui tools on ubuntu
apt:
name: ["copyq", "flameshot"]
state: latest
update_cache: no
become: yes
when:
( ansible_distribution == "Ubuntu" or ansible_distribution == "Linux Mint" )
and
( ansible_virtualization_role != "guest" )

文件判断

判断 Ansible 控制主机的文件

ansible 可通过如下关键字对文件状态进行判断:

判断操作 说明
file 判断路径是否是一个文件,如果路径是一个文件则返回真;
directory 判断路径是否是一个目录,如果路径是一个目录则返回真;
link 判断路径是否是一个软链接,如果路径是一个软链接则返回真;
mount 判断路径是否是一个挂载点,如果路径是一个挂载点则返回真;
exists 判断路径是否存在,如果路径存在则返回真;

例:判断 /test_folder 是否存在。

这里判断的路径是 ansible 控制主机的路径

1
2
3
4
5
6
7
8
9
10
11
---
- hosts: all
gather_facts: no
vars:
testpath: /test_folder
tasks:
- debug:
msg: "file exists"
when: testpath is exists
# 下面判断表示 testpath 路径是否不存在
# when: testpath is not exists

判断被控机器的文件状态

1
2
3
4
5
6
7
8
9
10
- name: get file stat for gpg key
stat: path=/usr/share/keyrings/docker-archive-keyring.gpg
register: vscode_gpg_key

# 判断远程文件是否存在
- name: add gpg key
shell:
cmd: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
become: yes
when: not vscode_gpg_key.stat.exists

变量判断

ansible 可通过如下几个关键字对变量进行判断:

string 判断对象是否是一个字符串,是字符串则返回真;
number 判断对象是否是一个数字,是数字则返回真;
defined 判断变量是否已经定义,已经定义则返回真;
undefind 判断变量是否已经定义,未定义则返回真;
none 判断变量值是否为空,如果变量已经定义,但是变量值为空,则返回真;

例 1:当对应的条件为真时,你可以看到 debug 模块对应的输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
- hosts: all
gather_facts: no
vars:
defined_var: "test"
none_var:
tasks:
- debug:
msg: "Variable is defined"
when: defined_var is defined
- debug:
msg: "Variable is undefined"
when: undefined_var is undefined
- debug:
msg: "The variable is defined, but there is no value"
when: none_var is none

例 2:判断给定变量是一个字符串还是数字。

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: all
gather_facts: no
vars:
testvar: "a"
tasks:
- debug:
msg: "{{testvar}} is a number"
when: testvar is number
- debug:
msg: "{{testvar}} is a string"
when: testvar is string

结果判断

ansible 可通过如下几个关键字来对任务的执行结果进行判断:

success 或 succeeded 通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
failure 或 failed 通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
change 或 changed 通过任务的返回信息判断任务的执行状态,任务执行状态为 changed 则返回真
skip 或 skipped 通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真

例:根据任务执行结果输出对应信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
---
- hosts: all
gather_facts: no
vars:
doshell: "yes"
tasks:
- shell: "cat /test_folder/test_file"
when: doshell == "yes"
register: returnmsg
ignore_errors: true
- debug:
msg: "success"
when: returnmsg is success
- debug:
msg: "failed"
when: returnmsg is failure
- debug:
msg: "changed"
when: returnmsg is change
- debug:
msg: "skip"
when: returnmsg is skip

整除判断

ansible 可通过如下关键字对一个数字进行整除判断:

even 判断数值是否是偶数,是偶数则返回真
odd 判断数值是否是奇数,是奇数则返回真
divisibleby(num) 判断是否可以整除指定的数值,如果除以指定的值以后余数为 0,则返回真

看如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
- hosts: localhost
gather_facts: no
vars:
num1: 2
num2: 3
num3: 8
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 4"
when: num3 is divisibleby(4)

列表父子集判断

ansible 可使用如下关键字对列表进行父子集判断:

父子集判断 说明
subset 判断一个 list 是不是另一个 list 的子集,是另一个 list 的子集时返回真
superset 判断一个 list 是不是另一个 list 的父集,是另一个 list 的父集时返回真

看如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
- hosts: localhost
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)

版本判断

在 ansible 中 version 关键字可以用于对比两个版本号的大小,或者与指定的版本号进行对比,使用语法为 version(‘ 版本号 ‘, ‘ 比较操作符 ‘)。

version 支持的比较操作符如下:

比较操作符 符号表示 字母表示
大于 > gt
大于等于 >= ge
小于 < lt
小于等于 <= le
等于 == 或 = eq
不等于 != 或 <> ne

看如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: localhost
vars:
ver1: 18.04
ver2: 22.04
tasks:
- debug:
msg: "This message can be displayed when the ver2 is greater than ver1"
when: ver2 is version(ver1,">")
- debug:
msg: "system version {{ansible_distribution_version}} greater than 18.04"
when: ansible_distribution_version is version("18.04","gt")

合并判断

在 ansible 中,可以使用 block 关键字将多个任务整合成一个块,这个块将被当做一个整体,我们可以对这个块添加判断条件,当条件成立时,则执行这个块中的所有任务。

我们来看一个小示例,如下:

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: localhost
gather_facts: no
tasks:
- debug:
msg: "task1"
- block:
- debug:
msg: "task2"
- debug:
msg: "task3"
when: 2 > 1

状态判断

failed_when 的作用就是,当对应的条件成立时,将对应任务的执行状态设置为失败,我们可以借助 failed_when 关键字来完成类似 fail 模块的功能。

看下面示例:

1
2
3
4
5
6
7
8
9
10
11
---
- hosts: localhost
gather_facts: no
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"

上例中,failed_when 对应的条件是 “error” in return_value.stdout,表示 error 字符串如果存在于 shell 模块执行后的标准输出中,则条件成立,当条件成立后,shell 模块的执行状态将会被设置为失败,由于 shell 模块的执行状态被设置为失败,所以 playbook 会终止运行,于是,最后的 debug 模块并不会被执行。

理解了 ‘ failed_when’ 关键字以后,顺势理解 ‘changed_when’ 关键字就容易多了。

状态判断 说明
failed_when 关键字的作用是在条件成立时,将对应任务的执行状态设置为失败。
changed_when 关键字的作用是在条件成立时,将对应任务的执行状态设置为 changed。
1
2
3
4
5
6
7
---
- hosts: localhost
gather_facts: no
tasks:
- debug:
msg: "test message"
changed_when: 2 > 1

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

1
2
3
4
5
6
7
8
9
10
11
$ ansible-playbook test.yml 

PLAY [localhost] **********************************************************************************************************************

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

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

在 Ansible 中只有任务作出了实际的操作时(执行后状态为 changed),才会真正的执行对应的 handlers,这样我们可以控制当前任务的状态。

其实,changed_when 除了能够在条件成立时将任务的执行状态设置为 changed,还能让对应的任务永远不能是 changed 状态,示例如下:

1
2
3
4
5
6
---
- hosts: B
gather_facts: no
tasks:
- shell: "ls /opt"
changed_when: false

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