Ansible的Jinja test

文章目录

环境

  • 管理节点:Ubuntu 22.04
  • 控制节点:CentOS 8
  • Ansible:2.15.6

概述

Jinja test是指计算一个表达式并返回 truefalse

同所有的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不满足条件。

此外, matchsearchregex 方法都可以添加 ignorecasemultiline 参数。

  • ignorecase :忽略大小写,默认值为False
  • multiline :多行,默认值为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_type
    • loose
    • strict
    • semver / semantic
    • pep440

注意: strictversion_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 :所有元素都是True
  • any :至少一个元素是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结果

  • successsucceeded :成功
  • 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

布尔类型:

  • yes
  • true
  • True
  • TRUE
  • no
  • No
  • NO
  • false
  • False
  • FALSE

比如:

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 yes is the only case-sensitive variant of these values.

但我试了一下,貌似跟其它几个值也没什么不同。

注:在我的测试中发现, yesno 赋值给变量时,变量会被当做 bool 类型,但是literal的 yesno 并不是 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.html
  • https://jinja.palletsprojects.com/en/latest/templates/#jinja-filters.select
相关推荐
明航咨询_贾老师18 小时前
RHCA Ansible高级自动化(DO374)认证信息整理
运维·自动化·ansible·rhca·红帽认证
有毒的教程5 天前
Ansible批量操作自动化完整教程:批量部署服务、配置同步、软件更新实战
运维·自动化·ansible
Hy行者勇哥10 天前
用Cursor智能编写Ansible/Terraform脚本,打通CI/CD链路
ci/cd·ansible·terraform
芷栀夏12 天前
飞牛NAS怎么部署Immich?家庭照片自动备份与远程访问教程
服务器·nginx·ansible
悠然南风22 天前
Ansible常见模块总结及LDAP Role 编写与调试
ansible
祺风挽楠1 个月前
ansible编辑
网络·ansible
芳心粽伙饭1 个月前
Ansible课后作业
ansible
烁3471 个月前
Ansible初识
ansible
烁3471 个月前
Ansible安装部署调试
ansible
烁3471 个月前
Ansible命令
ansible