Jinja2模版介绍

注:本文demo使用ansible2.7稳定版

ansible基础-变量的「8.2 模版使用变量」章节中关于模版与变量也有所提及,有兴趣的同学可以去回顾一下。

ansible通过Jinja2模版来实现动态表达式和变量的引用,模版的执行都是在ansible控制端完成的,所以理论上python的jinja2模块在控制端存在就能满足需求。

Jinja2模版都可以怎么使用?(分类)

  1. playbook文件中引用Jinja2模版实现动态表达式和变量的引用。
  2. 模版文件(roles/templates/xxx.j2)中引用Jinja2模版实现配置文件内容的拼接。

为什么要使用Jinja2模版?(好处)

  1. 使用过滤器、插件、测试变量等能够非常简单的实现一些小型的函数运算,使部署代码更加简洁高效。
  2. 适用性更加广泛,使部署代码更加灵活。

相比较于python原生的Jinja2模版,ansible扩展了很多过滤器和测试变量,同时也添加了一个新的插件「lookups」。

关于jinja2模版的基础语法和使用,因为篇幅原因,这里不再扩展。本文着重介绍下过滤器。

数据格式化过滤器

过滤器「to_json」「to_yaml」,将变量转换为json和yaml格式

{{ some_variable | to_json }}
{{ some_variable | to_yaml }}

过滤器「to_nice_json」「to_nice_yaml」,将变量转换为更加友好的json和yaml格式

{{ some_variable | to_nice_json }}
{{ some_variable | to_nice_yaml }}

也可以自定义缩进的大小

{{ some_variable | to_nice_json(indent=2) }}
{{ some_variable | to_nice_yaml(indent=8) }}

过滤器「from_json」「from_yaml」,从已经格式化好了的变量读取数据:

{{ some_variable | from_json }}
{{ some_variable | from_yaml }}

「from_json」示例,从file.json文件读取json数据:

tasks:
  - shell: cat /some/path/to/file.json
    register: result
  - set_fact:
      myvar: "{{ result.stdout | from_json }}"

过滤器「from_yaml_all」,用来解析YAML多文档文件

tasks:
  - shell: cat /some/path/to/multidoc-file.yaml
    register: result
 - debug:
     msg: '{{ item }}'
  loop: '{{ result.stdout | from_yaml_all | list }}'

YAML多文档文件指一个文件中包含多个yaml数据文档,例如:

---
part_one: one
...

---
part_two: two
...

变量强制定义过滤器

当我们引用一个未被定义的变量时,ansible默认会报错,当然我们可以通过更改ansible.cfg配置项的方式关闭这种机制(即设置[defaults]字段下的error_on_undefined_vars = False)。

在关闭这个机制的情况下,如果我们想让ansible强制检查某个变量是否定义,可以使用「mandatory」过滤器,写法如下:

{{ variable | mandatory }}

此时,如果变量「variable」被定义了,则引用,否则会报错:

fatal: [node1]: FAILED! => {"msg": "Mandatory variable 'aaa' not defined."}

变量默认值过滤器

「default」过滤器可以为未定义变量设置默认值,类似于roles/defaults/main.yaml里定义的变量,优先级最低(变量优先级参考ansible基础-变量)。

示例如下:

{{ some_variable | default(5) }}

另外,如果我们想将变量参数是false、False和空(None)视为未定义,则必须给defaults过滤器第二参数位置加上「true」:

{{ lookup('env', 'MY_USER') | default('admin', true) }}

上面示例中表示:从环境变量中查找「MU_USER」变量,如果变量值为false、False、空(None)、未定义则将其设置为「admin」。否则引用之前被定义的参数。

可删除参数过滤器

过滤器「omit」:在使用模块的时候,有些参数的存在与否可以取决于变量是否被定义:

- name: touch files with an optional mode
  file: dest={{ item.path }} state=touch mode={{ item.mode | default(omit) }}
  loop:
    - path: /tmp/foo
    - path: /tmp/bar
    - path: /tmp/baz
      mode: "0444"

上面示例表示:变量中如果定义了变量「mode」,file模块则使用mode参数,否则就不使用。

执行结果为「/tmp/foo」和「/tmp/bar」文件使用默认权限,「/tmp/baz」文件使用「0444」权限。

列表过滤器

过滤器「min」,获取最小值元素

{{ list1 | min }}

过滤器「max」,获取最大值元素

{{ [3, 4, 2] | max }}

过滤器「flatten」,扁平化列表元素

{{ [3, [4, 2] ] | flatten }}

转换结果为:

[3, 4, 2 ]

过滤器「flatten」,并且指定级别

{{ [3, [4, [2]] ] | flatten(levels=1) }}

只转换一级的列表元素,结果为:

[3, 4, [2] ]

过滤器「unique」,给列表元素去重

{{ list1 | unique }}

过滤器「union」,合并两个列表后去重

{{ list1 | union(list2) }}

过滤器「intersect」,取两个列表相同的元素

{{ list1 | intersect(list2) }}

过滤器「difference」,去掉list1中与list2相同的元素,返回list1中剩余的元素

{{ list1 | difference(list2) }}

过滤器「symmetric_difference」,去掉list1与list2相同的元素,返回list1和list2剩余元素的集合

{{ list1 | symmetric_difference(list2) }}

操作列表过滤器zip和zip_longest

过滤器「zip」,使两个列表元素递归的融合,生成一个「itertools.izip」生成器对象。

通常后面加上「list」过滤器来使用,表示list1[0]元素与list2[0]元素组合,作为新列表的第一个元素;list1[1]元素与list2[1]元素组合,作为新列表的第二个元素 ,以此类推…… 新列表元素个数以list1和list2中元素个数较少者为准。

如果文字描述不懂,看下面示例就懂了:

- name: give me list combo of two lists
  debug:
   msg: "{{ [1,2,3,4,5] | zip(['a','b','c','d','e','f']) | list }}"

转换结果为:

    "msg": [
        [
            1,
            "a"
        ],
        [
            2,
            "b"
        ],
        [
            3,
            "c"
        ],
        [
            4,
            "d"
        ],
        [
            5,
            "e"
        ]
    ]

过滤器「zip_longest」,与「zip」过滤器合并原理相似,「zip_longest」可以对更多的列表进行操作,且新列表元素个数以被操作列表中元素个数最多者为准,此时就需要指定「fillvalue」参数作为补位填充。示例如下:

{{ [1,2,3] | zip_longest(['a','b','c','d','e','f'], [21, 22, 23], [100,200,300],fillvalue='X') | list }}

转换结果为:

 

 "msg": [
        [
            1,
            "a",
            21,
            100
        ],
        [
            2,
            "b",
            22,
            200
        ],
        [
            3,
            "c",
            23,
            300
        ],
        [
            "X",
            "d",
            "X",
            "X"
        ],
        [
            "X",
            "e",
            "X",
            "X"
        ],
        [
            "X",
            "f",
            "X",
            "X"
        ]
    ]
转换结果

相关文章: