ansible11:jinja2模板

简单介绍

  比如现在有需求安装10台redis,结合前面的知识,简单,写一个ansible-playnook配合inventory就可以实现,但是redis启动后端口默认是监听在127.0.0.1上面的,这样使得其他主机的程序无法调用redis,但是又不能一台一台修改配置文件中的bind吧,这种情况就有了模板的解决方案,大致可以分为三步:

  1. 从别的redis程序中或者网上找一份配置文件,作为“模板”文件。

  2. 修改模板文件,将bind配置项中的IP设为变量。

  3. 使用ansible调用“template”模块,对模板文件进行渲染,根据模板生成每个主机对应的配置文件,并将最终生成的配置文件拷贝至目标主机中,启动redis。

    # 举例对比理解。
      0 15:16:32 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat /etc/ansible/hosts
    ck-master	ansible_host=172.16.2.9
    ck-node1	ansible_host=172.16.15.21
    ck-node2	ansible_host=172.16.15.22
    ck-node3	ansible_host=172.16.15.23
      0 15:16:39 root@ck-ansible,172.16.2.9:/server/ops_ansible # grep bind redis.conf 
    bind {{ansible_host}}
      0 15:16:42 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat redis.yaml 
    ---
    - hosts: ck-node1
      tasks:
      - name: deploy redis
        yum: 
          name: redis
      - name: copy template
        template: 
          src: /server/ops_ansible/redis.conf
          dest: /etc/redis.conf
          backup: yes
      0 15:16:48 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible-playbook redis.yaml
    # 在目标主机上验证一下。
      0 15:15:15 root@ck-node1,172.16.15.21:~ # grep bind /etc/redis.conf
    bind 172.16.15.21
    

语法说明

