环境
- 控制节点:Ubuntu 22.04
- Ansible 2.10.8
- 管理节点:CentOS 8
使用 when
语句做条件判断
创建文件 test1.yml
如下:
---
- hosts: all
tasks:
- name: task1
debug:
msg: "hello"
when: 1 > 0
- name: task2
debug:
msg: "OK"
when: 1 > 2
运行结果如下:
......
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "hello"
}
TASK [task2] ***************************************************************************************
skipping: [192.168.1.55]
......
可见,task满足条件,所以运行了;task2不满足条件,所以没有运行。
多个条件之间可以做逻辑运算(与或非),比如:
when: ((1 > 0) and (1 < 2)) or (not (1 == 3))
多个 and
条件,也可以写成list的形式,比如:
when:
- 1 < 2
- 2 < 3
- 3 < 4
基于 ansible_facts
的条件判断
例如:
- name: task3
debug:
msg: "hello"
when: ansible_facts['os_family'] == "RedHat" #"Debian"
也可以先把ansible_facts先存为变量,再对变量做条件判断,比如:
- name: task5
block:
- name: part1
set_fact:
version: "{{ ansible_facts['distribution_major_version'] }}"
- name: part2
debug:
msg: "Horse"
when: version | int >= 8
注:先用filter把变量转为int类型,再和整数8比较大小。
基于register变量的条件判断
这是一种常见的用法,上一个task把结果记录在变量里,下一个task根据该变量的值做条件判断。
---
- hosts: all
tasks:
- name: task1
shell: cat /tmp/a.txt | wc -l
register: result
- name: task2
debug:
msg: "More than 100 lines!"
when: result.stdout | int > 100
- 当文件超过100行时,结果如下:
......
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "More than 100 lines!"
}
......
当文件不超过100行时,结果如下:
......
TASK [task2] ***************************************************************************************
skipping: [192.168.1.55]
......
对register变量,可作如下判断:
is failed
is succeeded
is skipped
is changed
例如:
---
- hosts: all
tasks:
- name: task1
ansible.builtin.command: /bin/false
register: result
ignore_errors: true
- name: task2
debug:
msg: "Task fails!"
when: result is failed
- name: task3
debug:
msg: "Task succeeds!"
when: result is succeeded
- name: task4
debug:
msg: "Task skipped!"
when: result is skipped
- name: task5
debug:
msg: "Task changed!"
when: result is changed
基于变量的条件判断
注意: when
语句里的变量,不需要加 {{ }}
。
变量可转换成bool类型,例如:
---
- hosts: all
vars:
- var1: true
- var2: false
- var3: "yes"
- var4: "no"
tasks:
- name: task1
debug:
msg: "task1"
when: var1
- name: task2
debug:
msg: "task2"
when: not var2
- name: task3
debug:
msg: "task3"
when: var3 | bool
- name: task4
debug:
msg: "task4"
when: not (var4 | bool)
使用没有定义的变量会报错,所以,在使用变量前,可以先判断其是否定义:
is defined
is undifined
例如:
---
- hosts: all
tasks:
- name: task1
debug:
msg: "OK"
when: var1 is defined and var1
这是一种非常常见的用法。
在循环里使用条件判断
loop
和 when
可以一起用,对每次循环做条件判断。例如,遍历文件每一行,若内容超过2个字符,则打印其内容:
---
- hosts: all
tasks:
- name: task1
shell: cat /tmp/a.txt
register: result
- name: task2
debug:
msg: "{{ item }}"
loop: "{{ result.stdout_lines }}"
when: item | length > 2
假设 a.txt
内容如下:
aaaaa
b
ccccc
则运行结果如下:
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => (item=aaaaa) => {
"msg": "aaaaa"
}
skipping: [192.168.1.55] => (item=b)
ok: [192.168.1.55] => (item=ccccc) => {
"msg": "ccccc"
}
也可以遍历/判断自定义的list或者dict,例如:
---
- hosts: all
vars:
- mylist1: [ 1, 2, 3 ]
- mydict1: {"a": 10, "b": 20, "c": 30}
tasks:
- name: task1
debug:
msg: "{{ item }}"
loop: "{{ mylist1 }}"
when: item > 1
- name: task2
debug:
msg: "{{ item }}"
loop: "{{ query('dict', mydict1) }}"
when: item.value > 10
运行结果如下:
......
TASK [task1] ***************************************************************************************
skipping: [192.168.1.55] => (item=1)
ok: [192.168.1.55] => (item=2) => {
"msg": 2
}
ok: [192.168.1.55] => (item=3) => {
"msg": 3
}
TASK [task2] ***************************************************************************************
skipping: [192.168.1.55] => (item={'key': 'a', 'value': 10})
ok: [192.168.1.55] => (item={'key': 'b', 'value': 20}) => {
"msg": {
"key": "b",
"value": 20
}
}
ok: [192.168.1.55] => (item={'key': 'c', 'value': 30}) => {
"msg": {
"key": "c",
"value": 30
}
}
......
注意,最好也判断一下变量是否定义,比如:
- name: task3
debug:
msg: "{{ item }}"
loop: "{{ mylist2 }}"
when: mylist2 is defined and item > 1
- name: task4
debug:
msg: "{{ item }}"
loop: "{{ query('dict', mydict2) }}"
when: mydict2 is defined and item.value > 10
或者提供一个缺省的空list/dict,例如:
- name: task5
debug:
msg: "{{ item }}"
loop: "{{ mylist2 | default([]) }}"
when: item > 1
- name: task6
debug:
msg: "{{ item }}"
loop: "{{ query('dict', mydict2 | default({})) }}"
when: item.value > 10
注意:task3和task4会skip,而task5和task6会运行。
import和include的条件判断
先看include。例如, main.yml
内容如下:
---
- hosts: all
tasks:
- name: task1
include_tasks: test11.yml
#import_tasks: test11.yml
when: var1 is not defined
#vars:
# - var1: 111
test11.yml
内容如下:
---
- name: task1
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined
- name: task2
debug:
msg: "I am task2"
- name: task3
set_fact:
var1: 123
when: var1 is not defined
- name: task4
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined
- name: task5
debug:
msg: "I am task5"
若 main.yml
中没有定义 var1
,则运行结果如下:
TASK [main_task1] **********************************************************************************
included: /root/temp/temp1113_2/test11.yml for 192.168.1.55
TASK [task1] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "I am task2"
}
TASK [task3] ***************************************************************************************
ok: [192.168.1.55]
TASK [task4] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "var1 = 123"
}
TASK [task5] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "I am task5"
}
若 main.yml
中定义了 var1
,则运行结果如下:
TASK [main_task1] **********************************************************************************
skipping: [192.168.1.55]
include_tasks
的逻辑比较直观:
- 如果
main.yml
没有定义var1
,则满足条件,运行test11.yml
。 - 如果
main.yml
定义了var1
,则不满足条件,不运行test11.yml
。
现在,把 include_tasks
换成 import_tasks
, test11.yml
内容不变。
若 main.yml
中没有定义 var1
,则运行结果如下:
TASK [task1] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "I am task2"
}
TASK [task3] ***************************************************************************************
ok: [192.168.1.55]
TASK [task4] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task5] ***************************************************************************************
skipping: [192.168.1.55]
若 main.yml
中定义了 var1
,则运行结果如下:
TASK [task1] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task2] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task3] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task4] ***************************************************************************************
skipping: [192.168.1.55]
TASK [task5] ***************************************************************************************
skipping: [192.168.1.55]
import_tasks
的运行结果和 include_tasks
大不相同。这是因为, import_tasks
是在预编译期,就把引用的task替换过来了(注意在运行结果里并没有出现 main_task1
的字眼),所以就相当于把 when
的条件判断放到 test11.yml
的每个task里了:
---
- name: task1
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined and var1 is not defined
- name: task2
debug:
msg: "I am task2"
when: var1 is not defined
- name: task3
set_fact:
var1: 123
when: var1 is not defined and var1 is not defined
- name: task4
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined and var1 is not defined
- name: task5
debug:
msg: "I am task5"
when: var1 is not defined
这样就能理解运行结果了。
注意: main_task1
里的变量定义,并没有放到 test11.yml
的每个task里。
创建文件 main.yml
如下:
---
- hosts: all
tasks:
- name: main_task1
import_tasks: test13.yml
vars:
- var1: 111
创建文件 test13.yml
如下:
---
- name: task1
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined
- name: task2
set_fact:
var1: 123
- name: task3
debug:
msg: "var1 = {{ var1 }}"
when: var1 is defined
运行结果如下:
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "var1 = 111"
}
TASK [task2] ***************************************************************************************
ok: [192.168.1.55]
TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "var1 = 123"
}
可见,task1和task3打印的 var1
变量值并不相同。前者是从 main.yml
而来,后者是从task2而来。
注:关于 import_xxx
和 include_xxx
,参见我另一篇文档。
调试
最简单的方法就是打印出来看一下。比如:
---
- hosts: all
tasks:
- name: task1
set_fact:
var1: '123'
- name: task2
debug:
msg: "var1 = {{ var1 }}"
when: var1 == 123
运行结果如下:
TASK [task1] ***************************************************************************************
ok: [192.168.1.55]
TASK [task2] ***************************************************************************************
skipping: [192.168.1.55]
可以看到,task2被skip了,这是因为 when
语句没有满足条件。
要确认的话,可以把条件判断的结果打印出来:
......
- name: task3
debug:
var: var1 == 123
......
运行结果如下:
......
TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
"var1 == 123": false
}
......
可见条件判断的结果确实是false。
注意:用的是 debug
和 var
打印条件判断的结果。
接下来,可以打印出来变量看一下其值:
......
- name: task4
debug:
var: var1
......
运行结果如下:
......
TASK [task4] ***************************************************************************************
ok: [192.168.1.55] => {
"var1": "123"
}
......
可见 var1
的值是 "123"
,是一个字符串(如果是数值则是 123
)。
当然,更直接的办法是查看一下 var1
的类型:
......
- name: task5
debug:
msg: "{{ var1 | type_debug }}"
......
运行结果如下:
......
TASK [task5] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "AnsibleUnicode"
}
......
如果是数值,则类型是 int
。
因为 var1
是字符串,而 123
是整数,所以task2的判断条件不满足。
修改方法为:
原先为: var1 == 123
应改为: var1 == '123'
,或者 var1 | int == 123
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html