zoukankan      html  css  js  c++  java
  • 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 ...
      


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

  • 相关阅读:
    嵌入式系统编程和调试技巧
    使用Kotlin开发Android应用(II):创建新project
    2015 Multi-University Training Contest 2
    C#开发Unity游戏教程之游戏对象的属性变量
    Java开发project师案例-网络日志分析系统
    Flask
    Flask
    Flask
    Flask
    Flask
  • 原文地址:https://www.cnblogs.com/ccbloom/p/15508707.html
Copyright © 2011-2022 走看看