文章目录
- 环境
- 概述
- 语法
- 字符串
- Vault
- 真假性
- 版本比较
- 子集和超集
- list里的元素
- list的"所有元素都是true"和"至少一个元素是true"
- 路径
- human_readable
- task结果
- 类型
- 参考
环境
- 管理节点:Ubuntu 22.04
- 控制节点:CentOS 8
- Ansible:2.15.6
概述
Jinja test是指计算一个表达式并返回 true 或 false 。
同所有的template一样,test是运行在控制节点上,而不是受控节点上。
语法
<expression> is <test name>
比如: result is failed
字符串
我们经常需要用正则表达式来匹配字符串。可用如下test:
match:从起始位置匹配search:从任意位置匹配regex:类似search,可添加match_type参数
比如:
yaml
---
- hosts: all
vars:
var1: "abcdefghijklmn"
tasks:
- name: task1
debug:
msg: "OK"
when: var1 is match("abc") # OK
- name: task2
debug:
msg: "OK"
when: var1 is match ("^abc") # OK
- name: task3
debug:
msg: "OK"
when: var1 is match ("abc.*mn$") # OK
- name: task4
debug:
msg: "OK"
when: var1 is match ("mn") # Skip
- name: task5
debug:
msg: "OK"
when: var1 is search ("mn") # OK
- name: task6
debug:
msg: "OK"
when: var1 is regex ("mn") # OK
上述task中,只有task4不满足条件。
此外, match 、 search 、 regex 方法都可以添加 ignorecase 和 multiline 参数。
ignorecase:忽略大小写,默认值为Falsemultiline:多行,默认值为False
比如:
yaml
---
- hosts: all
vars:
var1: "abcdefg\nhijklmn"
tasks:
- name: task1
debug:
msg: "OK"
when: var1 is match("ABC") # Skip
- name: task2
debug:
msg: "OK"
when: var1 is match("ABC", ignorecase=True) # OK
- name: task3
debug:
msg: "OK"
when: var1 is search("^hi") # Skip
- name: task4
debug:
msg: "OK"
when: var1 is search("^hi", multiline=True) # OK
本例中, ^hi 匹配了第二行的开头,若 multiline 设置为True,则匹配成功。
Vault
vault_encrypted:测试是否为加密的vault值
比如:
yaml
---
- hosts: all
vars:
var1: "abcdefg"
var2: !vault |
$ANSIBLE_VAULT;1.2;AES256;dev
61323931353866666336306139373937316366366138656131323863373866376666353364373761
3539633234313836346435323766306164626134376564330a373530313635343535343133316133
36643666306434616266376434363239346433643238336464643566386135356334303736353136
6565633133366366360a326566323363363936613664616364623437336130623133343530333739
3039
tasks:
- name: task1
debug:
msg: "OK"
when: var1 is vault_encrypted # Skip
- name: task2
debug:
msg: "OK"
when: var2 is vault_encrypted # OK
真假性
truthy:真falsy:假
此外,二者都可以添加 convert_bool 参数,将"yes"/"no"、"on"/"off"等转换为布尔值。
比如:
yaml
---
- hosts: all
vars:
var1: "abcdefg"
var2: ""
var3: "yes"
var4: "no"
var5: "on"
var6: "off"
tasks:
- name: task1
debug:
msg: "OK"
when: var1 is truthy # OK
- name: task2
debug:
msg: "OK"
when: var2 is truthy # Skip
- name: task3
debug:
msg: "OK"
when: var3 is truthy(convert_bool=True) # OK
- name: task4
debug:
msg: "OK"
when: var4 is truthy(convert_bool=True) # Skip
- name: task5
debug:
msg: "OK"
when: var5 is truthy(convert_bool=True) # OK
- name: task6
debug:
msg: "OK"
when: var6 is truthy(convert_bool=True) # Skip
- name: task7
debug:
msg: "OK"
when: var1 is falsy # Skip
- name: task8
debug:
msg: "OK"
when: var2 is falsy # OK
- name: task9
debug:
msg: "OK"
when: var3 is falsy(convert_bool=True) # Skip
- name: task10
debug:
msg: "OK"
when: var4 is falsy(convert_bool=True) # OK
- name: task11
debug:
msg: "OK"
when: var5 is falsy(convert_bool=True) # Skip
- name: task12
debug:
msg: "OK"
when: var6 is falsy(convert_bool=True) # OK
版本比较
version:版本比较
可指定如下比较:
<lt:小于<=le:小于等于>gt:大于>=ge:大于等于===eq:等于!=<>ne:不等于
比如:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "{{ ansible_facts['distribution_version'] }}" # 8.1
- name: task2
debug:
msg: "OK"
when: ansible_facts['distribution_version'] is version('8.1', '>') # Skip
- name: task3
debug:
msg: "OK"
when: ansible_facts['distribution_version'] is version('8.1', '>=') # OK
version 方法还可以添加第三个参数,表示比较类型。
strict:True/False,是否严格比较version_typeloosestrictsemver/semanticpep440
注意: strict 和 version_type 互斥,最多只能指定一个。
此处我没仔细研究,等需要用的时候再说吧。
子集和超集
subset:子集superset:超集
比如:
yaml
---
- hosts: all
vars:
var1: [1, 2, 3, 4, 5]
var2: [2, 3, 4]
tasks:
- name: task1
debug:
msg: "OK"
when: var2 is subset(var1) # OK
- name: task2
debug:
msg: "OK"
when: var1 is subset(var2) # Skip
- name: task3
debug:
msg: "OK"
when: var2 is superset(var1) # Skip
- name: task4
debug:
msg: "OK"
when: var1 is superset(var2) # OK
- name: task5
debug:
msg: "OK"
when: var1 is subset(var1) # OK
- name: task6
debug:
msg: "OK"
when: var1 is superset(var1) # OK
list里的元素
contains:是否包含特定的元素,若包含则返回元素
比如:
yaml
---
- hosts: all
vars:
var1:
- name: Tom
age: 20
sport:
- football
- basketball
- name: Jerry
age: 18
sport:
- swim
- tennis
- football
tasks:
- name: task1
debug:
msg: "{{ var1 | selectattr('name', 'contains', 'Tom') }}" # 第一个元素
- name: task2
debug:
msg: "{{ var1 | selectattr('sport', 'contains', 'football') }}" # 第一个和第二个元素
- name: task3
debug:
msg: "{{ var1 | selectattr('sport', 'contains', 'football') | first }}" # 第一个元素
- name: task4
debug:
msg: "{{ (var1 | selectattr('sport', 'contains', 'football') | first).age }}" # 第一个元素的age属性值
运行结果如下:
powershell
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": [
{
"age": 20,
"name": "Tom",
"sport": [
"football",
"basketball"
]
}
]
}
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": [
{
"age": 20,
"name": "Tom",
"sport": [
"football",
"basketball"
]
},
{
"age": 18,
"name": "Jerry",
"sport": [
"swim",
"tennis",
"football"
]
}
]
}
TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": {
"age": 20,
"name": "Tom",
"sport": [
"football",
"basketball"
]
}
}
TASK [task4] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": "20"
}
本例中,是使用 selectattr 方法,通过元素的属性值来匹配元素。 contains 可作用于如下filter:
select:选择元素reject:排除元素selectattr:根据属性值选择元素rejectattr:根据属性值排除元素
比如:
yaml
---
- hosts: all
vars:
var1: ["aaa", "bbb", "ccc"]
tasks:
- name: task1
debug:
msg: "{{ var1 | select('contains', 'aaa') }}"
- name: task2
debug:
msg: "{{ var1 | select('contains', 'Tom') }}"
- name: task3
debug:
msg: "{{ var1 | reject('contains', 'aaa') }}"
- name: task4
debug:
msg: "{{ var1 | reject('contains', 'Tom') }}"
运行结果如下:
powershell
TASK [task1] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": [
"aaa"
]
}
TASK [task2] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": []
}
TASK [task3] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": [
"bbb",
"ccc"
]
}
TASK [task4] ***************************************************************************************
ok: [192.168.1.55] => {
"msg": [
"aaa",
"bbb",
"ccc"
]
}
注意: select 等方法还可以有很多其它有趣的参数,比如:
yaml
---
- hosts: all
vars:
var1: [0, 1, 2, 3, 4, 4, 3, 2, 1]
tasks:
- name: task1
debug:
msg: "{{ var1 | select('odd') }}" # 1, 3, 3, 1
- name: task2
debug:
msg: "{{ var1 | select('even') }}" # 0, 2, 4, 4, 2
- name: task3
debug:
msg: "{{ var1 | select('lessthan', 3) }}" # 0, 1, 2, 2, 1
- name: task4
debug:
msg: "{{ var1 | select('equalto', 1) }}" # 1, 1
select 等方法的返回值也可以当做布尔值,比如:
yaml
---
- hosts: all
vars:
var1: ["aaa", "bbb", "ccc"]
tasks:
- name: task1
debug:
msg: "OK"
when: var1 | select('contains', 'aaa') # OK
- name: task2
debug:
msg: "OK"
when: var1 | select('contains', 'Tom') # Skip
- name: task3
debug:
msg: "OK"
when: var1 | reject('contains', 'aaa') # OK
- name: task4
debug:
msg: "OK"
when: var1 | reject('contains', 'Tom') # OK
list的"所有元素都是true"和"至少一个元素是true"
all:所有元素都是Trueany:至少一个元素是True
比如:
yaml
---
- hosts: all
vars:
var1: [True, "{{ 1==1 }}", "!{{ 1==2 }}"]
var2: [True, False]
var3: [False, False, False]
tasks:
- name: task1
debug:
msg: "{{ var1 is all }}" # true
- name: task2
debug:
msg: "{{ var1 is any }}" # true
- name: task3
debug:
msg: "{{ var2 is all }}" # false
- name: task4
debug:
msg: "{{ var2 is any }}" # true
- name: task5
debug:
msg: "{{ var3 is all }}" # false
- name: task6
debug:
msg: "{{ var3 is any }}" # false
路径
directory:是否为目录file:是否为文件link:是否为链接exists: 路径是否存在abs:是否为绝对路径same_file:是否为相同路径的文件mount:是否为mount
比如:
yaml
---
- hosts: all
vars:
var1: "/usr/bin/ps"
tasks:
- name: task1
debug:
msg: "{{ var1 is directory }}" # false
- name: task2
debug:
msg: "{{ var1 is file }}" # true
- name: task3
debug:
msg: "{{ var1 is exists }}" # true
- name: task4
debug:
msg: "{{ var1 is abs }}" # true
human_readable
注:这貌似是转换,并不是test。
human_readable:数值转换为可读格式human_to_bytes:可读格式转换为数值
比如:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "{{ 1 | human_readable }}" # 1.00 Bytes
- name: task2
debug:
msg: "{{ 1 | human_readable(isbits = True) }}" # 1.00 bits
- name: task3
debug:
msg: "{{ 1024 | human_readable }}" # 1.00 KB
- name: task4
debug:
msg: "{{ (1024 * 1024) | human_readable }}" # 1.00 MB
- name: task5
debug:
msg: "{{ (1024 * 1024 * 1024) | human_readable }}" # 1.00 GB
- name: task5
debug:
msg: "{{ (1024 * 1024 * 1024) | human_readable(unit='M') }}" # 1024.00 MB
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "{{'1'|human_to_bytes}}" # 1
- name: task2
debug:
msg: "{{'1KB'|human_to_bytes}}" # 1024
- name: task3
debug:
msg: "{{'1MB'|human_to_bytes}}" # 1048576
- name: task4
debug:
msg: "{{'1GB'|human_to_bytes}}" # 1073741824
- name: task5
debug:
msg: "{{'1Kb'|human_to_bytes(isbits=True)}}" # 1024
task结果
success、succeeded:成功failed:失败changed:变化skipped:略过
比如:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "OK"
register: result1
- name: task2
debug:
msg: "{{ result1 is success }}, {{ result1 is failed }}, {{ result1 is changed }}, {{ result1 is skipped }}"
# True, False, False, False
- name: task3
debug:
msg: "OK"
when: 1 > 2
register: result2
- name: task4
debug:
msg: "{{ result2 is success }}, {{ result2 is failed }}, {{ result2 is changed }}, {{ result2 is skipped }}"
# True, False, False, True
- name: task5
debug:
msg: "{{ var1 }}"
ignore_errors: true
register: result3
- name: task6
debug:
msg: "{{ result3 is success }}, {{ result3 is failed }}, {{ result3 is changed }}, {{ result3 is skipped }}"
# False, True, False, False
- name: task7
shell: "echo OK"
register: result4
- name: task8
debug:
msg: "{{ result4 is success }}, {{ result4 is failed }}, {{ result4 is changed }}, {{ result4 is skipped }}"
# True, False, True, False
类型
你可能想通过 type_debug filter获取类型,然后跟字符串比较,比如:
yaml
---
- hosts: all
tasks:
- name: task1
debug:
msg: "{{ (1 | type_debug) == 'int' }}" # true
但是还有更好的方法,就是使用test来做类型比较。
string:字符串iterable:可迭代sequence:顺序mapping:映射(dictionary)
比如:
yaml
---
- hosts: all
vars:
var1: "aaa"
var2: 123
var3: ["aaa", "bbb", "ccc"]
var4: {name: Tom, age: 20}
tasks:
- name: task1
debug:
msg: "{{ var1 is string }}, {{ var1 is iterable }}, {{ var1 is sequence }}, {{ var1 is mapping }}" # True, True, True, False
- name: task2
debug:
msg: "{{ var2 is string }}, {{ var2 is iterable }}, {{ var2 is sequence }}, {{ var2 is mapping }}" # False, False, False, False
- name: task3
debug:
msg: "{{ var3 is string }}, {{ var3 is iterable }}, {{ var3 is sequence }}, {{ var3 is mapping }}" # False, True, True, False
- name: task4
debug:
msg: "{{ var4 is string }}, {{ var4 is iterable }}, {{ var4 is sequence }}, {{ var4 is mapping }}" # True, True, False
数值类型:
number:数值integer:整数float:浮点数
比如:
yaml
---
- hosts: all
vars:
var1: 123
var2: 45.6
tasks:
- name: task1
debug:
msg: "{{ var1 is number }}, {{ var1 is integer }}, {{ var1 is float }}"
# True, True, False
- name: task2
debug:
msg: "{{ var2 is number }}, {{ var2 is integer }}, {{ var2 is float }}"
# True, False, True
类型转换,比如:
yaml
---
- hosts: all
vars:
var1: "123"
var2: 123
var3: 45.6
tasks:
- name: task1
debug:
msg: "{{ (var1 | int) is integer }}" # true
- name: task2
debug:
msg: "{{ (var1 | float) is float }}" # true
- name: task3
debug:
msg: "{{ (var2 | float) is float }}" # true
- name: task4
debug:
msg: "{{ (var3 | int) is integer }}" # true
- name: task5
debug:
msg: "{{ (var2 | string) is string }}" # true
- name: task6
debug:
msg: "{{ (var3 | string) is string }}" # true
注:把 45.6 转换为 int 类型,结果是45 。
布尔类型:
yestrueTrueTRUEnoNoNOfalseFalseFALSE
比如:
yaml
---
- hosts: all
tasks:
- name: task1
loop:
- yes
- Yes
- YES
- true
- True
- TRUE
- no
- No
- NO
- false
- False
- FALSE
debug:
msg: "{{ item is boolean }}"
本例中,所有item都是布尔类型。
注意:要么全部小写,要么全部大写,要么首字母大写,后面都小写。其它写法比如 FaLSE 不是布尔类型。
注:官网上说 yes 是唯一大小写敏感的:
Note also that
yesis the only case-sensitive variant of these values.
但我试了一下,貌似跟其它几个值也没什么不同。
注:在我的测试中发现, yes 和 no 赋值给变量时,变量会被当做 bool 类型,但是literal的 yes 和 no 并不是 bool 类型:
yaml
---
- hosts: all
vars:
var1: yes
tasks:
- name: task1
debug:
msg: "{{ var1 | type_debug }}" # bool
- name: task2
debug:
msg: "{{ var1 is boolean }}" # true
- name: task3
debug:
msg: "{{ no is boolean }}" # false
- name: task4
debug:
msg: "{{ no | type_debug }}" # AnsibleUndefined
- name: task5
debug:
msg: "{{ true is boolean }}" # true
参考
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_tests.htmlhttps://jinja.palletsprojects.com/en/latest/templates/#jinja-filters.select