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
相关推荐
leo__5201 天前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
风清再凯6 天前
自动化工具ansible,以及playbook剧本
运维·自动化·ansible
IT乌鸦坐飞机6 天前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
遇见火星19 天前
如何使用Ansible一键部署MinIO集群?
ansible
粥周粥19 天前
ANSIBLE
ansible
码农101号19 天前
Linux中ansible模块补充和playbook讲解
linux·运维·ansible
码农101号19 天前
Linux的Ansible软件基础使用讲解和ssh远程连接
ansible
烟雨书信21 天前
ANSIBLE运维自动化管理端部署
运维·自动化·ansible
碎碎-li21 天前
ANSIBLE(运维自动化)
运维·自动化·ansible
@donshu@24 天前
Linux运维-ansible-python开发-获取inventroy信息
linux·运维·ansible