ansible_jinja2模板的使用

本章主要介绍在playbook中如何使用jinja2模板

  • 神马是jinja2模板
  • 在jinja2模板文件中写if判断语句
  • 在jina2模板文件中写for循环语句

可以使用copy模块把本地的一个文件拷贝到远端机器,下面再次复习一下。
本章实验都在/home/lduan/demo4下操作,先把demo4目录创建出来并把ansible.cfg和hosts拷贝进去,命令如下。

复制代码
[blab@node01 ~]$ mkdir demo4
[blab@node01 ~]$ cp ansible.cfg hosts demo4/
[blab@node01 ~]$ cd demo4/
[blab@node01 demo4]$ 
练习1:用copy拷贝一个文件到db主机组。
有一个文件aa.txt,内容如下。
复制代码
[blab@node01 demo4]$ cat aa.txt 
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: {{ansible_default_ipv4.address}}
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$

这个文件中包含一个 fact变量 ansible_default_ipv4.address。

写一个 playbook,内容如下。
复制代码
[blab@node01 demo4]$ cat 1.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端主机
    copy: src=aa.txt dest=/opt/aa.txt
[blab@node01 demo4]$
运行此playbook,命令如下。
复制代码
[blab@node01 demo4]$ ansible-playbook 1.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [拷贝一个文件到远端主机] *************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$
现在已经把本地的aa.,txt拷贝到node02和node03的/opt目录中了。下面查看这两台主机上 /opt/aa.txt的内容
复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/aa.txt"
node03 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: {{ansible_default_ipv4.address}}
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
node02 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: {{ansible_default_ipv4.address}}
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$ 

可以看到,当用copy拷贝一个文件到远端机器时,如果这个文件中有变量,拷贝过去的文件的变量并不会变成具体的值。

如果希望文件拷贝过去之后,文件中的变量变成具体的值,那么就不能用copy模块,而是要使用template模块了

练习2:修改1.yml的内容如下
复制代码
[blab@node01 demo4]$ cat 1.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端主机
    template: src=aa.txt dest=/opt/aa.txt
[blab@node01 demo4]$

与刚才相比,只是把copy换成了template。template模块的用法与copy模块一致,所以这里选项并没有变。运行此 playbook,命令如下。

复制代码
[blab@node01 demo4]$ ansible-playbook 1.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [拷贝一个文件到远端主机] *************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$

再次查看两台主机上/opt/aa.txt的内容

复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/aa.txt"
node03 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: 192.168.182.210
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
node02 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: 192.168.182.193
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$ cat 1.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端主机
    template: src=aa.txt dest=/opt/aa.txt
[blab@node01 demo4]$

可以看到,通过template拷贝含有变量的文件时,拷贝到远端机器之后,文件中的变量会变成具体的值

这个通过template拷贝的,含有变量的文件我们称为jinja2模板,jinja2模板文件的后缀一般使用 j2 ,这不是必须的,但是建议使用j2作为后缀

所以,需要修改aa.txt 的文件为aa.j2

复制代码
[blab@node01 demo4]$ mv aa.txt aa.j2

同时修改1.yml中对应的内容

复制代码
[blab@node01 demo4]$ cat 1.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端主机
    template: src=aa.j2 dest=/opt/aa.j2        //修改后缀名
[blab@node01 demo4]$

这里如果jinja2模板文件没有写路径,例如,例子中 src=aa.j2的aa.j2没有写路径,则优先到当前目录的templates 中找aa.j2,如果没有,则到当前目录中找aa.j2.

练习3:验证
复制代码
[blab@node01 demo4]$ mkdir templates

在templates目录中创建aa.j2

复制代码
[blab@node01 demo4]$ cat template/aa.j2 
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的主机名是: {{ansible_fqdn}}
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$

这样我们就有两个aa.j2了,还有一个是当前目录下的aa.j2

复制代码
[blab@node01 demo4]$ cat aa.j2 
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的 IP 地址是: {{ansible_default_ipv4.address}}
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$

再次运行此playbook

复制代码
[blab@node01 demo4]$ ansible-playbook 1.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [拷贝一个文件到远端主机] *************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$

查看两台主机上/opt/aa.txt 的内容

复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/aa.j2"
node03 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的主机名是: node03
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
node02 | CHANGED | rc=0 >>
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
 | 我的主机名是: node02
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
[blab@node01 demo4]$

