JINJA2模板的语法及使用
JINJA2模板的语法
个人理解非常像shell脚本或者开发语言,例如一些逻辑运算等。
如果有开发基础,更易懂吧。比如我哈哈哈哈哈
1、变量
- 可以在j2模板中引入facts变量,直接使用。
This is the system {{ ansible_facts['fqdn'] }}.
This is a {{ ansible_facts['distribution'] }} version {{ ansible_facts['distribution_version'] }} system.
Only use this system with permission.
- 也可以直接引用playbook中的变量
- 也可以在j2模板中定义变量——此时的优先级高于playbook中的优先级。
例如,在j2模板中定义了username变量:
{% set username = 'zhang' %}
The username id {{ username }}
在yml文件中也定义了变量
vars:
- username: wangxc
执行后,文件中的结果为:
The username id zhang
此时可以证明,j2模板中的变量优先级是更高的。
当移除掉j2模板中的变量定义时,将会引用yml文件中的变量。
The username id wangxc
2、逻辑控制——ifelse
{% if 条件表达式 %}
……
{% endif %}
{% if 条件表达式 %}
……
{% elif 条件表达式 %}
……
{% else %}
……
{% endif %}
jinja2的支持使用for循环、ifelse判断控制。逻辑控制语句,需要写在{% ………………%} 中
{# {% if filter01 is defined %} #}
{% if myhosts is defined %}
variable is defined
{% else %}
variable is undefined
{% endif %}
在yml文件中定义变量矩阵
vars:
myhosts:
- servera
- serverb
输出的结果:
variable is defined
3、逻辑控制——for循环
jinja2的支持使用for循环、ifelse判断控制
{% for myhost in groups['myhosts'] %}
my host is {{ myhost }}
{% endfor %}
在yml文件中定义变量矩阵
vars:
myhosts:
- servera
- serverb
运行结果:
my host is servera
my host is serverb
4、算术运算符
用的很少
+:把两个对象加到一起。如:{{ 1 + 1 }} 等于 2。但是如果两者是字符串或列表,你可以用这种方式来衔接它们【连接字符串推荐使用 ~ 运算符】。
-:用第一个数减去第二个数。如:{{ 3 - 2 }} 等于 1 。
/:对两个数做除法。返回值会是一个浮点数。如:{{ 1 / 2 }} 等于 {{ 0.5 }} 。
//:对两个数做除法,返回整数商。如:{{ 20 // 7 }} 等于 2 。
%:计算整数除法的余数。如:{{ 11 % 7 }} 等于 4 。
*:用右边的数乘左边的操作数。如:{{ 2 * 2 }} 会返回 4。也可以用于重复一个字符串多次。如:{{ '=' * 80 }} 会打印 80 个等号的横条。
**:取左操作数的右操作数次幂。如:{{ 2 ** 3 }} 会返回 8。
5、逻辑运算
==:比较两个对象是否相等。
!=:比较两个对象是否不等。
>:如果左边大于右边,返回 true。
>=:如果左边大于等于右边,返回 true。
<:如果左边小于右边,返回 true。
<=:如果左边小于等于右边,返回 true。
对于逻辑判断,在 for 过滤或 if 表达式中,它可以用于联合多个表达式:
and:如果左操作数和右操作数同为真,返回 true。
or:如果左操作数或右操作数有一个为真,返回 true。
not:对一个表达式取反(见下)。
(expr):表达式组。
提示:is 和 in 运算符同样支持使用中缀记法:foo is not bar 和 foo not in bar。所有的其它表达式需要前缀记法:not (foo and bar) 。
in:运行序列/映射包含检查。如果左操作数 包含于 右操作数,返回 true 。比如 {{ 1 in [1,2,3] }} 会返回 true。
is:运行一个 测验。参见上述
|:应用一个 过滤器。参见上述
~:把所有的操作数转换为字符串,并且连接它们。 {{ "Hello " ~ name ~ "!" }} 会返回(假设 name 值为 'John' ) Hello John!。
6、过滤器
官方的解释是这样的:
我觉得这一部分有点抽象,但看起来似乎又像是提供了一些比较方便的工具类(它叫做过滤器),可以帮助我们快速实现一些功能。就比如Java中的String类的自带方法,trim、toUpperCase、length等
以下是从网络上找到的一个例子,可以参考看看:
{# 变量定义 #}
{% set filter01 = -24.5 %}
{% set filter02 = 'abcDEGg' %}
{% set filter03 = " abCDef G hkIL " %}
{% set filter04 = ['physics', 'chemistry', 1997, 2000] %}
# 过滤器 使用
## 取绝对值
{{ filter01|abs() }} 或者 {{ filter01|abs }}
## 首字符大写,其他小写
{{ filter02|capitalize() }} 或者 {{ filter02|capitalize }}
## 去掉两端空格
|{{ filter03|trim() }}| 或者 |{{ filter03|trim }}|
## 返回序列的第一个
{{ filter04|first() }} 或者 {{ filter04|first }}
## 将序列变为字符串,可以指定每个元素间加入什么字符,默认空
默认情况: {{ filter04|join() }} 或者 {{ filter04|join }}
加入字符: {{ filter04|join('|') }}
# Tests 测验 使用
## 变量是否定义
未定义: {{ filter00 is defined }}
已定义: {{ filter01 is defined }}
## 变量是否是数字
{{ filter01 is number }} === {{ filter02 is number }}
## 变量是否是小写
{{ filter02 is lower }}
## 变量是否是字符串
{{ filter02 is string }}
## 变量在 if 中的判断是否已定义
{# ***** 变量已经被定义,直接判断表达式是 True或False ***** #}
{# {% if filter01 %} #}{# 如果变量没有定义,那么执行会报错 #}
{# 由于 filter00 之前未定义,因此这里定义为 false,不然执行会报错【生产中会在 playbook中定义】
{% set filter00 = false %}
{% if filter00 %}
#}
{# ***** 通过判断变量是否被定义,得到到True或False ***** #}
{# {% if filter01 is defined %} #}
{% if filter00 is defined %}
variable is defined
{% else %}
variable is undefined
{% endif %}
# range 使用
{% for i in range(1,20) %}
server 172.16.1.{{ i }}:80
{% endfor %}
运行的结果
# 过滤器 使用
## 取绝对值
24.5 或者 24.5
## 首字符大写,其他小写
Abcdegg 或者 Abcdegg
## 去掉两端空格
|abCDef G hkIL| 或者 |abCDef G hkIL|
## 返回序列的第一个
physics 或者 physics
## 将序列变为字符串,可以指定每个元素间加入什么字符,默认空
默认情况: physicschemistry19972000 或者 physicschemistry19972000
加入字符: physics|chemistry|1997|2000
# Tests 测验 使用
## 变量是否定义
未定义: False
已定义: True
## 变量是否是数字
True === False
## 变量是否是小写
False
## 变量是否是字符串
True
## 变量在 if 中的判断是否已定义
variable is undefined
# range 使用
server 172.16.1.1:80
server 172.16.1.2:80
server 172.16.1.3:80
server 172.16.1.4:80
server 172.16.1.5:80
server 172.16.1.6:80
server 172.16.1.7:80
server 172.16.1.8:80
server 172.16.1.9:80
server 172.16.1.10:80
server 172.16.1.11:80
server 172.16.1.12:80
server 172.16.1.13:80
server 172.16.1.14:80
server 172.16.1.15:80
server 172.16.1.16:80
server 172.16.1.17:80
server 172.16.1.18:80
server 172.16.1.19:80
JINJA2模板的引入
需要通过template模块,引入对应的j2模板。
j2模板没有要求必须以 .j2结尾,但为了提升可读性,建议这样做。
---
- name:
hosts: servera
tasks:
- name: jinja2 test
template:
src: jinja2.j2
dest: /home/student/j2_res
本文部分示例引用自:https://blog.youkuaiyun.com/woshizhangliang999/article/details/105849051
JINJA2模板综合实验
实验环境
[student@workstation file-review]$ pwd
/home/student/file-review
[student@workstation file-review]$ cat ansible.cfg
[defaults]
inventory = inventory
ansible_managed = Ansible managed: modified on %Y-%m-%d %H:%M:%S
[student@workstation file-review]$ cat inventory
[servers]
serverb.lab.example.com
[student@workstation file-review]$ cat files/issue
*------------------------------- PRIVATE SYSTEM -----------------------------*
- Access to this computer system is restricted to authorised users only. *
- *
- Customer information is confidential and must not be disclosed. *
*----------------------------------------------------------------------------*
实验要求
- 识别serverb上的facts变量,显示系统内存总量及处理器数目
- 创建一个j2模板,当devops用户登录时,显示出内存总量和处理器数目
- 创建playbook,使用devops用户并提权
- 使用template配置J2模板,并映射到目标主机的/etc/motd。设置所属组、所有者为root,权限为0644
- 使用stat和debug验证并显示/etc/motd的文件信息
- 使用copy将files/issue的文件放到被管理主机的/etc/目录下,并配置与源文件相同的权限
- 使用file模块保证/etc/issue.net是/etc/issue的链接
示例文件
[student@workstation file-review]$ cat motd.j2
system total memory: {{ ansible_facts['memtotal_mb'] }} MiB
system processor count: {{ ansible_facts['processor_count'] }}
[student@workstation file-review]$ cat motd.yml
---
- name:
hosts: all
remote_user: devops
become: true
tasks:
- name:
template:
src: motd.j2
dest: /etc/motd
owner: root
group: root
mode: 0644
- name:
stat:
path: /etc/motd
register: stat_res
- name:
debug:
msg: "{{ stat_res }}"
- name:
copy:
src: files/issue
dest: /etc/
owner: root
group: root
mode: 0644
- name:
file:
src: /etc/issue
dest: /etc/issue.net
state: link
owner: root
group: root
force: yes
运行结果
[student@workstation file-review]$ ansible-playbook motd.yml
PLAY [all] ***************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************
ok: [serverb.lab.example.com]
TASK [template] **********************************************************************************************************************
changed: [serverb.lab.example.com]
TASK [stat] **************************************************************************************************************************
ok: [serverb.lab.example.com]
TASK [debug] *************************************************************************************************************************
ok: [serverb.lab.example.com] => {
"msg": {
"changed": false,
"failed": false,
"stat": {
"atime": 1616666801.3760493,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "860519cbc178f27e2a63bcdd38510709cf65710c",
"ctime": 1616666801.3780494,
"dev": 64513,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 8758505,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0644",
"mtime": 1616666800.7440493,
"nlink": 1,
"path": "/etc/motd",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 55,
"uid": 0,
"version": "2324674415",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
TASK [copy] **************************************************************************************************************************
changed: [serverb.lab.example.com]
TASK [file] **************************************************************************************************************************
changed: [serverb.lab.example.com]
PLAY RECAP ***************************************************************************************************************************
serverb.lab.example.com : ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
验证
注意:默认sshd是无法展示issue中的内容。以下结果是ansible的lab命令在初始化实验环境时,已经配置过sshd服务的。
如果想要展示,需要手动修改serverb中的 /etc/ssh/sshd_config文件,添加下面这一行:
Banner /etc/issue.net
这一行指定了banner的文件路径。默认情况下是:
# no default banner path
#Banner none
以下是ansible的执行结果:
[student@workstation file-review]$ ssh devops@serverb
*------------------------------- PRIVATE SYSTEM -----------------------------*
* Access to this computer system is restricted to authorised users only. *
* *
* Customer information is confidential and must not be disclosed. *
*----------------------------------------------------------------------------*
system total memory: 821 MiB
system processor count: 1
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Thu Mar 25 18:53:58 2021 from 172.25.250.9
大功告成!