目录
一、ansible中模板的作用
假设,现在需要一次性在10台主机上安装redis,并且让安装后的redis都监听在redis所在主机的非“127.0.0.1”的IP地址上,该怎么办?通过ansible安装10台redis 很容易,但是,安装完成之后,10台主机中redis都是使用默认的监听地址“127.0.0.1”,我们不可能一个一个主机的修改配置文件,这时就需要使用“模板”
ansible会根据模板文件,为每一台主机生成对应的配置文件,步骤如下:
- 找一个现成的redis配置文件,作为“模板”文件,可以从之前安装的主机拷贝一份,也可以从redis的rpm包中提取一份
- 修改模板文件,将IP设置部分使用变量进行替换
- 使用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
- 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
- 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的关键字参数效果类似。
- 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