1.template简单使用
如果装多台redis,每台redis绑定自身ip.可以通过jinja2的方式去是实现。
# cat temptest.yml
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- yum:
name: redis
state: present
- template:
src: /testdir/ansible/redis.conf
dest: /etc/redis.conf
在模板中修改bind 127..0.0.1 为 bind {{ansible_host}}
template模块包含如下
owner参数: 指定最终生成的文件拷贝到远程主机后的属主。
group参数: 指定最终生成的文件拷贝到远程主机后的属组。
mode参数: 指定最终生成的文件拷贝到远程主机后的权限,如果你想将权限设置为"rw-r--r--",则可以使用mode=0644表示,如果你想要在user对应的权限位上添加执行权限,则可以使用mode=u+x表示。
除了上述参数,还有如下参数也很常用
force参数: 当远程主机的目标路径中已经存在同名文件,并且与最终生成的文件内容不同时,是否强制覆盖,可选值有yes和no,默认值为yes,表示覆盖,如果设置为no,则不会执行覆盖拷贝操作,远程主机中的文件保持不变。
backup参数: 当远程主机的目标路径中已经存在同名文件,并且与最终生成的文件内容不同时,是否对远程主机的文件进行备份,可选值有yes和no,当设置为yes时,会先备份远程主机中的文件,然后再将最终生成的文件拷贝到远程主机。
2.jinja2的语法
{{ }} :用来装载表达式,比如变量、运算表达式、比较表达式等。
{% %} :用来装载控制语句,比如 if 控制结构,for循环控制结构。
{# #} :用来装载注释,模板文件被渲染后,注释不会包含在最终生成的文件中。
例子:
[root@ansible ansible]# cat test.j2
test jinja2 variable
test {{ testvar1 }} test
执行:
ansible 192.168.10.20 -m template -e "testvar1=testtest" -a "src=test.j2 dest=/opt/test"
验证:
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
test jinja2 variable
test testtest test
"{{ }}"中还可以包含一些表达式
# cat test.j2
jinja2 test
{{ 1 == 1 }}
{{ 2 != 2 }}
{{ 2 > 1 }}
{{ 2 >= 1 }}
{{ 2 < 1 }}
{{ 2 <= 1 }}
生成文件内容如下:
# cat test
jinja2 test
True
False
True
True
False
False
逻辑运算的示例
jinja2 test
{{ (2 > 1) or (1 > 2) }}
{{ (2 > 1) and (1 > 2) }}
{{ not true }}
{{ not True }}
{{ not false }}
{{ not False }}
算数运算的相关示例如下:
# cat test.j2
jinja2 test
{{ 3 + 2 }}
{{ 3 - 4 }}
{{ 3 * 5 }}
{{ 2 ** 3 }}
{{ 7 / 5 }}
{{ 7 // 5 }}
{{ 17 % 5 }}
成员运算的相关示例如下:
模板文件内容
# cat test.j2
jinja2 test
{{ 1 in [1,2,3,4] }}
{{ 1 not in [1,2,3,4] }}
生成文件内容
# cat test
jinja2 test
True
False
除了变量和各种常用的运算符,过滤器也可以直接在"{{ }}"中使用
# cat test.j2
jinja2 test
{{ 'abc' | upper }}
jinja2的tests自然也能够在"{{ }}"中使用
模板文件内容
# cat test.j2
jinja2 test
{{ testvar1 is defined }}
{{ testvar1 is undefined }}
{{ '/opt' is exists }}
{{ '/opt' is file }}
{{ '/opt' is directory }}
"lookup"也可以在"{{}}"使用
# cat /testdir/ansible/test.j2
jinja2 test
{{ lookup('file','/testdir/testfile') }}
{{ lookup('env','PATH') }}
{# 为注释信息#}
test 2 tes2
{# zhushi #}
{#
hihhhj
#}
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test2"
192.168.10.20 | CHANGED | rc=0 >>
test 2 tes2
3. {%if%}在jinja2中的使用
"if"控制语句的用法
{% if 条件 %}
...
{% endif %}
例子:
[root@ansible ansible]# cat jinja2_test.yaml
---
- hosts: 192.168.10.20
remote_user: root
gather_facts: no
tasks:
- template:
src: /etc/ansible/test2.j2
dest: /opt/test2
vars:
testnum: 5
cat test2.j2
{% if testnum > 3 %}
greater than 3
{% endif %}
[root@ansible ansible]# ansible-playbook jinja2_test.yaml
PLAY [192.168.10.20] *****************************************************************************************************************************************************************************************
TASK [template] **********************************************************************************************************************************************************************************************
changed: [192.168.10.20]
PLAY RECAP ***************************************************************************************************************************************************************************************************
192.168.10.20 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test2"
192.168.10.20 | CHANGED | rc=0 >>
greater than 3
复杂的if结构
{% if 条件 %}
...
{% else %}
...
{% endif %}
或者
{% if 条件一 %}
...
{% elif 条件N %}
...
{% else %}
...
{% endif %}
或者
{% if 条件一 %}
...
{% elif 条件二 %}
...
{% elif 条件N %}
...
{% endif %}
"if"表达式
<do something> if <something is true> else <do something else>
{{ 'a' if 2>1 else 'b' }}
4.模板文件中使用变量
cat test.j2
jinja2 test
{% set teststr='jinja2var' %}
{{ teststr }}
[root@ansible ansible]# ansible 192.168.10.20 -m template -a "src=test2.j2 dest=/opt/test"
查看结果
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
jinja2 test
jinja2var
5.for在jinja2中的使用
for循环的基本语法
{% for 迭代变量 in 可迭代对象 %}
{{ 迭代变量 }}
{% endfor %}
例子:
[root@ansible ansible]# cat test2.j2
jinja2 test
{% for i in [3,1,4,6] %}
{{ i }}
{% endfor %}
[root@ansible ansible]# ansible 192.168.10.20 -m template -a "src=test2.j2 dest=/opt/test"
验证
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
jinja2 test
3
1
4
6
从生成的内容可以看出,每次循环后都会自动换行,如果不想要换行,则可以使用如下语法
jinja2 test
{% for i in [3,1,4,6] -%}
{{ i }}
{%-endfor %}
[root@ansible ansible]# ansible 192.168.10.20 -m template -a "src=test2.j2 dest=/opt/test"
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
jinja2 test
3146
在for的结束控制符"%}"之前添加了减号"-"
在endfor的开始控制符"{%"之后添加到了减号"-"
在每一项后面加一个空格
jinja2 test
{% for i in [3,1,4,6] -%}
{{ i }} {{ ' ' }}
{%-endfor %}
结果
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
jinja2 test
3 1 4 6
或者这样写
# cat test.j2
jinja2 test
{% for i in [3,1,7,8,2] -%}
{{ i~' ' }}
{%- endfor %}
循环操作字典
jinja2 test
{% for key,val in {'name':'bob','age':'18'}.iteritems() %}
{{ key ~':'~ val}}
{% endfor %}
ansible 192.168.10.20 -m template -a "src=test2.j2 dest=/opt/test"
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
jinja2 test
age:18
name:bob
借助loop.index特殊变量可以获取第几次循环
[root@ansible ansible]# ansible 192.168.10.20 -m template -a "src=test3.j2 dest=/opt/test"
192.168.10.20 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "f2f44e9e31f2f693928de2f50c289aead20eeb95",
"dest": "/opt/test",
"gid": 0,
"group": "root",
"md5sum": "e7a4f21bf3a8240e90cb795bfebad711",
"mode": "0644",
"owner": "root",
"size": 29,
"src": "/root/.ansible/tmp/ansible-tmp-1600329612.94-90721-265848675337608/source",
"state": "file",
"uid": 0
}
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
1----1
3----2
5----3
7----4
结果
[root@ansible ansible]# cat test3.j2
{% for i in [1,3,5,7] %}
{{ i ~'----'~ loop.index }}
{% endfor %}
range函数可以指定起始数字、结束数字、步长等,默认的起始数字为0
{% for i in range(1,4,2) %}
{{i}}
{% endfor %}
for嵌套if语句
{% for i in [7,1,5,3,9] if i>10 %}
{{ i }}
{%else%}
no one is greater than 10
{% endfor %}
{% for i in [7,1,5,3,9] if i>3 %}
{{ i ~'----'~ loop.index }}
{% endfor %}
{% for i in [7,1,5,3,9] %}
{% if i>3 %}
{{ i ~'----'~ loop.index}}
{% endif %}
{% endfor %}
想要支持break和continue,则需要添加一个loopcontrols扩展
jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n,jinja2.ext.loopcontrols
例子:
{% for i in [7,1,5,3,9] %}
{% if loop.index > 3 %}
{%break%}
{%endif%}
{{i ~'---'~ loop.index}}
{% endfor %}
上例表示3次迭代以后的元素不会被处理
6 引号在jinja2中的使用
如果jinja2文件里使用 类似{{}}等 可以使用引号
[root@ansible ansible]# cat test4.j2
{{ '{{' }}
{{ '{% test %}' }}
结果:
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
{{
{% test %}
可以使用"{% raw %}"块实现上述功能
{% raw %}
{% endraw %}
例子:
[root@ansible ansible]# cat test5.j2
{% raw %}
{{ test }}
{% for %}
{% if %}
{% endraw %}
结果:
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
{{ test }}
{% for %}
{% if %}
7 可以指定在jinja2文件里的引用符号
当我们调用templdate模块时,执行如下命令,注意,如下命令表示使用"(("代替"{{",使用"))"代替"}}"。
ansible test70 -m template -a "src=test.j2 dest=/opt/test variable_start_string='((' variable_end_string='))'"
可以使用block_end_string参数指定一个符号,这个符号用于替换"{% %}"中的"%}"
8 在jinja2中可以定义宏(函数)并引用它
9 在jinja2文件中可以使用include
# cat test.j2
test...................
test...................
{% include 'test1.j2' %}
test...................
# cat test1.j2
test1.j2 start
{% for i in range(3) %}
{{i}}
{% endfor %}
test1.j2 end
如果不想让背包含的文件使用外部变量的话,可以用"without context"显式的设置"include"
# cat test.j2
{% set varintest='var in test.j2' %}
test...................
test...................
{% include 'test1.j2' without context %}
test...................
# cat test1.j2
test1.j2 start
{{ varintest }}
test1.j2 end
如果导入的jinja2文件不存在 也让任务能正常执行的话,可以使用"ignore missing"标记皆可
# cat test.j2
test...................
test...................
{% include 'test1.j2' with context %}
test...................
{% include 'test2.j2' ignore missing with context %}
10 在jinja2文件中使用"{% import %}"
import的作用是在一个文件中导入其他文件中的宏
# cat function_lib.j2
{% macro testfunc() %}
test function
{% for i in varargs %}
{{ i }}
{% endfor %}
{% endmacro %}
{% macro testfunc1(tv1=1) %}
{{tv1}}
{% endmacro %}
# cat test.j2
{% import 'function_lib.j2' as funclib %}
something in test.j2
{{ funclib.testfunc(1,2,3) }}
something in test.j2
{{ funclib.testfunc1('aaaa') }}
由于我们已经将"function_lib.j2"文件中的宏导入到了"funclib"变量中,所以当我们需要调用"function_lib.j2"文件中的testfunc宏时,直接使用了如下代码即可。
{{ funclib.testfunc(1,2,3) }}
# cat function_lib.j2
{% macro testfunc() %}
test function
{% for i in varargs %}
{{ i }}
{% endfor %}
{% endmacro %}
{% macro testfunc1(tv1=111) %}
test function1
{{tv1}}
{% endmacro %}
# cat test1.j2
{% from 'function_lib.j2' import testfunc as tf, testfunc1 as tf1 %}
something in test1.j2
{{ tf(1,2) }}
something in test1.j2
{{ tf1('a') }}
如上例所示,我们使用了如下语法导入了'function_lib.j2'文件中的两个宏
{% from 'function_lib.j2' import testfunc as tf, testfunc1 as tf1 %}
上述语法表示:
从'function_lib.j2'文件中将testfunc宏导入为tf宏
从'function_lib.j2'文件中将testfunc1宏导入为tf1宏
11 在jinja2中使用继承
下面例子展示了继承的简单使用
[root@ansible ansible]# cat jinja2_jincheng.j2
something in fu
{% block test %}
this is test1.j2
{% endblock test %}
this is in fu
[root@ansible ansible]# cat jinja2_jincheng1.j2
thisis test2
{% extends 'jinja2_jincheng.j2' %}
{% block test %}
nihao nihao jinja2_jincheng1.j2
{% endblock test %}
thisis test2
执行
ansible 192.168.10.20 -m template -a "src=jinja2_jincheng1.j2 dest=/opt/test"
结果
[root@ansible ansible]# ansible 192.168.10.20 -m shell -a "cat /opt/test"
192.168.10.20 | CHANGED | rc=0 >>
thisis test2
something in fu
nihao nihao jinja2_jincheng1.j2
this is in fu
如果你并不想完全覆盖父模板中的块,而是想要在父模板某个块的基础之上进行扩展,那么则可以子模板中使用super块来完成,这样说可能不太容易理解,不如先来看一个小示例,如下:
# cat test.j2
something in test.j2...
{% block test %}
something in block test
something else in block test
{% endblock test %}
something in test.j2...
# cat test1.j2
{% extends 'test.j2' %}
{% block test%}
aaaaaaaaaaaaaa
{{ super() }}
11111111111111
{% endblock test %}
如上例所示,test1.j2继承自test.j2文件,同时,test1.j2中指明要修改test块,如你所见,子模板的test块中包含"{{ super() }}",这表示父模板中test块中的内容会替换到"{{ super() }}"对应的位置,换句话说就是,我们可以通过"{{ super() }}"来获取父级块中的内容,上例test1.j2的渲染结果如下:
# cat test1
something in test.j2...
aaaaaaaaaaaaaa
something in block test
something else in block test
11111111111111
something in test.j2...
更多关于继承的例子及说明参考如下链接
http://www.zsythink.net/archives/3051