前言
当你用ansible进行多机器的配置调整,且调整的东西都一模一样,此时你不会拒绝模板的诱惑。
ansible的模板是jinja2,所以jinja2的特性,在这里都可以用。
模板中,不要出现任何你觉得模板会忽略的东西,包括但不限于空格
模块 template
参数:
- src 模板文件路径
- dest 目的文件路径
牵扯到目的路径,必然有权限参数
- owner 目的属主
- group 目的属组
- mode 目的权限
覆盖与备份
- force 覆盖,yes / no
- backup 备份, yes / no , 若为 yes ,则目的重名文件会先改名
---
- hosts: localhost
remote_user: zyh
gather_facts: no
tasks:
- template:
src: ~/test.j2
dest: ~/test.info
模板分隔符
{{ }} 一般用来填充变量,可以是过滤器,也可以填充表达式,从而返回相应的值,例如 {{ 1==1 }} 返回 True
{% %} 一般用来填充控制语句
{# #} 模板注释语句,并非渲染后会出现
# ... ## 这一种 ansible 貌似不支持,所以可以忽略
分隔符1
# {{ }}
{# 普通变量 #}
{{ foo.bar }}
{{ foo['bar'] }}
{# 以过滤器 lookup 为例 #}
{{ lookup('file', '~/test.file') }}
{{ lookup('env', 'PATH' )}}
最终目的文件,会输出~/test.file
内容和 $PATH
内容
字符串拼接需要使用
~
,例如"name:"~name
分隔符2
# {% %}
# 官网所有的控制列表
https://jinja.palletsprojects.com/en/master/templates/#list-of-control-structures
条件控制语句 if
{% if 条件1 %}
pass
{% elif 条件2 %}
pass
{% else %}
pass
{% endif %}
循环语句 for
{% for i in 可迭代对象 %}
{{ i }}
{% endfor %}
默认循环后,每一个循环单体独占一行,如果需要删除独占,则需要给第二个%}和第三个控制符{%加减号,最终变为-%}和{%-。
关于字典类型,可以使用 iteritems() 函数,从而方便的获取到字典的 k 和 v。例如
{% for k,v in {'name':'zhangsan', 'gender':'male'}.iteritems() %}
{{ k }}:{{ v }}
{% endfor %}
# 渲染后
name:zhangsan
gender:male
条件和循环组合语句
{% for i in 可迭代对象 if 条件 %}
满足条件语句
{% else %}
不满足条件语句
{% endfor %}
例如
{% for i in [1,2,3,4] if i>2 %}
{{ i }}'s index is {{ loop.index }}
{% endfor %}
# 渲染后
3's index is 1
4's index is 2
loop.index 是循环体索引,这里可能会有个疑问。
正常情况下,3和4的索引应该就是3和4,之所以是1和2,原因在于当条件控制和循环控制位于同一行的时候,先行运算的是
[1,2,3,4] if i>2
,之后才开始走for
循环。如果你想输出原始循环体,则需要将条件控制语句另起一行,放在
for
循环内部
{% for i in [1,2,3,4] %}
{% if i>2 %}
{{ i }}'s index is {{ loop.index }}
{% endif %}
{% endfor %}
# 渲染后
3's index is 3
4's index is 4
上述的 loop.index 只是jinja2的一种使用方式,其它方式具体可见官网文档
https://jinja.palletsprojects.com/en/master/templates/#list-of-control-structures
宏 macro
宏就是类似于函数的一个东西。
{# 编写宏 #}
{% macro func() %}
函数体
{% endmacro %}
{# 调用宏 #}
{{ func() }}
例如:
{% macro func(a,b,c=3,d=4) %}
{# 宏编写的时候,宏参数,要遵循默认参数在后
{{ a }}
{{ b }}
{{ c }}
{{ d }}
{% endmacro %}
{{ func(1,2,5) }}
# 渲染后
1
2
5
4
当给出参数超出了宏所定义的参数时,根据情况,宏会将多余的参数存在变量中,即:
超出的为非关键字参数,则存放在一个叫
varargs
的元组中超出的为关键字参数,则存放在一个叫
kwargs
的字典中
call 方法
如同当前函数的装饰器,可以扩展当前宏的功能
{# 编写宏 func,并调用 caller #}
{% macro func(a) %}
我有一个{{ a }}。
{{ caller(a) }}
{% endmacro %}
{# 编写宏 func_ext #}
{% macro func_ext(a,b) %}
但{{ b }}比{{ a }}好吃。
{% endmacro %}
{# 通过 call 关联 func,加载 func_ext #}
{% call(a) func('汉堡') %}
{{ func_ext(a,'三明治') }}
{% endcall %}
caller是call的对象,因此caller也是可以给call传参
# 渲染后
我有一个汉堡。
但三明治比汉堡好吃
扩展
扩展官方文档,可见 https://jinja.palletsprojects.com/en/master/extensions/
这里我只简单的说一下如何启动 for
循环中的 break
和 continue
。
ansible
中添加 jinja2
扩展,需要修改主配置文件 /etc/ansible/ansible.cfg
,找到 jinja2_extensions
,在后面追加扩展配置即可,每一个扩展用逗号,
分割。
break
和continue
的扩展名叫:jinja2.ext.loopcontrols