{{ }}

  1. 说明:用来装载表达式,比如变量、运算、比较等,前面文章已经用的很多了哈。

  2. 举例:

      0 15:47:04 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test.j2 
    # test jinja2 var
    The value of this variable is {{ var1 }}
    
    # test jinja2 compare and operation
    {{ 1 == 1 }}
    {{ 2 != 2 }}
    {{ 2 > 1 }}
    {{ 2 >= 1 }}
    {{ 2 < 1 }}
    {{ 2 <= 1 }}
    {{ (2 > 1) or (1 > 2) }}
    {{ (2 > 1) and (1 > 2) }}
    {{ not true }}
    {{ not True }}
    {{ not false }}
    {{ not False }}
    {{ 3 + 2 }}
    {{ 3 - 4 }}
    {{ 3 * 5 }}
    {{ 2 ** 3 }}
    {{ 7 / 5 }}
    {{ 7 // 5 }}
    {{ 17 % 5 }}
    
    # python data type
    ## str
    {{ 'testString' }}
    {{ "testString" }}
    ## num
    {{ 15 }}
    {{ 18.8 }}
    ## list
    {{ ['Aa','Bb','Cc','Dd'] }}
    {{ ['Aa','Bb','Cc','Dd'].1 }}
    {{ ['Aa','Bb','Cc','Dd'][1] }}
    ## tuple
    {{ ('Aa','Bb','Cc','Dd') }}
    {{ ('Aa','Bb','Cc','Dd').0 }}
    {{ ('Aa','Bb','Cc','Dd')[0] }}
    ## dic
    {{ {'name':'bob','age':18} }}
    {{ {'name':'bob','age':18}.name }}
    {{ {'name':'bob','age':18}['name'] }}
    ## bool
    {{ True }}
    {{ true }}
    {{ False }}
    {{ false }}
      0 15:41:44 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -e 'var1=wula' -a 'src=test.j2 dest=/opt/test'
    # jinja2本身是基于python的模板引擎,所以python的基础数据类型都可以包含在”{{ }}”中。
    # 前文中讲的tests判断、lookup插件、过滤器也可以在{{ }}中使用。
    

{# #}

  1. 说明:用来装载注释信息。模板文件被渲染后,注释不会包含在最终生成的文件中。

  2. 举例:

    # 把第一例中的注释修改为{#  #}写法。
      0 15:54:19 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test.j2
    {#test jinja2 var#}
    The value of this variable is {{ var1 }}
    
    {#
    注释1
    注释2
    注释3
    #}
    

{% %}

if控制语句

  1. 语法。

    # 语法一
    {% if 条件 %}
    ...
    {% endif %}
    # 语法二
    {% if 条件一 %}
    ...
    {% elif 条件N %}
    ...
    {% endif %}
    # 语法三
    {% if 条件 %}
    ...
    {% else %}
    ...
    {% endif %}
    # 语法四
    {% if 条件一 %}
    ...
    {% elif 条件N %}
    ...
    {% else %}
    ...
    {% endif %}
    
  2. 举例。

    # 举例1
      0 16:13:07 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test.j2 
    {% if testnum > 3 %}
    greater than 3
    {% endif %}
      0 16:13:10 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test.yaml 
    ---
    - hosts: ck-node1
      vars:
        testnum: 5
      tasks:
      - template:
          src: test.j2
          dest: /opt/test
      0 16:13:15 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible-playbook test.yaml
    

if表达式

  1. 说明:可以实现类似三元运算的效果。条件成立输出a,不成立输出b。

  2. 举例。

      0 16:16:05 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test.j2
    {{ 'a' if 2>1 else 'b' }}
      0 16:16:08 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test.j2 dest=/opt/test'
    

for循环

  1. 语法:

    {% for 迭代变量 in 可迭代对象 %}
    {{ 迭代变量 }}
    {% endfor %}
    
  2. for循环指定分隔符。

    # 例1:循环操作列表
      0 16:28:47 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2
    {% for n in [3,1,7,8,2] %}
      {{ n }}		# 这里空两个空格,结果中也会空两个空格。
    {% endfor %}
      0 16:28:53 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test1.j2 dest=/opt/test'
    # 例2: 取消例1执行结果的自动换行。
      0 16:31:02 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test2.j2
    {% for n in [3,1,7,8,2] -%}
    {{ n }}
    {%- endfor %}、
    # 例3:取消例1执行结果的自动换行,并指定分隔符
      0 16:37:03 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test3.j2
    {% for n in [3,1,7,8,2] -%}
    {{ n ~ ',' }}		# ~作为连接符。
    {%- endfor %}
    # 例4:循环操作字典。
      0 16:40:53 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test4.j2
    {% for k,v in {'name': 'zoe','age': 18}.iteritems() %}	# 字典需要调用iteritems函数处理。
    {{ k ~ ': ' ~ v }}
    {% endfor %}
    
  3. loop.index:打印整个循环的第几次循环,从序号1开始。

      0 16:45:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test5.j2
    {% for n in [3,1,7,8,2] %}
    {{ n ~ '--' ~ loop.index }}
    {% endfor %}
    
  4. loop.index0:打印整个循环的第几次循环,从序号0开始。

  5. loop.revindex:打印当前循环次距离整个循环结束还剩几次,到序号1结束。

      0 17:07:05 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test6.j2
    {% for n in [3,1,7,8,2] %}
    {{ n ~ '--' ~ loop.revindex }}
    {% endfor %}
    
  6. loop.revindex0:打印当前循环次距离整个循环结束还剩几次,到序号0结束。

  7. range:范围取值(顾头不顾尾,不会取最后一个数值)。

    # 例1:
    {% for n in range(5) %}
    {{ n }}
    {% endfor %}
    # 例2:
      0 17:20:45 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test8.j2
    {% for n in range(1,5,2) %}		# 前面有说过,三个数值分别是起始、结束、步长。
    {{ n }}
    {% endfor %}
    
  8. for结合if实现过滤。

    # 写法1:
      0 17:24:00 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test9.j2
    {% for n in [1,5,2,8,6] if n>5 %}
    {{ n }}
    {% endfor %}
    # 写法2:
      0 17:26:37 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test10.j2
    {% for n in [1,5,2,8,6] %}
    {% if n>5 %}
    {{ n }}
    {% endif %}
    {% endfor %}
    # 从表面上看两种写法的结果一样,但是执行过程是有区别的,我们可以用loop.index查看一下。
      0 18:11:57 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test11.j2
    {% for n in [1,5,2,8,6] if n>5 %}
    {{ n ~ '--' ~ loop.index }}
    {% endfor %}
    
    {% for n in [1,5,2,8,6] %}
    {% if n>5 %}
    {{ n ~ '--' ~ loop.index }}
    {% endif %}
    {% endfor %}
      0 18:13:01 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test11.j2 dest=/opt/test'
      0 18:13:17 root@ck-node1,172.16.15.21:~ # cat /opt/test 
    8--1
    6--2
    
    8--4
    6--5
    # 从结果可以看出,当第一种for循环内联if表达式时,不满足条件时loop.index是不会计算的;而第二种在for循环中单独使用if表达式时,不满足条件也会被loop.index计算。
    
  9. for+if else

      0 18:17:57 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test12.j2
    {% for n in [1,5,2,8,6] if n>9 %}
    {{ n }}
    {% else %}
    no one is greater than 9
    {% endfor %}
    
  10. for else

    # 当列表为空时,才会渲染else的内容。
      0 18:23:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test13.j2
    {% set userlist=[] %}	# 定义变量。
    {% for u in userlist %}
    {{ u }}
    {% else %}
    no one
    {% endfor %}
    
  11. for循环递归。

      0 18:38:13 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test14.j2 
    {% set userinfo={'name': 'zoe','son': {'name': 'bob','son': {'name': 'tom'}}} %}
    {% for k,v in userinfo.iteritems() recursive %}
    {% if k == 'name' %}
    {% set fathername=v %}
    {% endif %}
    
    {% if k == 'son' %}
    {{ fathername ~ "'s son is " ~ v.name}}
    {{ loop( v.iteritems() ) }}
    {% endif %}
    {% endfor %}
    
  12. loop.cycle:与指定的值轮询结合。

      0 18:46:43 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test15.j2 
    {% set userlist=['bob','zoe','selina','tom'] %}
    {% for u in userlist %}
    {{ u ~ '--' ~ loop.cycle('team1','team2') }}
    {% endfor %}
    
  13. 默认情况下,jinja2中的for循环无法使用break或continue,是因为jinja2把这种操作归纳在了一些扩展中,启用相应扩展即可使用相应功能。

    # 修改配置文件启用jinja2扩展,添加loopcontrols扩展即可在循环中使用break和continue。
      0 18:57:37 root@ck-ansible,172.16.2.9:/server/ops_ansible # vim /etc/ansible/ansible.cfg
    jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n,jinja2.ext.loopcontrols
      0 19:13:56 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test16.j2
    {% for n in [1,5,2,8,6] %}
    {% if loop.index>4 %}
    {% break %}
    {% endif %}
    {{ n ~ '--' ~ loop.index }}
    {% endfor %}
    
  14. for+continue:跳过偶数次的循环

      0 19:34:41 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test16.j2
    {% for n in [1,5,2,8,6] %}
    {% if loop.index is even %}
    {% continue %}
    {% endif %}
    {{ n ~ '--' ~ loop.index }}
    {% endfor %}
    
  15. for+break。

    # 3次迭代以后的元素不再处理。
      0 19:36:12 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test17.j2
    {% for n in [1,5,2,8,6] %}
    {% if loop.index>3 %}
    {% break %}
    {% endif %}
    {{ n ~ '--' ~ loop.index }}
    {% endfor %}
    
  16. for+do扩展:修改列表内容。ansible.cfg默认就包含do扩展,启用即可。

      0 19:43:31 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test18.j2
    {% set numlist=[1,3,5] %}
    
    {% for n in numlist %}
    {{ n }}
    {% endfor %}
    
    {%do numlist.append(7)%}		# append:追加到末尾。
    
    {% for n in numlist  %}
    {{n}}
    {% endfor %}
    

转义相关

  1. raw:上面有说{{}}、{##}、{%%}都会被jinja2引擎识别并处理,但有些场景就需要结果中包含这些特殊符号呢?那就需要借助raw转义了。

      0 19:51:33 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2 
    {% raw %}
    {{ test }}
    {% test %}
    {# test #}
    {% if %}
    {% endfor %}
    {% endraw %}
    
  2. variable_start_string和variable_end_string:替换{{ }}中的“{{”和“}}”。

      0 20:07:54 root@ck-ansible,172.16.2.9:/server/ops_ansible # ll
    总用量 8
    -rw-r--r-- 1 root root 78 10月 26 19:51 test1.j2
    -rw-r--r-- 1 root root 85 10月 26 20:07 test2.j2
      0 20:07:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test2.j2 dest=/opt/test variable_start_string="((" variable_end_string="))"'
    
  3. block_start_string和block_start_string:替换{% %}中的“{%”和“%}”

宏相关

  jinja2中的函数也成为宏,利用宏可以重复利用一段内容,jinja2宏也可以传入参数,一些涉及到的概念说明(我不确定ansible中是不是有如下概念,只是拿了python的概念到这来方便理解):

  • 形参:在宏(函数)定义阶段括号内定义的参数,称之为形式参数,简称形参。形参的本质是变量名。
  • 位置形参:在宏定义阶段,按从左到右的顺序依次定义的形参,称之为位置形参。但凡是按照位置定义的形参,都必须被传值,而且一定数量对等。
  • 默认形参:在函数定义阶段就为形参赋值,该形参称为默认形参。
  • 实参:在函数调用阶段括号内传入的值,称之为实际参数,简称实参。实参的本质是变量值。
  • 位置实参:在函数调用阶段,按从左到右的顺序依次定义的实参,称之为位置实参。按照位置为对应的形参依次传值。
  • 关键字实参:在调用函数时,按照key=value形式为指定的参数传值,称为关键字实参。

  1. 定义一个简单的宏。

      0 20:15:31 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2
    {% macro testfunc() %}		# 定义宏
    test string					# 宏内容
    {% endmacro %}				# 定义宏
     
    {{ testfunc() }}			# 调用宏
    
  2. 传参宏。

      0 20:19:31 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test2.j2
    {% macro testfunc(v1=111) %}	# 定义宏时设置默认形参是111。
    test string
    {{ v1 }}  
    {% endmacro %}
     
    {{ testfunc() }}		# 不传参打印默认形参。
    {{ testfunc(666) }}		# 打印传参。
    
  3. 多个传参时,位置实参必须放在关键字实参的前面,与位置形参一一对应,否则会打印错误结果。

      0 20:29:27 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test3.j2
    {% macro testfunc(v1,v2,v3=3,v5=5) %}
    test string
    {{ v1 }}
    {{ v2 }}
    {{ v3 }}
    {{ v5 }}
    {% endmacro %}
     
    {{ testfunc('a','b') }}
    # 可见:调用宏时传入的值会按照参数顺序进行对应赋值。
    
  4. 指定传参:位置实参必须放在关键字实参的前面,与位置形参一一对应。

      0 21:35:19 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test4.j2
    {% macro testfunc(v1,v2,v3=3,v5=5) %}
    test string
    {{ v1 }}
    {{ v2 }}
    {{ v3 }}
    {{ v5 }}
    {% endmacro %}
     
    {{ testfunc('a','b',v5=777) }}
    

内置变量

  1. varargs:将溢出的非关键字传参全部接收,以元组类型存储在varargs变量中(类似python的*args)。

    # 例1
      0 21:51:53 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2
    {% macro testfunc(testarg1=1,testarg2=2) %}
      test string
      {{testarg1}}
      {{testarg2}}
      {{varargs}}
    {% endmacro %}
     
    {{ testfunc('a','b','c','d','e') }}
    # 例2:没有定义参数,使用宏时可以传入任意值。
      0 22:09:05 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test2.j2
    {% macro testfunc() %}
    test string
    {%for i in varargs%}
    {{i}}
    {%endfor%}
    {{ '--------' }}
    {% endmacro %}
     
    {{ testfunc() }}
    {{ testfunc(1,2,3) }}
    
  2. kwargs:将溢出的关键字传参全部接收,以字典类型存储在wkargs变量中(类似python的*kwargs)。

      0 11:28:11 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test3.j2
    {% macro testfunc(v1=555) %}
    test string
    {{kwargs}}
    {% endmacro %}
     
    {{ testfunc(666,testvar='abc') }}
    
  3. caller:说是caller变量,不如说是caller方法。使用caller方法可以替换宏中的内容。

      0 11:30:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test4.j2
    {% macro testfunc() %}
    test string
    {{caller()}}
    {% endmacro %}
    
    {%call testfunc() %}
    wula
    {% endcall %}
    # 可以理解为把caller空变量放在testfunc函数中,在下面使用call方法重新复制给了caller变量,实现改变宏内容的操作。
    
  4. 使用caller在一个宏中调用另外一个宏。

      0 13:24:29 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test5.j2
    {% macro testfunc1() %}
    test string
    {{caller()}}
    {% endmacro %}
     
    {% macro testfunc2() %}
    {% for i in range(3) %}
    {{i}}
    {% endfor %}
    {% endmacro %}
    
    {%call testfunc1()%}
    {{testfunc2()}}
    {%endcall%}
    
  5. caller传参。

      0 13:35:58 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test6.j2 
    {% macro testfunc() %}
    test string
    {{caller('wula')}}
    {% endmacro %}
    
    {% call(var1) testfunc()  %}
    {{var1}}
    {% endcall %}
    

宏属性

  1. name:宏的名称。

  2. arguments:在宏定义阶段,所有参数的参数名组成一个元组存放在arguments属性中。

  3. defaults:在宏定义阶段,所有的默认形参组成了一个元组存放在defaults中。

  4. catch_varargs:如果宏中使用了varargs变量,此属性的值为true。

  5. catch_kwargs: 如果宏中使用了kwargs变量,此属性的值为true。

  6. caller:如果宏中使用了caller变量,此属性值为true。

      0 13:39:50 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test7.j2
    {% macro foo(v1,v2,v3=5,v5=5) %}
    test string
    {{ v1 }}
    {{ v2 }}
    {{ v3 }}
    {{ v5 }}
    {% endmacro %}
    
    {{ foo.name }}
    {{ foo.arguments }}
    {{ foo.defaults }}
    {{ foo.catch_varargs }}
    {{ foo.catch_kwargs }}
    {{ foo.caller }}
    

{% include % }包含

  1. jinja2中也可以使用“include”去加载包含其它j2文件。比如在test2.j2中引用test1.j2。

      0 13:50:12 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2
    test1.j2 info start
    {% for n in range(3) %}
    {{ n }}
    {% endfor %}
    test1.j2 info end
      0 13:50:16 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test2.j2
    test2.j2 info start
    {% include 'test1.j2' %}
    test2.j2 info end
      0 13:50:18 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test2.j2 dest=/opt/test'
    
  2. 默认情况下,被包含文件是可以使用主文件中定义的变量的。

    # 例1:
      0 13:52:56 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test3.j2
    test3.j2 info start
    {{ var1 | default('natasha',boolean=true) }}
    test3.j2 info end
      0 13:53:00 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test4.j2
    test4.j2 info start
    {% set var1='wula' %}
    {% include 'test3.j2' %}
    test4.j2 info end
      0 14:39:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test4.j2 dest=/opt/test'
    
  3. include一个不存在j2文件时,忽略报错。

      0 14:45:45 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test5.j2 
    test5.j2 info start
    {{ var1 | default('natasha',boolean=true) }}
    test5.j2 info end
      0 14:45:51 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test6.j2 
    test6.j2 info start
    {% set var1='wula' %}
    {% include 'test5.j2' %}
    {% include 'test7.j2' ignore missing %}
    test6.j2 info end
      0 14:45:53 root@ck-ansible,172.16.2.9:/server/ops_ansible # ansible ck-node1 -m template -a 'src=test6.j2 dest=/opt/test'
    

{% import %}导入

  1. include的作用是在模板中包含另一个模板文件,而import的作用是在一个文件中导入其它文件中的宏。下面举例:使用import..as方式导入宏文件中的全部宏。

      0 16:56:12 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat funclib.j2 
    {% macro foo1(v1) %}
    {{ v1 }}
    {% endmacro %}
    
    {% macro foo2(v2) %}
    {{ v2 }}
    {% endmacro %}
      0 16:56:14 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2 
    test1.j2 info start
    {% import 'funclib.j2' as funclib %}	# 将funclib.j2文件中的宏导入到funclib变量中,方便后续调用。
    {{ funclib.foo1('wula') }}
    {{ funclib.foo2('natasha') }}
    test1.j2 info end
    
  2. 使用from..import..方式导入宏文件中的指定宏。

      0 16:57:55 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat funclib.j2 
    {% macro foo1(v1) %}
    {{ v1 }}
    {% endmacro %}
    
    {% macro foo2(v2) %}
    {{ v2 }}
    {% endmacro %}
      0 16:57:58 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test2.j2 
    test1.j2 info start
    {% from 'funclib.j2' import foo1 as f1,foo2 as f2 %}
    {{ f1('wula') }}
    {{ f2('bobosha') }}
    test1.j2 info end
    
  3. 如果宏的名字是以一个或多个下划线开头,则表示这个宏为私有宏,私有宏不能被导入到其他文件中使用。

      0 17:01:56 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat funclib.j2 
    {% macro _foo(v1) %}
    {{ v1 }}
    {% endmacro %}
    
    {{ _foo('wula') }}
    

继承

  模板继承:将通用的配置写在主模板的公共区域,将可能需要修改或者动态填充的部分写在主模板的块(block)中,后续使用如果涉及到修改配置,可以编写一个子模板直接继承主模板的公共区域配置,只覆盖需要修改的块(block)即可。

  1. 使用子模板去继承主模板。

      0 17:49:59 root@ck-ansible,172.16.2.9:/server/ops_ansible # ll
    总用量 8
    -rw-r--r-- 1 root root  92 10月 27 17:49 subtem.j2
    -rw-r--r-- 1 root root 161 10月 27 17:49 tem.j2
      0 17:50:01 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat tem.j2 
    fixed configuration1		# 相对固定的配置
    fixed configuration2
    fixed configuration3
    
    {% block bt1 %}				# 把相对不固定的配置写在bt1块中。
    Unfixed configuration1		# 相对不固定的配置
    Unfixed configuration2
    {% endblock %}
    
    fixed configurationN
      0 17:50:03 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat subtem.j2 
    {% extends 'tem.j2' %}		# 继承主模板
    
    {% block bt1 %}
    new configuration1			# 编写bt1块中的新配置去替换主模板中的旧配置。
    new configuration2
    {% endblock %}
    
  2. 存在块嵌套的情况下使用继承,会覆盖掉该块下的所有内容,包括子块。

      0 18:14:05 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat tem.j2 
    fixed configuration1
    fixed configuration2
    fixed configuration3
    
    {% block bt1 %}
    Unfixed configuration1 in bt1
    Unfixed configuration2 in bt1
        {% block bt2 %}
        Unfixed configuration1 in bt2
        Unfixed configuration2 in bt2
        {% endblock bt2 %}
    {% endblock bt1 %}		# endblock后的bt1可省略,这里是为了与bt2作区分,多个块存在的时候建议加上。
    
    fixed configurationN
      0 18:14:07 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat subtem.j2 
    {% extends 'tem.j2' %}
    {% block bt1 %}
    new configuration1 in bt1
    new configuration2 in bt1
    {% endblock bt1 %}
    
  3. 不修改主模板文件,只新增主模板文件中某个块的内容。

      0 18:24:25 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat tem.j2
    fixed configuration1
    fixed configuration2
    fixed configuration3
    
    {% block bt1 %}
    Unfixed configuration1 in bt1
    Unfixed configuration2 in bt1
    {% block bt2 %}
    Unfixed configuration1 in bt2
    Unfixed configuration2 in bt2
    {% endblock bt2 %}
    {% endblock bt1 %}
    
    fixed configurationN
      0 18:24:26 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat subtem.j2 
    {% extends 'tem.j2' %}
    {% block bt2 %}
    {{ super() -}}	# 利用super()获取到父块中的所有内容,并新增下面两行内容。利用-取消自动换行(前面说过的)。
    new configuration1 in bt2
    new configuration2 in bt2
    {% endblock bt2 %}
    
  4. for循环+block:默认情况下,for循环内的块是无法获取for循环的变量的(会报变量未定义),想要获取到需要借助scoped修饰符。

      0 18:39:52 root@ck-ansible,172.16.2.9:/server/ops_ansible # cat test1.j2
    something in test1.j2 ...
    
    {% for n in range(3) %}
    {% block bt1 scoped %}
    something in block bt1 ---- {{n}}
    {% endblock bt1 %}
    {% endfor %}
    
    something in test1.j2 ...
    


写作不易,转载请注明出处,谢谢~~

原文地址:https://www.cnblogs.com/ccbloom/p/15508707.html