十二、ansible中的模板 template 模块和 jinja2模板引擎

目录

一、ansible中模板的作用

示例1:使用template 管理nginx实战

示例2:测试

二、jinja2模板引擎(一)

1、jinja2的语法结构

2、变量操作示例:

 3、比较表达式示例:

4、逻辑运算示例

5、算数运算符示例:

6、成员运算符示例

7、{# #}用法示例:

三、 jinja2 模板引擎(二)

1、if 控制语句

2、if 表达式

3、for 循环

示例1:

示例2:for 循环操作字典

示例3:for 循环语句和 if 控制语句 结合

示例4:for 循环的递归操作

4、ansible启用break 和continue扩展

5、ansible使用 do 扩展修改列表

四、jinja2模板引擎(三)

1、转义的一些操作

2、宏相关总结

3、宏内部特殊变量

4、宏的属性


一、ansible中模板的作用

        假设,现在需要一次性在10台主机上安装redis,并且让安装后的redis都监听在redis所在主机的非“127.0.0.1”的IP地址上,该怎么办?通过ansible安装10台redis 很容易,但是,安装完成之后,10台主机中redis都是使用默认的监听地址“127.0.0.1”,我们不可能一个一个主机的修改配置文件,这时就需要使用“模板”

        ansible会根据模板文件,为每一台主机生成对应的配置文件,步骤如下:

  1. 找一个现成的redis配置文件,作为“模板”文件,可以从之前安装的主机拷贝一份,也可以从redis的rpm包中提取一份
  2. 修改模板文件,将IP设置部分使用变量进行替换
  3. 使用ansible调用“template”模块,对模板文件进行渲染,根据模板生成每个主机对应的配置文件,并将最终生成的配置文件拷贝到目标主机中。

示例1:使用template 管理nginx实战

1、先在管理端安装nginx
[root@k8s-master-1 include]# yum install nginx

2、查看nginx的配置文件
[root@k8s-master-1 include]# cat /etc/nginx/nginx.conf
worker_processes auto; # 这个参数是work 进程,为自动,是根据系统CPU,自动创建的。查看本机CPU是几核的 使用 “lscpu查看”

[root@k8s-master-1 include]# lscpu
CPU(s):                2  可以看到是2核
所以启动nginx:也会显示2个nginx的work进程

[root@k8s-master-1 include]# systemctl start nginx
[root@k8s-master-1 include]# 
[root@k8s-master-1 include]# ps aux |grep nginx
root       3618  0.0  0.0  41460   944 ?        Ss   14:13   0:00 nginx: master process /usr/sbin/nginx
nginx      3619  0.0  0.0  43932  1948 ?        S    14:13   0:00 nginx: worker process
nginx      3620  0.0  0.0  43932  1948 ?        S    14:13   0:00 nginx: worker process

现在我需要把这个配置文件传到被管理端,并根据被管理端CPU的个数,来生成配置文件,或者说,我想根据CPU数量*2 来生成进程数。
使用template 模板来实现

1、首先准备一个源文件,以j2结尾
[root@k8s-master-1 template]# cp /etc/nginx/nginx.conf ./nginx.conf.j2
[root@k8s-master-1 template]# vim testTemplate.yaml
---
- hosts: web
  remote_user: root

  tasks:
  - name: install nginx
    yum:
      name: nginx
      state: installed

  - name: copy template
    template:
      src: /etc/ansible/test/template/nginx.conf.j2
      dest: /etc/nginx/nginx.conf

  - name: start nginx
    service:
      name: nginx
      state: started
[root@k8s-master-1 template]# ansible-playbook testTemplate.yaml 
TASK [Gathering Facts] ******************************************************
ok: [192.168.134.138]

TASK [install nginx] ******************************************************************************
ok: [192.168.134.138]

TASK [copy template] ******************************************************************************
ok: [192.168.134.138]

TASK [start nginx] ********************************************************************************
changed: [192.168.134.138]

PLAY RECAP *************************************************************************************
192.168.134.138      : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# 执行成功检查是否安装
[root@k8s-master-1 template]# ansible web -m shell -a  'rpm -q nginx'
192.168.134.138 | CHANGED | rc=0 >>
nginx-1.20.1-10.el7.x86_64

# 检查进程  可以看到也有两个进程,因为是2个cpu核数
[root@k8s-master-1 template]# ansible web -m shell -a  'ps -ef |grep nginx'
192.168.134.138 | CHANGED | rc=0 >>

nginx    126236 126234  0 15:24 ?        00:00:00 nginx: worker process
nginx    126237 126234  0 15:24 ?        00:00:00 nginx: worker process

# 检查对用端口是否打开
[root@k8s-master-1 template]# ansible web -m shell -a  'netstat -lnp | grep nginx'
192.168.134.138 | CHANGED | rc=0 >>
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      126234/nginx: maste 
tcp6       0      0 :::80                   :::*                    LISTEN      126234/nginx: maste

可以看到已经有两个进程启动
如果我想让nginx的进程是cpu核数的两倍,怎么实现,如下
1、先查出cpu核数的关键字
[root@k8s-master-1 template]# ansible web -m setup | grep 'cpu'
        "ansible_processor_vcpus": 2, 

2、以变量的方式修改nginx.conf.j2文件
worker_processes {{ ansible_processor_vcpus*2 }};
修改完成之后,怎么同步到被管理端呢?
修改playbook文件,因为之前服务已经启动了,这次只是做修改,修改完成之后,重启生效,所以需要使用 handlers触发器来执行,如下:
  tasks:
  - name: install nginx
    yum:
      name: nginx
      state: installed

  - name: copy template
    template:
      src: /etc/ansible/test/template/nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

  - name: start nginx
    service:
      name: nginx
      state: started

  handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted

执行完,查看nginx进程,就成了4个。
[root@k8s-master-1 template]# ansible web -m shell -a 'ps -ef |grep nginx'
192.168.134.138 | CHANGED | rc=0 >>

nginx      9954   9953  0 15:49 ?        00:00:00 nginx: worker process
nginx      9955   9953  0 15:49 ?        00:00:00 nginx: worker process
nginx      9956   9953  0 15:49 ?        00:00:00 nginx: worker process
nginx      9957   9953  0 15:49 ?        00:00:00 nginx: worker process

使用变量来修改nginx的端口,示例

现在nginx的端口是80,如果我让每台机器的端口都不一样,怎么实现,定义变量
1、在主机清单中,为每个主机定义一个变量
[root@k8s-master-1 ansible]# vim hosts
192.168.134.138 port=9090

2、修改模板文件:nginx.conf.j2
    server {
        listen       {{ port }};
        listen       [::]:{{ port }};
把配置文件设置端口这里 改成引用变量的方式,这样每台主机的端口都会安装变量定义的端口显示

3、执行playbook

4、查看端口
[root@k8s-master-1 template]# ansible web -m shell -a 'netstat -lnp |grep nginx'
192.168.134.138 | CHANGED | rc=0 >>
tcp        0      0 0.0.0.0:9090            0.0.0.0:*               LISTEN      17051/nginx: master 
tcp6       0      0 :::9090                 :::*                    LISTEN      17051/nginx: master 

或者在playbook中定义变量 
vars:
  port: 9090
执行playbook,这样所有主机 的nginx 端口都是9090

示例2:测试

1、创建一个模板文件,模板中值写获取目标主机IP的变量,
[root@k8s-master-1 template]# vim test.j2
{{ ansible_default_ipv4.address }}

2、编写playbook
[root@k8s-master-1 template]# vim test.yaml
---
- hosts: web
  remote_user: root


  tasks:
  - name: test template
    template:
      src: /etc/ansible/test/template/test.j2
      dest: /tmp/test.conf
[root@k8s-master-1 template]# ansible-playbook test.yaml      
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test.conf'
192.168.134.138 | CHANGED | rc=0 >>
192.168.134.138

二、jinja2模板引擎(一)

        jinja2 是 Python的全功能模板引擎。ansible需要使用jinja2 模板来修改被管理主机的配置文件。

        ansible使用jinja2模板,需要借助template 模块实现。

        template模块和copy模块完全一样,都是拷贝文件至远程主机,与copy的语法基本完全一致,区别在于template模块会自动解析要拷贝的文件中变量的值,而copy会原封不动的copy过去。

1、jinja2的语法结构

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

2、变量操作示例:

示例1:
1、创建模板文件
[root@k8s-master-1 template]# vim test.j2
test jinja2 variable
test {{ testvar1 }} test

2、
[root@k8s-master-1 template]# ansible web -m template -e "testvar1=wuzhaobo" -a 'src=/etc/ansible/test/template/test.j2 dest=/tmp/test1'

3、去被控端查看
[root@k8s-node-2 tmp]# cat test1 
test jinja2 variable
test wuzhaobo test

示例2:
创建jinja2 模板文件
[root@k8s-master-1 template]# vim test.j2
{{ teststr }}
{{ testnum }}
{{ testlist[1] }}
{{ testlist1[1] }}
{{ testdic['name'] }}

创建playbook
[root@k8s-master-1 template]# vim testj2.yaml
---
- hosts: web
  remote_user: root

  vars:
    teststr: 'tstr'
    testnum: 18
    testlist: ['aA','bB','cC']
    testlist1:
    - AA
    - BB
    - CC
    testdic:
      name: bob
      age: 18
  tasks:
  - template:
      src: /etc/ansible/test/template/test.j2
      dest: /tmp/test1

执行playbook
[root@k8s-node-2 tmp]# cat test1 
tstr
18
bB
BB
bob

 3、比较表达式示例:

模板文件
[root@k8s-master-1 template]# vim test2.j2
{{ 1 == 1 }}
{{ 2 != 2 }}
{{ 2 > 1 }}
{{ 2 >= 0 }}
{{ 2 < 1 }}
{{ 2 <= 1 }}
[root@k8s-master-1 template]# ansible web -m template -a 'src=/etc/ansible/test/template/test2.j2 dest=/tmp/test1'
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
True
False
True
True
False
False

4、逻辑运算示例

[root@k8s-master-1 template]# vim test3.j2
{{ (2 > 1) or (1 > 2) }}  #逻辑或,有一个成立 即为true
{{ (2 > 1) and (1 > 2) }}
 #逻辑和  必须同时成立,即为true

{{ not true }} # not 取反


{{ not False }}
[root@k8s-master-1 template]# ansible web -m template -a 'src=/etc/ansible/test/template/test3.j2 dest=/tmp/test1'
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
True
False
 

False

True

5、算数运算符示例:

[root@k8s-master-1 template]# vim test4.j2
{{ 3 + 2 }}  // 求和
{{ 3 - 4 }}
   // 减法
{{ 3 * 5 }}
  // 乘法
{{ 2 ** 3 }}
  //幂次方
{{ 7 / 5 }}
  //除法
{{ 7 // 5 }}
//除法 取整数
{{ 17 % 5 }}  //除法 取余数
[root@k8s-master-1 template]# ansible web -m template -a 'src=/etc/ansible/test/template/test4.j2 dest=/tmp/test1'
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
5
-1
15
8
1.4
1
2

6、成员运算符示例

[root@k8s-master-1 template]# vim test5.j2
{{ 1 in [1,2,3,4] }}   // 1 在 列表中
{{ 1 not in [1,2,3,4] }}  // 1  不在列表中
[root@k8s-master-1 template]# ansible web -m template -a 'src=/etc/ansible/test/template/test5.j2 dest=/tmp/test1'
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
True
False

7、{# #}用法示例:

        使用"{# #}“包含注释信息,所以,如果我们需要在模板文件中对某些配置进行注释,则可以将注释信息写入到”{# #}"中,示例如下:

[root@k8s-master-1 template]# vim test6.j2
jinja2 test
{# 这是一行注释信息 #}
jinja2 test
{#
这是多行注释信息,
模板被渲染以后,
最终的文件中不会包含这些信息
#}
jinja2 test
[root@k8s-master-1 template]# ansible web -m template -a 'src=/etc/ansible/test/template/test6.j2 dest=/tmp/test1'
[root@k8s-master-1 template]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
jinja2 test
jinja2 test
jinja2 test
上述示例表示
{# #}中的注释内容不会在最终生成的文件中显示。

三、 jinja2 模板引擎(二)

        在jinja2 中 {% %}:对控制语句进行包含,比如使用“if”控制语句,“for”循环控制语句等,都需要包含{% %}中。

1、if 控制语句

语法:

{% if 条件 %}
    ***

    ***

{% endif %}

示例:
[root@k8s-master-1 jinja2]# vim test1.j2
{% if num>3 %}
greater than 3
{% endif %}
[root@k8s-master-1 jinja2]# vim temptest1.yaml
---
- hosts: web
  remote_user: root

  tasks:
  - name: test if
    template:
      src: /etc/ansible/test/jinja2/test1.j2
      dest: /tmp/test1
    vars:
      num: 5
[root@k8s-master-1 jinja2]# ansible-playbook temptest1.yaml
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
greater than 3
如果传入的变量小于3 则不显示任何信息,可以使用else          

if...else...结构

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

if...else if 结构

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

2、if 表达式

        if 不仅有控制语句,还有 if 表达式,利用 if 表达式,可以实现三元运算的效果

        if表达式的语法:

        if else

        示例:

[root@k8s-master-1 jinja2]# vim test2.j2
{{ 'a' if 2>1 else 'b'}}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test2.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
a
如果2>1这个条件为真,则使用’a’,如果2>1这个条件不成立,则使用’b’,而2必定大于1,所以条件成立,最终使用’a’

3、for 循环

语法:

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

        {{ 迭代变量 }}

        {% endfor %}

示例1:
1、实现简单的for 循环
{% for i in [1,2,5,7,4] %}
{{ i }}
{% endfor %}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test3.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
1
2
5
7
4
可以看到 输出的结果会自动换行,如果不想换行 使用“ -”
在for的结束控制符"%}“之前添加了减号”-"
在endfor的开始控制符"{%“之后添加到了减号”-"
{% for i in [1,2,5,7,4] -%}
{{ i }}
{%- endfor %}
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
12574
可以看到输出的结果都连载一起 不方便看,可以加个空格
{% for i in [1,2,5,7,4] -%}
{{ i }}{{ '' }}
或者 {{ i~ ' ' }}
{%- endfor %}
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
1 2 5 7 4
示例2:for 循环操作字典
[root@k8s-master-1 jinja2]# vim test4.j2
{% for key,val in {'name':'wuzhaobo','age':'29'}.iteritems() %}
{{ key ~ ': '~ val }}
{%endfor%}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test4.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
age: 29
name: wuzhaobo
iteritems()函数是Python 2中用于字典对象的方法,它返回一个迭代器,该迭代器将按键值对的形式依次返回字典中的元素。
然而,在Python 3中,iteritems()方法已被移除,因为字典对象本身就是可迭代的。取而代之的是items()方法,它在Python 3中扮演与iteritems()类似的角色。
如上所示,在循环操作字典时,先使用 iteritems 函数对字典进行处理,然后使用key和val两个变量作为迭代变量,分别用于存放字典中键值对的"键"和"值",所以,直接输出两个变量的值即可,key和val是我随意起的变量名,你可以自己定义这两个迭代变量的名称,而且,上例中的iteritems函数也可以替换成items函数,但是推荐使用 iteritems 函数。

for循环 还有一些内置变量和函数 在这里不做演示

示例3:for 循环语句和 if 控制语句 结合
[root@k8s-master-1 jinja2]# vim test5.j2
{% for i in [1,3,5,7,9] if i >= 3 -%}
{{ i~' ' }}
{% else %}
No greater than or equal to 3
{%- endfor %}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test5.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
3 5 7 9

for循环中没有使用if内联表达式时,也可以使用else块
示例4:for 循环的递归操作
{% set dictionary={ 'name':'wuzhaobo','son':{ 'name':'aaa','son':{ 'name':'bbb' } } } %}

{% for key,val in dictionary.items() recursive %}
  {% if key == 'name' %}
   {% set fathername = val %}
  {% endif %}

  {% if key == 'son' %}
    {{ fathername ~"s son is" ~ ' ' ~ val.name }}
    {{ loop(val.items() ) }}
  {% endif %}
{% endfor %}
在操作字典时,使用了iteritems函数,在for循环的末尾,我们添加了recursive 修饰符,当for循环中有recursive时,
表示这个循环是一个递归的循环,当我们需要在for循环中进行递归时,只要在需要进行递归的地方调用loop函数即可,
上例中的"loop( value.iteritems() )"即为调用递归的部分,由于value也是一个字典,所以需要使用iteritems函数进行处理。
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
  
      wuzhaobos son is aaa
 
      aaas son is bbb

4、ansible启用break 和continue扩展

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

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

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

        完成上述配置步骤即可在for循环中使用break和continue控制语句,与其他语言一样,break表示结束整个循环,continue表示结束当次循环。

break示例:

[root@k8s-master-1 jinja2]# vim test7.j2
{% for i in [7,1,5,3,9] %}
  {% if loop.index > 3 %}
    {%break%}
  {%endif%}
  {{i ~'---'~ loop.index}}
{% endfor %}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test7.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
    7---1
    1---2
    5---3

5、ansible使用 do 扩展修改列表

        如果我们想要在jinja2中修改列表中的内容,则需要借助jinja2的另一个扩展,这个扩展的名字就是"do",刚才修改jinja2_extensions配置的时候,默认就有这个扩展,它的名字是jinja2.ext.do

示例:

[root@k8s-master-1 jinja2]# vim test8.j2
{% set testlist=[3,5] %}
 
{% for i in testlist  -%}
  {{ i ~ ' ' }}
{%- endfor %}
 
{%do testlist.append(7)%}
 
{% for i in testlist  -%}
  {{ i ~ ' ' }}
{%- endfor %}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test8.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
  3  5   3  5  7
使用 append()方法 追加元素

四、jinja2模板引擎(三)

1、转义的一些操作

        上边我们讲过jinja2 的基础用法,也就是说,在模板文件中,一旦遇到“{{ }}”,“{{% %}}”,“{{# #}}”,jinja2 模板就会进项相应的处理,最终生成的文件内容中并不会包含这些字符,但是,有时候想要包含这些字符怎么办嘞?就需要用到 转义

  • 引号转义

    最简单的方法就是直接在“{{}}" 中使用引号,将这类字符引起来,当做字符串处理

    示例:

[root@k8s-master-1 jinja2]# vim test7.j2
{{ '{{' ~ ' ' ~ '}}' }}
{{ '{{ test abc }}' }}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test7.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
{{ }}
{{ test abc }}
  • raw块转义

        如果有较多这样的字符需要保持原样,使用上边引号转义的话,比较麻烦,因此需要借助“{% raw %}”来实现块的转义

示例:

[root@k8s-master-1 jinja2]# vim test8.j2 
{% raw %}
  {% for key,val in {'name':'wuzhaobo','age':'29'}.iteritems() %}
  {{ key ~ ': '~ val }}
  {%endfor%}
{% endraw %}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test8.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>

  {% for key,val in {'name':'wuzhaobo','age':'29'}.iteritems() %}
  {{ key ~ ': '~ val }}
  {%endfor%}

2、宏相关总结

  • 宏的使用

        jinja2中也有类似函数的东西,它叫做"宏",利用宏,我们可以方便快捷的重复的利用一段内容。定义宏时需要使用

        "{% macro %}“开头,使用”{% endmacro %}"结束,如果想要真正的使用宏,还需要引用它,下例的最后一行就是在调用testfunc宏。

示例:

[root@k8s-master-1 jinja2]# vim test9_func.j2
{% macro testfunc() %}
  test string
{% endmacro %}

{{ testfunc() }}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test9_func.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>

  test string
  • 传参数的宏

示例:

[root@k8s-master-1 jinja2]# vim test9_func.j2
// 定义了两个变量
{% set testvar1='test1' %}
{% set testvar2=2 %}

{% macro testfunc(a,b) %}
  test string
  {{ a }}
  {{ b }}
{% endmacro %}
//把这两个变量作为参数,传到宏里边
{{ testfunc(testvar1,testvar2) }}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test9_func.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>


  test string
  test1
  2
  • 宏使用参数的默认值

        上边示例有一个很明显的问题,就是如果宏在定义的时候有对应的参数,在调用宏时就必须传入对应的参数,否则就会报错,其实,我们还可以在定义宏时,为对应的参数指定一个默认值,当在调用宏时没有显式的指定对应的参数时,宏就使用参数的默认值,

示例:

[root@k8s-master-1 jinja2]# vim test9_func.j2
{% macro testfunc(a=3,b=4) %}
  test string
  {{ a }}
  {{ b }}
{% endmacro %}

{{ testfunc() }}
{{ testfunc(1,2) }}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test9_func.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>


  test string
  3
  4

  test string
  1
  2
// 如上 我们在定义宏时,为a 和 b 参数定义了默认值3,4,然后调用了两次testfunc宏,第一次没有传入对应参数,使用了默认值,第二次调用宏时传入了对应参数,于是使用了传入的值

3、宏内部特殊变量

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

  1. varargs

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

    示例:

    [root@k8s-master-1 jinja2]# vim test10_func.j2
    {% macro testfunc(a=1,b=2) %}
      test
      {{ a }}
      {{ b }}
      {{ varargs }}
    
    {% endmacro %}
    {{ testfunc('a','b','c','d','e','f')}}
    [root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test10_func.j2 dest=/tmp/test1'
    [root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
    192.168.134.138 | CHANGED | rc=0 >>
      test
      a
      b
      ('c', 'd', 'e', 'f')
      
    既然varargs变量里面存储了多余的参数,那么如果宏压根就没有定义任何参数,我们却传入了一些参数,那么这些所有传入的参数都是“多余”出的参数,也可以使用varargs变量处理这些参数,
    {% macro testfunc() %}
      {% for i in varargs -%}
        {{ i ~' ' }}
    
      {%- endfor %}
    
    {% endmacro %}
    
    {{ testfunc('a','b','c','d','e','f')}}
    [root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test10_func.j2 dest=/tmp/test1'
    [root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
    192.168.134.138 | CHANGED | rc=0 >>
    
      a b c d e f
  2. kwargs

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

    示例:

    [root@k8s-master-1 jinja2]# vim test11_func.j2
    {% macro testfunc(input=1) %}
      test
      {{ input }}
      {{ varargs }}
      {{ kwargs }}
    
    {% endmacro %}
    
    {{ testfunc('a','b','test',testkey='abc') }}
    [root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test11_func.j2 dest=/tmp/test1'
    [root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
    192.168.134.138 | CHANGED | rc=0 >>
    
      test
      a
      ('b', 'test')
      {'testkey': 'abc'}
    如上例所示,我们在定义宏时,定义了一个参数input,并且设置了默认值,在宏中,我们输出了varargs变量和kwargs变量,在调用宏时,我们多传入了3个参数,最后一个参数是一个带有参数名的关键字参数,
    多余的非关键字参数都会保存在varargs变量中,varargs变量的结构是一个元组,而多余的关键字参数都会保存在kwargs变量中,kwargs变量的结构是一个字典,kwargs变量实现的效果与Python的关键字参数效果类似。
  3. caller

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

        如果想要替换testfunc宏中的”{{caller()}}"部分,则需要在调用testfunc宏时,使用"call语句块"进行调用,

    示例:

    [root@k8s-master-1 jinja2]# vim test12_func.j2
    {% macro testfunc() %}
      test
      {{ caller() }}
    
    {% endmacro %}
    
    {% call testfunc() %}
      asd
      zxc
    {% endcall %}
    [root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test12_func.j2 dest=/tmp/test1'
    [root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
    192.168.134.138 | CHANGED | rc=0 >>
    
      test
        asd
      zxc
    2、caller其实还能够帮助我们在一个宏中调用另一个宏。
    {% macro testfunc() %}
      test
      {{ caller() }}
      
    {% endmacro %}
    
    {% macro testfunc1() %}
      {% for i in range(3) -%}
        {{ i~ ' ' }}
      {%- endfor %}
    
    {% endmacro %}
    
    
    
    {% call testfunc() %}
      {{ testfunc1() }}
    {% endcall %}
    [root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test12_func.j2 dest=/tmp/test1'
    [root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
    192.168.134.138 | CHANGED | rc=0 >>
    
      test
          0 1 2
    如上例所示,我们定义了两个宏,testfunc和testfunc1,我们将testfunc1传递到了testfunc中。
    

    4、宏的属性

宏属性

含义

name

宏的名称

arguments

宏中定义的所有参数名

defaults

宏中定义的参数,如果有默认值

catch_varargs

宏中如果使用了变量,此值为true

catch_kwargs

宏中使用了关键字,此值为true

caller

宏中使用了caller变量,此值为true

 示例:

{% macro test1(a,b,c=3,d=4) %}
  {{ a }}
  {{ b }}
  {{ c }}
  {{ d }}

{% endmacro %}
  {{ test1.name }}
  {{ test1.arguments }}
  {{ test1.defaults }}
  {{ test1.catch_varargs }}
  {{ test1.catch_kwargs }}
  {{ test1.caller }}
[root@k8s-master-1 jinja2]# ansible web -m template -a 'src=/etc/ansible/test/jinja2/test13_func.j2 dest=/tmp/test1'
[root@k8s-master-1 jinja2]# ansible web -m shell -a 'cat /tmp/test1'
192.168.134.138 | CHANGED | rc=0 >>
  test1
  ('a', 'b', 'c', 'd')
  (3, 4)
  False
  False
  False

  • 47
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁华依在

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值