这里可以看到显示的主机名,所以是 templates目录中的aa.j2生效了。

1.if判断

在jinja2模板文件中,我们也是可以使用if判断语句的,语法格式如下。

复制代码
 {% if 判断1 %}
 内容1
 {% elif 判断2 %}
 内容2
 ...多个elif...
 {% else %}
 内容3
 {% endif %}
注意:
  1. "%"两边有没有空格都可以,不过所有的"%"前后空格要保持一致,即要有都有,要没有都没有。
    2. if和elif中的内容如果太长了,可以另起一行写。
    如果判断1成立,则打印内容1,后面的条件不再判断,直接跳转到endif后面的内容;如果判断1不成立,则执行elif后面的判断2,如果成立则打印内容2,后面的条件不再判断,直接跳转到endif后面的内容。以此类推,如果所有的f和elif都不成立,则打印else中的内容。
  2. elif和 else不是必需的。
练习:写一个 jinja2模板文件
复制代码
[blab@node01 demo4]$ cat templates/bb.j2 
1111
 {% if ansible_fqdn=="node02" %}
  {{ansible_fqdn}}
 {% else %}
aaaa
 {% endif %}
3333
[blab@node01 demo4]$

这里jinja2模板所生成的文件一共会产生3行内容,第一行的1111和第三行的3333是必打印出来的,第二行的内容具体是什么要看情况。如果在node02上执行则显示主机名,如果在其他机器上执行则显示aaaa。

写一个playbook
复制代码
[blab@node01 demo4]$ cat 2.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端
    template: src=bb.j2 dest=/opt/bb.conf
[blab@node01 demo4]$ 

这里是把templates/bb.j2拷贝到两台机器的/opt中并命名为bb.conf。运行此playbook,命令如下。

复制代码
[blab@node01 demo4]$ ansible-playbook 2.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [拷贝一个文件到远端] ***************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$

查看两台机器上/opt/bb.conf的内容

复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/bb.conf"
node03 | CHANGED | rc=0 >>
1111
 aaaa
 3333
node02 | CHANGED | rc=0 >>
1111
   node02
 3333
[blab@node01 demo4]$

可以看到,node02的/opt/bb.conf的第二行显示的是主机名,node03的/opt/bb.conf的第二行显示的是 aaaa。
在if和 elif后面是可以写多个判断的,用or或and作为连接符,语法如下:

  • 判断1 or 判断11:判断1和判断11只要有一个成立就算成立,只有全部不成立才算不成立。
  • 判断1 and 判断11:判断1和判断11只有全部成立才算成立,只要有一个不成立就算不成立
查看下面的 jinja2模板文件
复制代码
[blab@node01 demo4]$ cat templates/cc.j2 
1111
 {% if ansible_fqdn=="node02" 
	and
 ansible_distribution_major_version=="7" %}
  {{ansible_fqdn}}
 {% else %}
 aaaa
 {% endif %}
3333
[blab@node01 demo4]$ 

这里jinja2模板会打印3行内容,第一行和第三行的内容是固定的,为1111和3333。第二行的内容是什么,要看是否满足条件,这里判断被管理主机名为server2.rhce.cc及系统主版本号为7,二者都要满足,第二行才会显示主机名,否则显示 aaaa。需要注意的是,这里if 判断语句太长,特意写成了3行也是没问题的。

写一个playbook
复制代码
[blab@node01 demo4]$ cat 3.yml 
---
- hosts: db
  tasks:
  - name: 我要拷贝一个文件过去
    template: src=cc.j2 dest=/opt/cc.conf
[blab@node01 demo4]$
运行此playbook。
复制代码
[blab@node01 demo4]$ ansible-playbook 3.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [我要拷贝一个文件过去] **************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$
查看两台机器上/opt/cc.conf的内容
复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/cc.conf"
node03 | CHANGED | rc=0 >>
1111
  aaaa
 3333
node02 | CHANGED | rc=0 >>
1111
  aaaa
 3333
[blab@node01 demo4]$ 

2.for循环

一个列表中有多个元素,如果需要依次对列表中的每个元素操作,则可以使用for循环来实现,for 循环的语法如下。

复制代码
 {% for i in 列表名 %}
  {{i}}
 {% endfor %}

这里首先把列表中的第一个元素赋值给i,执行中间的操作;然后把第二个元素赋值给i执行中间的操作,以此类推,直到把最后一个元素赋值给i。看下面的例子。

