Ansible-template-编写技巧

参考1
参考2

Ansible templates 由 Jinja2 templating language 来编写.

使用 template 主要是为了能在文档中展开 dynamic variables, 语法如 {{ variable_here }}.

简述 Jinja2 template

一般以 .j2 作为 Jinja2 template 的后缀 (主要是方便编辑器识别)

Ansible facts

参考

Ansible facts 是一些从 target nodes 上收集到的 data (IP, BIOS 信息, software, hardware info 等), 其用 JSON 格式保存, 可以通过 ansible_facts 变量访问.

不同系统的 fact 信息不同, 如:

1
2
3
4
5
6
7
8
9
10
- hosts: all
tasks:
- package:
name: "httpd"
state: present
when ansible_facts["os_name"] == "RedHat"
- package:
name: "apache2"
state: present
when ansible_facts["os_name"] == "Ubuntu"

访问 facts

在运行 playbook 前, Ansible 会用 setup module 来收集 facts 信息.

用 ad-hoc 命令获取

获取所有主机的全部 facts 信息:

1
ansible all -m setup -i inventory.yaml

输出如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fedora1 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.177.24"
],
"ansible_all_ipv6_addresses": [
"fe80::5054:ff:fe87:4814"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "04/01/2014",
"ansible_bios_vendor": "SeaBIOS",
"ansible_bios_version": "Arch Linux 1.16.3-1-1",
"ansible_board_asset_tag": "NA",
"ansible_board_name": "NA",
"ansible_board_serial": "NA",
"ansible_board_vendor": "NA",
"ansible_board_version": "NA",
"ansible_chassis_asset_tag": "NA",
"ansible_chassis_serial": "NA",
"ansible_chassis_vendor": "QEMU",
"ansible_chassis_version": "pc-q35-8.2",
...
...

可以通过设置 filter 来获取特定信息:

1
ansible all -m setup -a "filter=ansible_cmdline" -i inventory.yaml

输出如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fedora2 | SUCCESS => {
"ansible_facts": {
"ansible_cmdline": {
"BOOT_IMAGE": "(hd0,gpt2)/boot/vmlinuz-6.2.9-300.fc38.x86_64",
"quiet": true,
"rhgb": true,
"ro": true,
"root": "UUID=a08a148f-27f0-42e4-89d2-c93870c44df3"
},
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
fedora1 | SUCCESS => {
"ansible_facts": {
"ansible_cmdline": {
"BOOT_IMAGE": "(hd0,gpt2)/boot/vmlinuz-6.2.9-300.fc38.x86_64",
"quiet": true,
"rhgb": true,
"ro": true,
"root": "UUID=a82caaa6-edd3-4d6e-b330-5a77456c6e9f"
},
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}

在 playbook 中使用

在 playbook 中访问 facts 条目时, 需要使用原条目去掉 ansible 之后的名称, 如 ansible_facts["system"] 而不是 ansible_facts["ansible_system"].

如:

1
2
3
4
- hosts: all
tasks:
- debug:
var: ansible_facts

输出如:

输出指定条目:

1
2
3
4
- hosts: all
tasks:
- debug:
var: ansible_facts["cmdline"]

输出如:

示例

配置 httpd 的示例

编写 httpd.conf.j2 Apache 配置 template

httpd.conf.j2 文件的内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# This is the main Apache HTTP server configuration file
#
# {{ ansible_managed }}

ServerRoot "/etc/httpd"
Listen {{ http_port }}
Include conf.modules.d/*.conf

User apache
Group apache

ServerAdmin {{ admin }}@{{ ansible_hostname }}

<Directory />
AllowOverride none
Require all denied
</Directory>

DocumentRoot "{{ content_dir }}"

<Directory "{{ content_dir }}">
AllowOverride none
# Allow open access:
Require all granted
</Directory>

<Directory "{{ content_dir }}">
Options Indexes FollowSymLinks
AllowOverride none
Require all granted
</Directory>

<IfModule dir_module>
DirectoryIndex index.html
</IfModule>

<Files ".ht">
Require all denied
</Files>

ErrorLog "logs/error_log"

LogLevel warn

<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common

<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>

CustomLog "logs/access_log" combined
</IfModule>

<IfModule />
ScriptAlias /cgi-bin/"/var/www/cgi-bin"
</IfModule>

<Directory "/var/www/cgi-bin">
AllowOverride none
Options none
Require all granted
</Directory>

<IfModule mime_module>
TypesConfig /etc/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>

AddDefaultCharset UTF-8

<IfModule mime_magic_module>
MIMEMagicFile conf/magic
</IfModule>

EnableSendFile on

IncludeOptional conf.d/*.conf

编写 index.html.j2 template

index.html.j2 文件的内容为:

1
2
3
4
5
Welcome to {{ ansible_hostname }}
-The ipv4 address is {{ ansible_default_ipv4['address']}}
-The current memory usage is {{ ansible_memory_mb['real']['used']}}mb out of {{ ansible_memory_mb['real']['total']}}mb
-The {{ ansible_devices | first }} block device has the following partitions:
-{{ ansible_devices['vdb']['partitions'] | join('\n -')}}

Apache template playbook

apache-template.yml 文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Host to execute this playbook
- hosts: ansible01.test.lab
# Become root user
become: true
vars:
# Apache listen on Port 8080
http_port: 8080
admin: ansible-devops
# DocumentRoot set to content_dir var
# New DocumentRoot is webcontent
content_dir: /webcontent
tasks:
- name: Create Group for Webcontent
group:
name: webcontent
state: present
- name: Create Webcontent Dir
file:
path: /webcontent
state: directory
group: webcontent
owner: ansible-devops
mode: '2775'
- name: set mode to enforcing
selinux:
policy: targeted
state: enforcing
- name: enable httpd cgi boolean
seboolean:
name: httpd_enable_cgi
state: true
persistent: true
- name: Set SELinux Context on Directory
sefcontext:
target: "/webcontent(/.*)?"
setype: httpd_sys_content_t
state: present
- name: run restorecon
command: restorecon -irv /webcontent
# Push httpd Config Template
- name: push config template
template:
src: /home/vcirrus-consulting/RHCE-Ansible/templates/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
backup: true
# Notify handler to Restart Apache
notify: "restart apache"
# Push index Config Template
- name: push index.html template
template:
src: /home/vcirrus-consulting/RHCE-Ansible/templates/index.html.j2
dest: /webcontent/index.html
# Notify this hander, and Roll Out New Changed in Config File
handlers:
- name: restart web servers
service:
name: httpd
state: restarted
listen: "restart apache"

(注意在 playbook 中定义的 vars 可以在 template 中使用)

向 HTML Template 传入 list

index.j2 文件的内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<body>

<h1>Best Breakfast Items</h1>

<ul>

{% for breakfast_item in breakfast %}
<li> {{ breakfast_item }} </li>

{% endfor %}

</ul>

{% set today = ansible_date_time['weekday_number'] | int %}
{% if today == 2 %}
<p> Today is Tuesday, get a free coffe with your sandwich! </p>
{% else %}
<p> Stop in today for the best breakfast in town! </p>
{% endif %}

</body>
</html>

playbook.yml 文件的内容为:

1
2
3
4
5
6
7
8
9
10
- name: Breakfast test
hosts: servers
vars:
breakfast: ["Pepper and egg", "Coffee", "Giardiniera"]

tasks:
- name: Call template
template:
src: ~/ansibledemo/demo.j2
dest: /var/www/html/demo.html

Ansible-template-编写技巧
http://example.com/2024/03/20/Ansible-template-编写技巧/
作者
Jie
发布于
2024年3月20日
许可协议