在上一篇关于 Ansible 决策的教程中,您学习了如何使用 块文件 或者 排队 Ansible 模块。
在本教程中,您将学习如何使用 神社2 模板引擎 进行更多涉及和动态的文件修改。
您将学习如何访问 Jinja2 模板中的变量和事实。 此外,您将学习如何在 Jinja2 中使用条件语句和循环结构。
要尝试本教程中的示例,您应该按照正确的顺序学习整个 RHCE Ansible 教程系列。
在 Jinja2 中访问变量
Ansible 将在您的项目目录或名为的目录中查找 jinja2 模板文件 模板 在您的项目目录下。
让我们创建一个模板目录来保持更干净和更有条理:
[[email protected] plays]$ mkdir templates
[[email protected] plays]$ cd templates/
现在创建您的第一个 Jinja2 模板,名称为 索引.j2:
[[email protected] templates]$ cat index.j2
A message from {{ inventory_hostname }}
{{ webserver_message }}
请注意,Jinja2 模板文件名必须以 .j2 扩展名结尾。
这 库存主机名 是另一个 Ansible 内置(又名特殊或魔术)变量,它引用在剧中迭代的“当前”主机。 这 webserver_message 是您将在剧本中定义的变量。
现在回到您的项目目录并创建以下内容 检查-apache.yml:
[[email protected] plays]$ cat check-apache.yml
---
- name: Check if Apache is Working
hosts: webservers
vars:
webserver_message: "I am running to the finish line."
tasks:
- name: Start httpd
service:
name: httpd
state: started
- name: Create index.html using Jinja2
template:
src: index.j2
dest: /var/www/html/index.html
请注意, httpd 软件包已在上一个教程中安装。
在本手册中,您首先要确保 Apache 在第一个任务中运行 Start httpd
. 然后使用 模板 第二个任务中的模块 Create index.html
使用 Jinja2 处理和传输 索引.j2 您创建到目的地的 Jinja2 模板文件 /var/www/html/index.html.
继续运行剧本:
[[email protected] plays]$ ansible-playbook check-apache.yml
PLAY [Check if Apache is Working] **********************************************
TASK [Gathering Facts] *********************************************************
ok: [node3]
ok: [node2]
TASK [Start httpd] *************************************************************
ok: [node2]
ok: [node3]
TASK [Create index.html using Jinja2] ******************************************
changed: [node3]
changed: [node2]
PLAY RECAP *********************************************************************
node2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
到目前为止一切看起来都不错; 让我们运行一个快速的临时 Ansible 命令来检查 索引.html 在网络服务器节点上:
[[email protected] plays]$ ansible webservers -m command -a "cat /var/www/html/index.html"
node3 | CHANGED | rc=0 >>
A message from node3
I am running to the finish line.
node2 | CHANGED | rc=0 >>
A message from node2
I am running to the finish line.
惊人的! 请注意 Jinja2 是如何获取 库存主机名 内置变量和 webserver_message 你的剧本中的变量。
您还可以使用 curl 命令查看是否从两个网络服务器获得响应:
[[email protected] plays]$ curl node2.linuxhandbook.local
A message from node2
I am running to the finish line.
[[email protected] plays]$ curl node3.linuxhandbook.local
A message from node3
I am running to the finish line.
访问 Jinja2 中的事实
您可以像访问 playbook 中的事实一样访问 Jinja2 模板中的事实。
为了演示,更改为您的 模板 目录并创建 信息.j2 Jinja2 文件,内容如下:
[[email protected] templates]$ cat info.j2
Server Information Summary
--------------------------
hostname={{ ansible_facts['hostname'] }}
fqdn={{ ansible_facts['fqdn'] }}
ipaddr={{ ansible_facts['default_ipv4']['address'] }}
distro={{ ansible_facts['distribution'] }}
distro_version={{ ansible_facts['distribution_version'] }}
nameservers={{ ansible_facts['dns']['nameservers'] }}
totalmem={{ ansible_facts['memtotal_mb'] }}
freemem={{ ansible_facts['memfree_mb'] }}
请注意 信息.j2 访问八个不同的事实。 现在回到您的项目目录并创建以下内容 服务器信息.yml 剧本:
[[email protected] plays]$ cat server-info.yml
---
- name: Server Information Summary
hosts: all
tasks:
- name: Create server-info.txt using Jinja2
template:
src: info.j2
dest: /tmp/server-info.txt
请注意,您正在创建 /tmp/server-info.txt 在所有主机上基于 信息.j2 模板文件。 继续运行剧本:
[[email protected] plays]$ ansible-playbook server-info.yml
PLAY [Server Information Summary] *******************************************
TASK [Gathering Facts] **********************************
ok: [node4]
ok: [node1]
ok: [node3]
ok: [node2]
TASK [Create server-info.txt using Jinja2] ********
changed: [node4]
changed: [node1]
changed: [node3]
changed: [node2]
PLAY RECAP *************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node4 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
一切看起来都不错! 现在让我们运行一个快速的临时命令来检查 /tmp/server-info.txt 在其中一个节点上的文件:
[[email protected] plays]$ ansible node1 -m command -a "cat /tmp/server-info.txt"
node1 | CHANGED | rc=0 >>
Server Information Summary
--------------------------
hostname=node1
fqdn=node1.linuxhandbook.local
ipaddr=10.0.0.5
distro=CentOS
distro_version=8.2
nameservers=['168.63.129.16']
totalmem=1896
freemem=1087
如您所见,Jinja2 能够访问和处理所有事实。
Jinja2 中的条件语句
您可以使用 如果 Jinja2 中的条件语句,用于测试各种条件和比较变量。 这允许您根据您的测试条件确定您的文件模板执行流程。
要演示,请转到您的 模板 目录并创建以下内容 selinux.j2 模板:
[[email protected] templates]$ cat selinux.j2
{% set selinux_status = ansible_facts['selinux']['status'] %}
{% if selinux_status == "enabled" %}
"SELINUX IS ENABLED"
{% elif selinux_status == "disabled" %}
"SELINUX IS DISABLED"
{% else %}
"SELINUX IS NOT AVAILABLE"
{% endif %}
模板中的第一条语句创建一个新变量 selinux_statusand
将其值设置为 ansible_facts['selinux']['status']
.
然后你使用 selinux_status
在你的 如果 测试条件判断是否 SELinux 已启用、禁用或未安装。 在这三种不同的情况下,您都会显示一条反映 Selinux 状态的消息。
注意如何 如果 Jinja2 中的语句模仿 Python 的 如果 陈述; 只是不要忘记使用 {% endif %}
.
现在回到您的项目目录并创建以下内容 selinux-status.yml 剧本:
[[email protected] plays]$ cat selinux-status.yml
---
- name: Check SELinux Status
hosts: all
tasks:
- name: Display SELinux Status
debug:
msg: "{{ ansible_facts['selinux']['status'] }}"
- name: Create selinux.out using Jinja2
template:
src: selinux.j2
dest: /tmp/selinux.out
继续运行剧本:
[[email protected] plays]$ ansible-playbook selinux-status.yml
PLAY [Check SELinux Status] ****************************************************
TASK [Gathering Facts] *********************************************************
ok: [node4]
ok: [node2]
ok: [node3]
ok: [node1]
TASK [Display SELinux Status] **************************************************
ok: [node1] => {
"msg": "enabled"
}
ok: [node2] => {
"msg": "disabled"
}
ok: [node3] => {
"msg": "enabled"
}
ok: [node4] => {
"msg": "Missing selinux Python library"
}
TASK [Create selinux.out using Jinja2] *****************************************
changed: [node4]
changed: [node1]
changed: [node3]
changed: [node2]
PLAY RECAP *********************************************************************
node1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 node4 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
从剧本输出; 你可以看到 SELinux 在两者上都启用了 节点1 和 节点3. 我禁用了 SELinux 节点2 在运行剧本之前 节点4 没有安装 SELinux,因为 Ubuntu 使用 AppArmor 而不是 SELinux。
最后,您可以运行以下临时命令来检查 selinux.out 在所有托管主机上:
[[email protected] plays]$ ansible all -m command -a "cat /tmp/selinux.out"
node4 | CHANGED | rc=0 >>
"SELINUX IS NOT AVAILABLE"
node2 | CHANGED | rc=0 >>
"SELINUX IS DISABLED"
node3 | CHANGED | rc=0 >>
"SELINUX IS ENABLED"
node1 | CHANGED | rc=0 >>
"SELINUX IS ENABLED"
在 Jinja2 中循环
您可以使用 为了 Jinja2 中的语句来循环列表、范围等中的项目。对于 example,下面的 for 循环将遍历 范围(1,11)因此将显示 1->10 的数字:
{% for i in range(1,11) %}
Number {{ i }}
{% endfor %}
注意 Jinja2 中的 for 循环是如何模仿 Python 的 for 循环的语法的; 再次不要忘记结束循环 {% endfor %}
.
现在让我们创建一个完整的 example 这展示了 Jinja2 中 for 循环的强大功能。 切换到您的模板目录并创建以下内容 主机.j2 模板文件:
[[email protected] templates]$ cat hosts.j2
{% for host in groups['all'] %}
{{ hostvars[host].ansible_facts.default_ipv4.address }} {{ hostvars[host].ansible_facts.fqdn }} {{ hostvars[host].ansible_facts.hostname }}
{% endfor %}
注意这里你使用了一个新的内置特殊(魔术)变量 主机变量 这基本上是一个字典,其中包含清单中的所有主机和分配给它们的变量。
您遍历清单中的所有主机,然后遍历每个主机; 您显示了三个变量的值:
- {{主机变量[host].ansible_facts.default_ipv4.address }}
- {{主机变量[host].ansible_facts.fqdn }}
- {{主机变量[host].ansible_facts.hostname }}
另请注意,您必须在同一行并排包含这三个变量以匹配 /etc/hosts 文件。
现在回到您的项目目录并创建以下内容 本地 dns.yml 剧本:
[[email protected] plays]$ cat local-dns.yml
---
- name: Dynamically Update /etc/hosts File
hosts: all
tasks:
- name: Update /etc/hosts using Jinja2
template:
src: hosts.j2
dest: /etc/hosts
然后继续运行剧本:
[[email protected] plays]$ ansible-playbook local-dns.yml
PLAY [Dynamically Update /etc/hosts File] *********************************************
TASK [Gathering Facts] ***************************
ok: [node4]
ok: [node2]
ok: [node1]
ok: [node3]
TASK [Update /etc/hosts using Jinja2] ***********************************************
changed: [node4]
changed: [node3]
changed: [node1]
changed: [node2]
PLAY RECAP **********************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node4 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
到目前为止一切看起来都不错; 现在运行以下临时命令来验证 /etc/hosts 文件已正确更新 节点1:
[[email protected] plays]$ ansible node1 -m command -a "cat /etc/hosts"
node1 | CHANGED | rc=0 >>
10.0.0.5 node1.linuxhandbook.local node1
10.0.0.6 node2.linuxhandbook.local node2
10.0.0.7 node3.linuxhandbook.local node3
10.0.0.8 node4.linuxhandbook.local node4
完美的! 看起来像您预期的那样正确格式化。
我希望您现在意识到 Ansible 中 Jinja2 模板的强大功能。 请继续关注下一个教程,您将在其中学习使用 Ansible Vault 保护敏感信息和文件。