目录
前篇《ansible 剧本Playbooks(六)角色roles》讲了以nginx为角色实现了自动化安装,但nginx配置部分没有使用模板。
学好模板templates是很有必要的,是ansible使用的是jinja2模板引擎,所以得先了解一下jinja2的使用,再学模板。
一、Jinja2 介绍
1.1 模板的作用
模板功能可以帮助我们灵活的生成配置文件,我们只需要先选择一个文件作为模板文件,然后修改模板文件中需要灵活生成的部分,使用变量进行替换(对应的变量必须提前定义好或者能够在运行时获取),模板文件中不需要灵活生成的部分保持不变即可,当需要为各个目标主机生成配置文件时,只需调用template模块,templdte模块会在ansible控制机中对模板文件进行渲染,最终生成各个主机对应的配置文件,然后拷贝到远程主机的指定位置中。
除了在playbook中能够使用template模块,在ad-hoc命令中也可以直接调用templdate模块,在ad-hoc命令中使用templdate模块比较方便我们测试模板文件的最终生成效果。
PS:简单来说ansible模板就是把配置文件不变的部分固定,把变的部分抽取出来,以变量的方式代替,这样你就不用每次都编辑配置文件了。
比如nginx配置,只需要修改域名、网站目录、日志目录及名字,其它基本上不变,那么你就可以做成模板方式,把不变的部分固定下来,变的部分用变量代替。以后配置nginx直接使用模板就行。只需要填写域名domain、网站目录sitePath、日志目录logDir、logName即可。大大提高工作效果。
1.2 jinja2模板引擎
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全。
ansible使用的是jinja2模板引擎,如果想要更加灵活的编辑模板文件,最好还要了解一些与jinja2有关的基本知识点,其实,我们一直都在使用jinja2的语法,当我们在playbook中引用变量时,会将变量用双括号"{{ }}“括起,这就是jinja2的语法,在jinja2中,使用”{{ }}“装载变量,除了”{{ }}",还有一些其他的jinja2基本语法。
{{ }} :用来装载表达式,比如变量、运算表达式、比较表达式等。
{% %} :用来装载控制语句,比如 if 控制结构,for循环控制结构。
{# #} :用来装载注释,模板文件被渲染后,注释不会包含在最终生成的文件中。
二、Jinja2表达式
可以看翻译的Jinja2表达式
2.1 字面量
表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。下面 的字面量是可用的:
2.1.1 引号
#引号
如:“Hello World”
双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字 符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),它们都是 有用的。
和其它编程语言一样:双引号特殊符号会生效,单引号是原样输出。
2.1.2 整数和浮点数
#整数和浮点数
如:42 / 42.23
直接写下数值就可以创建整数和浮点数。如果有小数点,则为浮点数,否则为 整数。记住在 Python 里, 42 和 42.0 是不一样的。42属于整数,42.0属性浮点数。
2.1.3 列表
#列表
如:[‘list’, ‘of’, ‘objects’]
一对中括号括起来的东西是一个列表。列表用于存储和迭代序列化的数据。例如 你可以容易地在 for 循环中用列表和元组创建一个链接的列表
<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
('downloads.html', 'Downloads')] %}
<li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
PS:官方用的是html,其实我们不一定要使用html,根据配置的不同而定,主要是学会它的使用方法,不要转不过弯。
2.1.4 元组
#元组
如: (‘tuple’, ‘of’, ‘values’)
元组与列表类似,只是你不能修改元组。如果元组中只有一个项,你需要以逗号 结尾它。元组通常用于表示两个或更多元素的项。更多细节见上面的例子。
2.1.5 字典
#字典
如:{‘dict’: ‘of’, ‘key’: ‘and’, ‘value’: ‘pairs’}
2.1.6 布尔类型
#真假
true / false
true 永远是 true ,而 false 始终是 false 。
2.2 算术
Jinja 允许你用计算值。这在模板中很少用到,但是为了完整性允许其存在。支持下面的 运算符:
符号 | 说明 |
---|---|
+ | 把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。 无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2 。 |
- | 用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1 。 |
/ | 对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }} |
// | 对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2 |
% | 计算整数除法的余数。 {{ 11 % 7 }} 等于 4 |
* | 用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ ‘=’ * 80 }} 会打印 80 个等号的横条 |
** | 取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8 |
2.3 比较操作符
符号 | 说明 |
---|---|
== | 比较两个对象是否相等 |
!= | 比较两个对象是否不等 |
> | 如果左边大于右边,返回 true |
>= | 如果左边大于等于右边,返回 true |
< | 如果左边小于右边,返回 true |
<= | 如果左边小于等于右边,返回 true 。 |
2.4 逻辑运算符
符号 | 说明 |
---|---|
and | 如果左操作数和右操作数同为真,返回 true |
or | 如果左操作数和右操作数有一个为真,返回 true |
not | 对一个表达式取反(见下) |
(expr) | 表达式组 |
2.5 其它运行符
下面的运算符非常有用,但不适用于其它的两个分类:
符号 | 说明 |
---|---|
in | 运行序列/映射包含检查。如果左操作数包含于右操作数,返回 true 。比如 {{ 1 in[1,2,3] }} 会返回 true |
is | 运行一个 测试 |
| | 应用一个 过滤器 |
~ | 把所有的操作数转换为字符串,并且连接它们。 {{ "Hello " ~ name ~ "!" }} 会返回(假设 name 值为 ''John' ) Hello John! |
() | 调用一个可调用量:{{ post.render() }} 。 在圆括号中,你可以像在 python 中一样使用位置参数和关键字参数:{{ post.render(user, full=true) }} 。 |
. / [] | 获取一个对象的属性。(见 变量 ) |
2.6 其它
除外之外,Jinja2还提供了非常有用的“test”语句,比如:我们可以使用如下语句来判断变量foo是否被定义过
foo is defined
当变量foo被定义过,那么这个表达式的结果就是true,相反则为false。使用起来非常直接,就与直接用英文对话一样。类似的还有:undefined(与defined相反),equalto(与==等效),even(判断对象是否是偶数)以及iterable(判断对象是否可迭代)。
三、变量
变量语法: {{ 变量名 }}
注意:变量名左右两边有空格的
执行语句:{% 执行语句 %}
注意:执行语句左右两边有空格的
{% ... %} 和 {{ ... }}
前者用于执行诸如 for 循环 或赋值的语句,后者把表达式的结果打印到模板上
你可以使用点( . )来访问变量的属性,作为替代,也可以使用所谓的“下标”语 法( [] )。下面的几行效果是一样的:
{{ foo.bar }}
{{ foo['bar'] }}
四、过滤器
变量可以通过 过滤器 修改。过滤器与变量用管道符号( | )分割,并且也 可以用圆括号传递可选参数。多个过滤器可以链式调用,前一个过滤器的输出会被作为 后一个过滤器的输入。
例如 {{ name|striptags|title }} 会移除 name 中的所有 HTML 标签并且改写 为标题样式的大小写格式。过滤器接受带圆括号的参数,如同函数调用。这个例子会 把一个列表用逗号连接起来: {{ list|join(', ') }} 。
内置过滤器清单 中介绍了所有的内置过滤器
五、Jinja2其它
5.1 条件语句
条件语句的语法如下:
{% if 表达式 %}
...
{% endif %}
例子不讲了,自己看
5.2 for语句
for语句的语法
{% for item in all_items%}
{{ item }}
{% endif %}
5.3 注解
要把模板中一行的部分注释掉,默认使用 {# ... #} 注释语法。这在调试或 添加给你自己或其它模板设计者的信息时是有用的:
{# note: disabled template because we no longer use this
{% for user in users %}
...
{% endfor %}
#}
5.4 空白控制
默认配置中,模板引擎不会对空白做进一步修改,所以每个空白(空格、制表符、换行符 等等)都会原封不动返回。如果应用配置了 Jinja 的 trim_blocks ,模板标签后的 第一个换行符会被自动移除(像 PHP 中一样)。
此外,你也可以手动剥离模板中的空白。当你在块(比如一个 for 标签、一段注释或变 量表达式)的开始或结束放置一个减号( - ),可以移除块前或块后的空白:
{% for item in seq -%}
{{ item }}
{%- endfor %}
5.5 转义
原样输出用单引号,对于较大的段落,标记一个块为 raw 是有意义的。例如展示 Jinja 语法的实例, 你可以在模板中用这个片段:
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
5.6 其它
其它的自己看我这里不说了,复制粘贴意义不大
六、结合python
少数Jin2并不能发挥强大的功能场景中,我们可以使用Python的内置方法来进行补充,比如:string.split和[number].is_signed()等。
我们来看如下一个应用场景,目前我们有一款软件版本号为4.6.1,现在有一个任务需要通过判断软件的版本号来确定要不要执行接下来的任务,如果主版本号为4就执行任务,其它版本则不执行。这时,Jinja2表达式将不再适合,我们可以通过Python的内置方法,使用点号“.”来对版本号进行拆分后取得第1位主版本号,然后用它与数字4进行比较。具体代码如下:
- name: 当软件主版本号为4的时候进行操作
[task here]
when: software_version.split(‘.’)[0] == ‘4’
通常我们建议尽量使用更为简洁的Jinja2语句来进行判断,但是在涉及变量的复杂操作时,Python的内置方法还是不错的选择。