ansible之playbook-03 templates 使用

Jinja2和template模块的使用

Jinja2简介

Ansible 模板是一种强大的工具,可用于在自动化任务中以动态方式生成配置、文件和其他工件。模板使用 Jinja2 模板语言,这是一种功能强大的模板语言,可用于创建复杂的模板。

Jinja2 模板语言:使用字面量,有下面形式。

  • 字符串:使用单引号或者双引号数字:

  • 整数、浮点数

  • 列表元组:[item1、item2、……]

  • 字典:[key1:value1,key2:value2,……]

  • 布尔型:true/false

  • 算数运算:+ ,-, *, /,/ /,%,**

  • 比较操作:==, !=, >, >=, <, <=

  • 逻辑运算:and、or、not

  • 流表达式:If For When

jinja2的语法结构

playbook中的tasks 必须使用template 模板;

  • {{ }}:用来装载表达式,比如:变量、运算表达式、比较表达式;
  • {% %}:用来装载控制语句,比如 if 控制结构,for循环控制结构;
  • {# #}:用来装载注释,模板文件被渲染后,注释不会包含在最终生成的文件中;
  • jinja2 的文件后缀一般为 .j2

注意:

  • 在jinja2模板文件里使用for语句和if语句,playbook中使用loop语句和when语句。

控制语句

if表达式和注释

if表达式

{{ ‘A’ if 4>1 else ‘B’}}

如果4>1条件为真,输出A,否则输出B

jinja.yml

- name: jinjia模板配置文件
  hosts: all
  tasks:
    - name: jinjia
      template:
        src: host.j2
        dest: /tmp/hosts
cat host.j2

{{ 'A' if 4>1 else 'B'}}

《ansible之playbook-03 templates 使用》

《ansible之playbook-03 templates 使用》

注释

修改配置文件中ansible_managed的值

《ansible之playbook-03 templates 使用》

{# 这是注释,不会输出到文件中  #}
{{ ansible_managed  }}
{{ 'A' if 4<1 else 'B'}}

《ansible之playbook-03 templates 使用》

if条件语句

1.普通if

{% if 条件 %}
...
{% endif %}

2.if…else

语法:
{% if 条件 %}
...
{% else %}
...
{% endif %}

3.if…elif…else

语法:
{% if 条件 %}
...
{% elif 条件N %}
...
{% else %}
...
{% endif %}

if语句测试

---
- name: jinjia模板配置文件
  hosts: all
  vars:
          score: 75
  tasks:
    - name: jinjia
      template:
        src: host.j2
        dest: /tmp/hosts
[root@eab5aec2df6c palybook]# cat host.j2
{# 这是注释,不会输出到文件中  #}
{{ ansible_managed  }}

{% if score >80 %}
优秀
{% elif score>60 %}
及格
{% else %}
不及格
{% endif %}

修改score变量的值

《ansible之playbook-03 templates 使用》

for循环

{% for 迭代变量 in 可迭代对象%}

{{ 迭代变量 }}

{% endfor %}
{% for i in [0,2,4,10,5] %}
{{ i }}
{% endfor %}

《ansible之playbook-03 templates 使用》

{% for key,val in {'name':'shadowwu','age':'29'}.items() %}
{{ key ~ ': '~ val }}
{%endfor%}
python2使用iteritems()函数,python3使用items(),~连接变量与字符串

《ansible之playbook-03 templates 使用》

for循环加if

{% for i in [3,2,5,9,7] if i >= 3 -%}
{{ i~' ' }}
{%- endfor %}
-%}{%-让输出不会换行

《ansible之playbook-03 templates 使用》

for递归操作

{%- set dictionary={ 'name':'shadow','son':{ 'name':'zhangsan','son':{ 'name':'lisi' } } } -%}
{%- for key,val in dictionary.items() recursive -%}
{% if key == 'name' %}
{{ val  -}}
{%- endif -%}
{% if key == 'son' -%}
{{ ' son is '~ val.name }}
{% if  val.son is defined -%}
{{ loop(val.items() ) -}}
{% endif %}
{% endif %}
{%- endfor -%}



在for循环的末尾,我们添加了recursive 修饰符,当for循环中有recursive时,表示这个循环是一个递归的循环,当我们需要在for循环中进行递归时,只要在需要进行递归的地方调用loop函数即可
注意在表达式的两头添加-消除空格换行,Jinja2默认只替换数据,不消除原来的空格和换行

《ansible之playbook-03 templates 使用》

Jinja2提供了两个配置项:lstrip_blockstrim_blocks,它们的意义分别是:

  • (1).lstrip_blocks:设置为true时,会将Jinja2语句块前面的本行前缀空白符号移除
  • (2).trim_blocks:设置为true时,Jinja2语句块后的换行符会被移除掉

对于Ansible的template模块,lstrip_blocks默认设置为False,trim_blocks默认设置为true。也就是说,默认情况下,template模块会将语句块后面的换行符移除掉,但是会保留语句块前的本行前缀空白符号。

---
- name: jinjia模板配置文件
  hosts: all
  vars:
          score: 40
  tasks:
    - name: jinjia
      template:
        src: host.j2
        dest: /tmp/hosts
        lstrip_blocks: true
        trim_blocks: true
{% set dictionary={ 'name':'wuzhaobo','son':{ 'name':'aaa','son':{ 'name':'bbb' } } } %}
{% for key,val in dictionary.items() recursive %}
    {% if key == 'name' %}
{{ val  -}}
   {% endif %}
   {% if key == 'son' %}
{{ ' son is '~ val.name }}
        {% if  val.son is defined %}
{{ loop(val.items() ) }}
        {% endif %}
    {% endif %}
{% endfor %}
注意,有实际输出的行,前面的空格是有效的

for循环+playbook变量组

{% for name in group %}
  number user:{{ loop.index }} ,{{ name }}
{% endfor %}
---
- name: jinjia模板配置文件
  hosts: localhost
  vars:
       group:
         - zhangsan
         - lisi
         - wangwu
       fruit:
         - apple
         - banana
         - orange
  tasks:
    - name: jinjia
      template:
        src: host.j2
        dest: /tmp/hosts
        lstrip_blocks: true
        trim_blocks: true

《ansible之playbook-03 templates 使用》

将group改为groups就是默认的清单文件组

《ansible之playbook-03 templates 使用》

ansible启用break 和continue扩展

默认情况下 ansible是无法使用break和continue,只不过需要修改配置文件/etc/ansible/ansible.cfg

文件151行设置jinja2_extension选项,取消注释,并添加loopcontrols 扩展

jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n,jinja2.ext.loopcontrols

《ansible之playbook-03 templates 使用》

{% for i in [5,2,8,4] %}
  {% if loop.index > 2 %}
    {%break%}
  {%endif%}
  {{i ~'---'~ loop.index}}
{% endfor %}

loop.index从1开始
---
- name: jinjia模板配置文件
  hosts: localhost
  vars:
          score: 40
  tasks:
    - name: jinjia
      template:
        src: host.j2
        dest: /tmp/hosts
        lstrip_blocks: true
        trim_blocks: true

《ansible之playbook-03 templates 使用》

变量过滤器

  • 变量过滤器就是优化输出内容格式,方便阅读。
  • 格式:{{ 变量 | to_json }}
# {{ ansible_managed  }}
{# to_json #}
{% if 1 < 2   %}
{{ ansible_facts['default_ipv4'] | to_json   }}
{% endif %}


# {{ ansible_managed  }}
{# to_nice_json #}
{% if 1 < 2   %}
{{ ansible_facts['default_ipv4'] | to_nice_json   }}
{% endif %}

《ansible之playbook-03 templates 使用》

# {{ ansible_managed  }}
{# to_yaml #}
{% if 1 < 2   %}
{{ ansible_facts['default_ipv4'] |to_yaml  }}
{% endif %}


# {{ ansible_managed  }}
{# to_nice_yaml #}
{% if 1 < 2   %}
{{ ansible_facts['default_ipv4'] | to_nice_yaml   }}
{% endif %}

《ansible之playbook-03 templates 使用》

转义操作

普通转义

在模板文件中,使用“{{ }}”,“{{% %}}”,“{{# #}}”来定义模板,一旦遇到要使用这些特殊字符怎么办,在里面用引号括起来,当中字符处理即可,单引号反斜杠进行转义

# {{ ansible_managed  }}
{{ '{{\'' ~ ' ' ~ '}}' }}
{{ '{{ test abc }}' }}

《ansible之playbook-03 templates 使用》

raw块转义

如果有较多这样的字符需要保持原样,使用引号转义比较麻烦,可以使用“{% raw %}”来实现块的转义

{% raw %}
# {{ ansible_managed  }}
{{ '{{\'' ~ ' ' ~ '}}' }}
{{ '{{ test abc }}' }}
{% endraw %}

《ansible之playbook-03 templates 使用》

宏的使用

jinja2中有类似函数的东西,它叫做”宏”,利用宏,我们可以方便快捷的重复的利用一段内容。

定义时需要使用”{% macro %}“开头,使用”{% endmacro %}”结束,然后在使用的地方进行调用。

简单的无参宏

{% macro testfunc() %}
  some thing
{% endmacro %}

传参数的宏

// 定义了两个变量
{% set myname='shadow' %}
{% set myage=18 %}

{% macro testfunc(a,b) %}

  我的名字是:{{ a }}
  我的年龄是:{{ b }}
{% endmacro %}
//调用宏并传参
{{ testfunc(myname,myage) }}

《ansible之playbook-03 templates 使用》

定义参数的默认值

// 定义了两个变量
{% set myname='shadow' %}
{% set myage=18 %}

{% macro testfunc(a='张三',b=28) %}

  我的名字是:{{ a }}
  我的年龄是:{{ b }}
{% endmacro %}
//调用宏并传参
{{ testfunc() }}
{{ testfunc(myname,myage) }}

可以看到,调用无参的宏使用了默认的值

《ansible之playbook-03 templates 使用》

宏内部特殊变量

在宏的内部,有三个默认的内置特殊变量,分别是:varargs、kwargs、caller

varargs

​ 我们在调用宏时,多传入几个参数,这些额外的参数会作为一个元组织报错在varargs变量上,我们可以通过获取 varargs变量的值,获取到额外的参数

// 定义了两个变量
{% set myname='shadow' %}
{% set myage=18 %}

{% macro testfunc(a='张三',b=28) %}

  我的名字是:{{ a }}
  我的年龄是:{{ b }}
   {% for i in varargs -%}
    {{ i ~' ' }}
  {% endfor %}
{% endmacro %}
//调用宏并传参
{{ testfunc(myname,myage,45,36,28) }}

《ansible之playbook-03 templates 使用》

kwargs

kwargs变量和varargs变量很像,但是kwargs变量值是针对“关键字参数”而言,而varargs变量时针对“非关键字参数”而言

varargs变量的结构是一个元组,kwargs变量的结构是一个字典,kwargs必须在参数末尾添加

// 定义了两个变量
{% set myname='shadow' %}
{% set myage=18 %}

{% macro testfunc(a='张三',b=28) %}

  {{  kwargs }}
  {{  varargs }}
   {% for i in varargs -%}
    {{ i ~' ' }}
  {% endfor %}
{% endmacro %}
//调用宏并传参
{{ testfunc(myname,myage,45,36,wangwu='28',liuxiu=88) }}

《ansible之playbook-03 templates 使用》

caller

caller可以帮助我们将宏中的内容进行替换,当我们要传入大段内容或者复杂的内容时,可以借助caller进行传递。

类似导入代码,使用一下进行定义
{% call 宏 %}
{% endcall %}

在宏中使用{{ caller() }}调用
{% macro 宏() %}
  {{ caller() }}
{% endmacro %}

在一个宏中调用另一个宏,有两种方法

{% macro testfunc() %}
  test
  {{ caller() }}
{% endmacro %}

{% macro testfunc1() %}
  {% for i in range(3) -%}
    {{ i~ ' ' }}
  {%- endfor %}

{% endmacro %}

{% call testfunc() %}
  {{ testfunc1() }}
{% endcall %}
{% macro testfunc() %}
  test
  {{ testfunc1() }}

{% endmacro %}

{% macro testfunc1() %}
  {% for i in range(3) -%}
    {{ i~ ' ' }}
  {%- endfor %}

{% endmacro %}
 {{ testfunc() }}

《ansible之playbook-03 templates 使用》

宏的属性

属性 含义
name 宏的名称
arguments 宏中定义的所有参数名
catch_varargs 宏中如果使用了变量,此值为true
catch_kwargs 宏中使用了关键字,此值为true
caller 宏中使用了caller变量,此值为true
{% macro testfunc(a=44,b=66) %}
  test
  {{ caller() }}
{% endmacro %}

{% macro testfunc1() %}
  {% for i in range(3) -%}
    {{ i~ ' ' }}
  {%- endfor %}

{% endmacro %}

{% call testfunc() %}
  {{ testfunc1() }}
{% endcall %}
  {{ testfunc.name }}
  {{ testfunc.arguments }}
  {{ testfunc.catch_varargs }}
  {{ testfunc.catch_kwargs }}
  {{ testfunc.caller }}

《ansible之playbook-03 templates 使用》

宏的导入

如果宏的定义和宏的使用不在同一个模板文件中,则需要先使用{% from <宏所在文件> import <宏名> %}引入宏的定义再进行使用。

host.j2

/ 定义了两个变量
{% set myname='shadow' %}
{% set myage=18 %}

{% from 'test.j2' import testfunc %}
//调用宏并传参
{{ testfunc(myname,myage) }}

test.j2

{% macro testfunc(a,b) %}

  我的名字是:{{ a }}
  我的年龄是:{{ b }}
{% endmacro %}

《ansible之playbook-03 templates 使用》

问题及解决

jinja2模板空格换行问题

《ansible之playbook-03 templates 使用》

配置lstrip_blocks和trim_blocks为true时,Jinja2语句块后的换行符会被移除掉

模板测试网址

参考

Ansible基础6——文件模块、jinja2模板_ansible修改文件内容 模块-CSDN博客

十二、ansible中的模板 template 模块和 jinja2模板引擎_ansible template-CSDN博客

ansible——template(模板)、角色_ansible template-CSDN博客

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注