复制代码
[blab@node01 demo4]$ cat templates/dd.conf.j2 
{% set list1=['aa','bb','cc'] %}
1111
{% for i in list1 %}
 {{i}}
{% endfor %}
5555
[blab@node01 demo4]$

这里手动在jinja2模板中定义了一个列表(注意定义列表的方式)list1,里面有3个元素,分别为aa、bb、cc。然后对这个列表的内容进行循环。
这里jinja2模板生成的文件有5行内容,第1行和第5行的内容是固定的,为1111和5555。 第2~4行是循环列表list1 中的值,为aa、bb、cc.

写一个 playbook
复制代码
[blab@node01 demo4]$ cat 4.yml 
---
- hosts: db
  tasks:
  - name: 拷贝一个文件到远端主机
    template: src=dd.conf.j2 dest=/opt/dd.conf
[blab@node01 demo4]$
运行此playbook
复制代码
[blab@node01 demo4]$ ansible-playbook 4.yml 

PLAY [db] **********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node03]
ok: [node02]

TASK [拷贝一个文件到远端主机] *************************************************************
changed: [node03]
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node03                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$
查看db组 上/opt/dd.conf的内容
复制代码
[blab@node01 demo4]$ ansible db -m shell -a "cat /opt/dd.conf"
node03 | CHANGED | rc=0 >>
1111
 aa
 bb
 cc
5555
node02 | CHANGED | rc=0 >>
1111
 aa
 bb
 cc
5555
[blab@node01 demo4]$

除了jinja2模板中手动定义的列表,一般情况下,我们会在playbook中定义列表,然后对列表中的元素进行循环

练习:写一个变量文件users_list.txt,里面包含一个名称为users的列表
复制代码
[blab@node01 demo4]$ cat users_list.txt 
users:
- uname: tom
  age: 20
  sex: man
- uname: tom
  age: 19
  sex: man
- uname: bob
  age: 22
  sex: man
- uname: mary
  age: 23
  sex: woman
- uname: wangwu
  age: 24
  sex: man
[blab@node01 demo4]$ 
在 templates目录下写一个ee.j2,里面写一个 for 语句循环users列表
复制代码
[blab@node01 demo4]$ cat templates/ee.j2 
现在 公司中所有员工姓名是:
{% for i in users %}
 {{i.uname}}
{% endfor %}
[blab@node01 demo4]$ 
循环每个元素时,只打印元素中的uname变量。写一个名称为5.yaml的playbook,加载变量文件 users list.txt,
复制代码
[blab@node01 demo4]$ cat 5.yml 
---
- hosts: node02
  vars_files:
  - users_list.txt
  tasks:
  - name: 拷贝一个文件到远端
    template: src=ee.j2 dest=/opt/ee.conf
[blab@node01 demo4]$

这里通过 template模块把ee.j2拷贝到被管理主机的/opt 中并命名为ee.conf。查看node02上/opt/ee.conf的内容

复制代码
[blab@node01 demo4]$ ansible-playbook 5.yml 

PLAY [node02] ******************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node02]

TASK [拷贝一个文件到远端] ***************************************************************
changed: [node02]

PLAY RECAP *********************************************************************
node02                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[blab@node01 demo4]$ 

查看被管理主机的/opt/ee.conf,里面包括users列表中所有的用户名。

复制代码
[blab@node01 demo4]$ ansible node02 -m shell -a "cat /opt/ee.conf"
node02 | CHANGED | rc=0 >>
现在 公司中所有员工姓名是:
 tom
 tom
 bob
 mary
 wangwu
[blab@node01 demo4]$
相关推荐
leo__5202 天前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
风清再凯7 天前
自动化工具ansible,以及playbook剧本
运维·自动化·ansible
IT乌鸦坐飞机7 天前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
遇见火星20 天前
如何使用Ansible一键部署MinIO集群?
ansible
粥周粥20 天前
ANSIBLE
ansible
码农101号20 天前
Linux中ansible模块补充和playbook讲解
linux·运维·ansible
码农101号20 天前
Linux的Ansible软件基础使用讲解和ssh远程连接
ansible
烟雨书信21 天前
ANSIBLE运维自动化管理端部署
运维·自动化·ansible
碎碎-li21 天前
ANSIBLE(运维自动化)
运维·自动化·ansible
@donshu@24 天前
Linux运维-ansible-python开发-获取inventroy信息
linux·运维·ansible