管理变量、机密和事实
1. Ansible 管理变量简介
1.1 概念
1.1.1 命名变量
1.2 定义变量
1.2.1 定义变量的方式
2. playbook中的变量变量
2.1 在Playbook中定义变量
2.2 主机变量和组变量
2.3 使用目录填充主机和组变量
2.4 从命令行覆盖变量
2.5 使用数组作为变量
2.6 捕捉变量
3. 管理机密
3.1 Ansible Vault
3.1.1 创建加密的文件
3.1.2 查看加密的文件
3.1.3 解密已经加密的文件
3.1.4 文件已经存在现在进行加密
3.1.5 编辑已经加密的文件
3.1.6 已经加密的文件重新加密
3.2 playbook和ansible vault
3.2.1 变量文件管理的推荐做法
4. 管理事实
4.1 描述Ansible事实
4.2 Ansible事实作为变量注入
4.3 关闭事实收集
4.4 创建自定义事实
4.5 使用魔法变量
1. Ansible 管理变量简介
1.1 概念
变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如nginx-1.6.3这个软件包的版本,在其它地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本,并减少错误的数量。
通过变量,可以轻松地在Ansible项目中管理给定环境的动态值。例如,变量可能包含下面这些值:
- 要创建的用户
- 要安装的软件包
- 要重新启动的服务
- 要删除的文件
- 要从互联网检索的存档
1.1.1 命名变量
变量的名称必须以字母开头,并且只能包含字母、数字和下划线。
无效和有效的Ansible变量名称示例
无效的变量名称 | 有效的变量名称 |
web server | web_server |
remote.file | remote_file |
1st file | file_1 file1 |
remoteserver$1 | remote_server_1 remote_server1 |
1.2 定义变量
可以在Ansible项目中的多个位置定义变量。不过,这些变量大致可简化为三个范围级别:
- 全局范围:从命令行或Ansible配置设置的变量
- Play范围:在play和相关结构中设置的变量
- 主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
如果在多个xeklh定义了相同名称的变量,则采用优先级别最高的变量。窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖。
1.2.1 定义变量的方式
- 通过命令行进行变量定义
- 在playbook文件中进行变量定义
- 通过Inventory主机信息文件中进行变量定义
- 通过vars_files的方式定义变量
- 通过host_vars和group_vars定义变量
2. playbook中的变量变量
在Ansible Playbook中发挥着重要作用,因为它们可以简化playbook中变量数据的管理。
2.1 在Playbook中定义变量
编写playbook时,可以定义自己的变量,然后在任务中调用这些值。例如,名为web_package的变量可以使用值httpd来定义。然后,任务可以使用yum模块调用该变量来安装httpd软件包。
Playbook变量可以通过多种方式定义。一种常见的方式是将变量放在playbook开头的vars块中:
[root@yibie ~]# cd /etc/ansible/
[root@yibie ansible]# cd playbook/
[root@yibie playbook]# vim apache.yml
[root@yibie playbook]# cat apache.yml
---
- hosts:apache
vars:
name:yibie
uid:1314
tasks:
- name:create user
user:
name:"{{name}}"
uid:"{{uid}}"
state:present
[root@yibie playbook]# id yibie
uid=1001(yibie) gid=1314(yibie) 组=1314(yibie)
[root@yibie playbook]#
也可以在外部文件中定义playbook变量,此时不使用playbook中的vars块,可以改为使用vars_file指令,后面跟上相对于playbook位置的外部变量文件名称列表
[root@yibie playbook]# ls
apache.yml lamp.yml
[root@yibie playbook]# mkdir vars
[root@yibie playbook]# vim vars/yibie.yml
[root@yibie playbook]# cat vars/yibie.yml
content: yibie yyds!
[root@yibie playbook]# cat user.yml
---
- hosts: 192.168.57.30
vars_files:
- vars/yibie.yml
tasks:
- name:
shell: "echo {{ content }} > /tmp/abc"
[root@yibie-apache ~]# cat /tmp/abc
yibie yyds!
2.2 主机变量和组变量
直接应用于主机的清单变量分为两在类:
- 主机变量,应用于特定主机
- 组管理,应用于一个主机或一组主机组中的所有主机
主机变量优先于组变量,但playbook中定义的变量的优先级比这两者更高
若要定义主机变量和组变量,一种方法是直接在清单文件中定义,这是较旧的做法,不建议采用,但你可能会在未来工作中遇到
定义192.168.47.147的ansible_user主机变量
[servers]
192.168.57.30 ansible_user=root
定义servers主机组的user组变量
[servers]
192.168.57.30
192.168.57.50
[servers:vars]
user=root
定义servers组的user组变量,该组由两个主机组成,每个主机组有两个服务器:
[servers1]
192.168.57.30
192.168.57.50
[server2]
192.168.57.20
192.168.57.40
[servers:children]
server1
server2
[servers:vars]
user=root
此做法存在的缺点,它使得清单文件更难以处理,在同一文件中混合提供了主机和变量信息,而且采用得也是过时的语法
2.3 使用目录填充主机和组变量
定义主机和主机组的变量的首选做法是在与清单文件或目录相同的工作目录中,创建group_vars和host_vars两个目录。这两个目录分别包含用于定义组变量和主机变量的文件
建议的做法是使用host_vars和group_vars目录定义清单变量,而不直接在清单文件中定义他妈
为了定义用于servers组的组变量,需要创建名为group_vars/servers的YAML文件,然后该文件的内容将使用与playbook相同的语法将变量设置为值
2.4 从命令行覆盖变量
清单变量可被playbook中设置的变量覆盖,这两种变量又可通过在命令行中传递参数到ansible或ansible-playbook命令来覆盖。在命令行上设置的变量称为额外变量。
当需要覆盖一次性运行的playbook的变量的一定义值时,额外变量非常有用
[root@yibie playbook]# cat user.yml
---
- name: task1
hosts: 192.168.57.30
tasks:
- name: chuangjianyonghu
user:
name: "{{ user }}"
state: present
[root@yibie ansible]# ansible-playbook -e "user=awm" playbook/user.yml
PLAY [task1] *******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.57.30]
TASK [chuangjianyonghu] ********************************************************
changed: [192.168.57.30]
PLAY RECAP *********************************************************************
192.168.57.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.5 使用数组作为变量
除了将同一元素相关的配置数据(软件包列表、服务列表和用户列表等)分配到多个变量外,也可以使用数组。这种做法的一个好处在于,数组是可以浏览的。
[root@yibie playbook]# ls
apache.yml lamp.yml user.yml vars
[root@yibie playbook]# cd vars/
[root@yibie vars]# vim info.yml
[root@yibie vars]# cat info.yml
info:
yibie:
first_name: yi
last_name: bie
age: 20
awm:
first_name: a
first_name: wm
age: 22
[root@yibie vars]# cd
[root@yibie ~]# cd /etc/ansible/playbook/
[root@yibie playbook]# vim test.yml
[root@yibie playbook]# cat test.yml
---
- hosts: 192.168.57.30
gather_facts: no
vars_files:
- vars/info.yml
tasks:
- name: x
shell: echo {{ info }} >/tmp/abc
[root@yibie playbook]# ansible-playbook test.yml
PLAY [192.168.57.30] ************************************************************
TASK [x] ************************************************************************
changed: [192.168.57.30]
PLAY RECAP **********************************************************************
192.168.57.30 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.6 捕捉变量
使用register语句捕获命令输出。输出保存在一个临时变量中,然后在playbook中可用于调试用途或者达成其他目的
[root@yibie playbook]# vim test.yml
[root@yibie playbook]# cat test.yml
---
- hosts: 192.168.57.30
gather_facts: no
tasks:
- name: register variables
command: "df -h"
register: result //随便定义
- debug: var=result //debug:打印;var=随便定义
[root@yibie playbook]# ansible-playbook test.yml
PLAY [192.168.57.30] ************************************************************
TASK [register variables] *******************************************************
changed: [192.168.57.30]
TASK [debug] ********************************************************************
ok: [192.168.57.30] => {
"result": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"cmd": [
"df",
"-h"
],
"delta": "0:00:00.003676",
"end": "2021-07-23 21:39:18.178323",
"failed": false,
"rc": 0,
"start": "2021-07-23 21:39:18.174647",
"stderr": "",
"stderr_lines": [],
"stdout": "文件系统 容量 已用 可用 已用% 挂载点\ndevtmpfs 1.9G 0 1.9G 0% /dev\ntmpfs 1.9G 0 1.9G 0% /dev/shm\ntmpfs 1.9G 11M 1.9G 1% /run\ntmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup\n/dev/mapper/rhel-root 50G 5.7G 45G 12% /\n/dev/sr0 7.9G 7.9G 0 100% /mnt/cdrom\n/dev/mapper/rhel-home 46G 354M 45G 1% /home\n/dev/nvme0n1p1 1014M 229M 786M 23% /boot\ntmpfs 376M 1.2M 375M 1% /run/user/42\ntmpfs 376M 4.6M 371M 2% /run/user/0",
"stdout_lines": [
"文件系统 容量 已用 可用 已用% 挂载点",
"devtmpfs 1.9G 0 1.9G 0% /dev",
"tmpfs 1.9G 0 1.9G 0% /dev/shm",
"tmpfs 1.9G 11M 1.9G 1% /run",
"tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup",
"/dev/mapper/rhel-root 50G 5.7G 45G 12% /",
"/dev/sr0 7.9G 7.9G 0 100% /mnt/cdrom",
"/dev/mapper/rhel-home 46G 354M 45G 1% /home",
"/dev/nvme0n1p1 1014M 229M 786M 23% /boot",
"tmpfs 376M 1.2M 375M 1% /run/user/42",
"tmpfs 376M 4.6M 371M 2% /run/user/0"
]
}
}
PLAY RECAP **********************************************************************
192.168.57.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@yibie playbook]# vim test.yml
[root@yibie playbook]# cat test.yml
---
- hosts: 192.168.57.30
gather_facts: no
tasks:
- name: register variables
user:
name: yibie
state: present
register: result
- debug: var=result['uid']
[root@yibie playbook]# ansible-playbook test.yml
PLAY [192.168.57.30] ************************************************************
TASK [register variables] *******************************************************
ok: [192.168.57.30]
TASK [debug] ********************************************************************
ok: [192.168.57.30] => {
"result['uid']": "1000"
}
PLAY RECAP **********************************************************************
192.168.57.30 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@yibie playbook]#
3. 管理机密
3.1 Ansible Vault
ansible可能需要访问密码或apl密钥等敏感数据,以便能配置受管主机,通常,此信息可能以纯文本形式存储于清单变量或其他ansible文件中,但,任何有权访问ansible文件的用户都能访问到,存在安全风险
ansible提供得ansible vault可以解密加密任何由ansible使用得结构化数据文件。若要使用ansible-vault,可通过ansible-vault的命令行工具创建、编辑、加密、解密和查看文件
3.1.1 创建加密的文件
使用ansible-vault create filename创建一个新的加密文件,输入密码,默认编辑器是vi打开文件
[root@yibie ansible]# ansible-vault create group_vars/apache
New Vault password:
Confirm New Vault password:
3.1.2 查看加密的文件
使用ansbile-vault view filename查看加密的文件,而不必打开它编辑
[root@yibie ansible]# cat group_vars/apache
$ANSIBLE_VAULT;1.1;AES256
38383666613461336362366130613932303061333538633535333237313964356637333434653932
6631396362613033646266613034623466366530356236380a643839336630396661626262626462
37333837363339333064656261663163333065623065386531643562653062306339373264333334
3638326433336461620a623737643039346466616130633633613564333435383733646238646430
37613932303931666332653263653966383266313162636434653036383935323731
[root@yibie ansible]# ansible-vault view group_vars/apache
Vault password:
ansible_user=root
ansible_password=123456
3.1.3 解密已经加密的文件
使用ansbile-vault decrypt filename命令,永久解密
[root@yibie ansible]# ansible-vault decrypt group_vars/apache
Vault password:
Decryption successful
[root@yibie ansible]# cat group_vars/apache
ansible_user=root
ansible_password=123456
3.1.4 文件已经存在现在进行加密
使用ansible-vault encrypt filename
[root@yibie ansible]# ansible-vault encrypt group_vars/apache
New Vault password:
Confirm New Vault password:
Encryption successful
3.1.5 编辑已经加密的文件
使用ansible-vaule edit filename
[root@yibie ansible]# ansible-vault edit group_vars/apache
Vault password: //这里输入密码
//输入密码后自动进入vi编辑器
//输入修改内容
3.1.6 已经加密的文件重新加密
使用ansible-vault rekey filename,修改新的密码需要输入旧的密码
[root@yibie ansible]# ansible-vault rekey group_vars/apache
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
3.2 playbook和ansible vault
要运行可访问通过ansible vault加密的文件的playbook,需要向ansible-playbook命令提供加密文件,如果不提供密码,playbook将返回错误
[root@yibie ansible]# ansible-playbook playbook/test.yml //没有提供密码
ERROR! Attempting to decrypt but no vault secrets found
要为playbook提供vault密码,可使用–vault-id选项,列如
[root@yibie ansible]# ansible-playbook --vault-id @prompt playbook/test.yml
Vault password (default):
PLAY [*] ***********************************************************************
TASK [create user huihui] ******************************************************
changed: [192.168.57.30]
PLAY RECAP *********************************************************************
192.168.57.30 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
此外,也可使用–vault-password-file=文件名[
[root@yibie ~]# openssl rand -base64 20 //这是随机生成一个密码
2bWCqoQ6vESMQhcoufWrzFcE1EU=
//解密
[root@yibie ansible]# ansible-vault decrypt --vault-password-file=.hhh group_vars/apache
Decryption successful
[root@yibie ansible]# cat group_vars/apache
ansible_user=root
ansible_password=123456
wo neng ni die
[root@yibie ansible]# vim .hhh
[root@yibie ansible]# ansible-vault encrypt --vault-password-file=.hhh group_vars/apache
Encryption successful
[root@yibie ansible]# vim .xxx //进去修改
[root@yibie ansible]# ansible-vault rekey --vault-password-file=.hhh --new-vault-password-file=.xxx group_vars/apache
Rekey successful
3.2.1 变量文件管理的推荐做法
大致意思就是把需要加密的变量放在一个文件下,不需要加密的变量放在另一个文件下,意思就是分开放
[root@yibie ansible]# cat playbook/test.yml
---
- hosts: "*"
gather_facts: no
vars_files:
- vars/users.yml
tasks:
- name: create user {{ user }}
user:
user: "{{ user }}"
state: present
[root@yibie ansible]# cat .hhh
123456..
[root@yibie ansible]# ansible-vault create --vault-password-file=.hhh playbook/vars/users.yml
[root@yibie ansible]# ansible-playbook --vault-password-file=.hhh playbook/test.yml
PLAY [*] ****************************************************************************************************
TASK [Gathering Facts] **************************************************************************************
ok: [192.168.57.30]
TASK [create user huihui] ***************************************************************************************
changed: [192.168.57.30]
PLAY RECAP **************************************************************************************************
192.168.57.30 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@yibie-apache ~]# id huihui
uid=4002(huihui) gid=4002(huihui) 组=4002(huihui)
[root@yibie-apache ~]#
4. 管理事实
4.1 描述Ansible事实
Ansible事实是Ansible在受管主机上自动检测到的变量。事实中包含有与主机相关的信息,可以像play中的常规变量、条件、循环或依赖于从受管主机收集的值的任何其他语句那样使用。
为受管主机收集的一些事实可能包括:
- 主机名称
- 内核版本
- 网络接口
- IP地址
- 操作系统版本
- 各种环境变量
- CPU数量
- 提供的或可用的内存
- 可用磁盘空间
借助事实,可以方便地检索受管主机的状态,并根据该状态确定要执行的操作。例如:
- 可以根据含有受管主机当前内核版本的事实运行条件任务,以此来重启服务器
- 可以根据通过事实报告的可用内存来自定义MySQL配置文件
- 可以根据事实的值设置配置文件中使用的IPv4地址
通常,每个play在执行第一个任务之前会先自动运行setup模块来收集事实。
在命令行里
[root@yibie ansible]# ansible 192.168.57.30 -m setup | less
192.168.57.30 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.122.1",
"192.168.57.30"
],
"ansible_all_ipv6_addresses": [
"fe80::20c:29ff:fe41:dafa"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "07/29/2019",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "(hd0,msdos1)/vmlinuz-4.18.0-193.el8.x86_64",
"crashkernel": "auto",
省略
在playbook里
[root@yibie ansible]# vim playbook/test.yml
[root@yibie ansible]# cat playbook/test.yml
---
- hosts: "*"
tasks:
- name: yibie
debug:
var: ansible_facts //var变量的意思
[root@yibie playbook]# ansible-playbook test.yml //这是获取全部
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.57.30]
TASK [yibie] *******************************************************************
ok: [192.168.57.30] => {
"ansible_facts": {
"all_ipv4_addresses": [
"192.168.122.1",
"192.168.57.30"
],
"all_ipv6_addresses": [
"fe80::20c:29ff:fe41:dafa"
省略
在playbook里获取想要的事实
[root@yibie playbook]# vim test.yml
[root@yibie playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: yibie
debug:
var: ansible_facts['all_ipv4_addresses']
[root@yibie playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.57.30]
TASK [yibie] *******************************************************************
ok: [192.168.57.30] => {
"ansible_facts['all_ipv4_addresses']": [
"192.168.122.1",
"192.168.57.30" //结果
]
}
PLAY RECAP *********************************************************************
192.168.57.30 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
获取的更加精确一点
[root@yibie playbook]# vim test.yml
[root@yibie playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: yibie
debug:
var: ansible_facts['all_ipv4']['addresses'] //区别
[root@yibie playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.57.30]
TASK [yibie] *******************************************************************
ok: [192.168.57.30] => {
"ansible_facts['all_ipv4']['addresses']": "VARIABLE IS NOT DEFINED!" //结果
}
PLAY RECAP *********************************************************************
192.168.57.30 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
另一种方法获取,python方式,不建议使用
[root@yibie playbook]# cat test.yml
---
- hosts: "*"
tasks:
- name: yibie
debug:
var: ansible_facts['all_ipv4']['addresses'] //区别
下表显示了可能从受管节点收集的并可在playbook中使用的一些事实:
Ansible事实的示例
事实 | 变量 |
短主机名 | ansible_facts['hostname'] |
完全限定域名 | ansible_facts['fqdn'] |
IPv4地址 | ansible_facts['default_ipv4']['address'] |
所有网络接口的名称列表 | ansible_facts['interfaces'] |
/dev/vda1磁盘分区的大小 | ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
DNS服务器列表 | ansible_facts['dns']['nameservers'] |
当前运行的内核版本 | ansible_facts['kernel'] |
如果变量的值为散列/字典类型,则可使用两种语法来获取其值。比如:
- ansible_facts['default_ipv4']['address']也可以写成ansible_facts.default_ipv4.address
- ansible_facts['dns']['nameservers']也可以写成ansible_facts.dns.nameservers
在playbook中使用事实时,Ansible将事实的变量名动态替换为对应的值:
[root@yibie ansible]# vim playbook/test.yml
[root@yibie ansible]# cat playbook/test.yml
---
- hosts: "*"
tasks:
- name: yibie
debug:
msg: >
The host named {{ ansible_facts['fqdn'] }}
ip is {{ ansible_facts['default_ipv4']['address'] }}
[root@yibie ansible]# cd playbook/
[root@yibie playbook]# ansible-playbook test.yml
PLAY [*] ***********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.57.30]
TASK [yibie] *******************************************************************
ok: [192.168.57.30] => {
"msg": "The host named yibie-apache ip is 192.168.57.30\n"
}
PLAY RECAP *********************************************************************
192.168.57.30 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4.2 Ansible事实作为变量注入
在Ansible2.5之前,事实是作为前缀为字符串ansible_的单个变量注入,而不是作为ansible_facts变量的一部分注入。例如,ansible_facts['distribution']事实会被称为ansible_distribution。
许多较旧的playbook仍然使用作为变量注入的事实,而不是在ansible_facts变量下创建命名空间的新语法。我们可以使用临时命令来运行setup模块,以此形式显示所有事实的值。
选定的Ansible事实名称比较
ansible_facts形式 | 旧事实变量形式 |
ansible_facts['hostname'] | ansible_hostname |
ansible_facts['fqdn'] | ansible_fqdn |
ansible_facts['default_ipv4']['address'] | ansible_default_ipv4['address'] |
ansible_facts['interfaces'] | ansible_interfaces |
ansible_facts['devices']['vda']['partitions']['vda1']['size'] | ansible_devices['vda']['partitions']['vda1']['size'] |
ansible_facts['dns']['nameservers'] | ansible_dns['nameservers'] |
ansible_facts['kernel'] | ansible_kernel |
目前,Ansible同时识别新的事实命名系统(使用ansible_facts)和旧的2.5前“作为单独变量注入的事实”命名系统。
将Ansible配置文件的[default]部分中inject_facts_as_vars参数设置为False,可关闭旧命名系统。默认设置目前为True。
[root@yibie ansible]# vim ansible.cfg
# will be changed to a default of 'False' in a future release.
# ansible_facts.
inject_facts_as_vars = false
inject_facts_as_vars的默认值在Ansible的未来版本中可能会更改为False。如果设置为False,则只能使用新的ansible_facts.*命名系统引用Ansible事实。所以建议大家一开始就要适应这种方式。
4.3 关闭事实收集
有时我们不想为play收集事实。这样做的原因可能有:
- 不准备使用任何事实
- 希望加快play速度
- 希望减小play在受管主机上造成的负载
- 受管主机因为某种原因无法运行setup模块
- 需要安装一些必备软件后再收集事实
以上种种原因导致我们可能想要永久或暂时关闭事实收集的功能,要为play禁用事实收集功能,可将gather_facts关键字设置为no:
---
- name: This play gathers no facts automatically
hosts: large_farm
gather_facts: no
即使play设置了gather_facts: no,也可以随时通过运行使用setup模块的任务来手动收集事实:
---
- name: gather_facts
hosts: “*”
gather_facts: no
tasks:
- name: get gather_facts
setup:
- name: debug
debug:
var: ansible_facts
4.4 创建自定义事实
除了使用系统捕获的事实外,我们还可以自定义事实,并将其本地存储在每个受管主机上。这些事实整合到setup模块在受管主机上运行时收集的标准事实列表中。它们让受管主机能够向Ansible提供任意变量,以用于调整play的行为。
自定义事实可以在静态文件中定义,格式可为INI文件或采用JSON。它们也可以是生成JSON输出的可执行脚本,如同动态清单脚本一样。
有了自定义事实,我们可以为受管主机定义特定的值,供play用于填充配置文件或有条件地运行任务。动态自定义事实允许在play运行时以编程方式确定这些事实的值,甚至还可以确定提供哪些事实。
默认情况下,setup模块从各受管主机的/etc/ansible/facts.d目录下的文件和脚本中加载自定义事实。各个文件或脚本的名称必须以.fact结尾才能被使用。动态自定义事实脚本必须输出JSON格式的事实,而且必须是可执行文件。
[root@yibie ansible]# mkdir -p /etc/ansible/facts.d
[root@yibie ansible]# cd /etc/ansible/facts.d/
[root@yibie facts.d]# vim yy.fact
[root@yibie facts.d]# cat yy.fact
[pavckages]
web_package = httpd
db_package = mariadb-server
[users]
user1 = joe
user2 = janear: ansible_facts.default_ipv4.address
[root@yibie facts.d]#
同样的事实可能以JSON格式提供。以下JSON事实等同于以上示例中INI格式指定的事实。JSON数据可以存储在静态文本文件中,或者通过可执行脚本输出到标准输出:
{
"packages": {
"web_package": "httpd",
"db_package": "mariadb-server"
},
"users": {
"user1": "joe",
"user2": "jane"
}
}
自定义事实文件不能采用playbook那样的YAML格式。JSON格式是最为接近的等效格式。
自定义事实由setup模块存储在ansible_facts.ansible_local变量中。
事实按照定义它们的文件的名称来整理。例如,假设前面的自定义事实由受管主机上保存为/etc/ansible/facts.d/custom.fact的文件生成。在这种情况下,ansible_facts.ansible_local['custom']['users']['user1']的值为joe。
可以利用临时命令在受管主机上运行setup模块来检查自定义事实的结构。
[root@yibie ansible]# ansible 192.168.57.30 -m setup
自定义事实的使用方式与playbook中的默认事实相同:
---
- hosts: all
tasks:
- name: Prints various Ansible facts
debug:
msg: >
The package to install on {{ ansible_facts['fqdn'] }}
is {{ ansible_facts['ansible_local']['cutstom']['packages']['web_package'] }}
4.5 使用魔法变量
一些变量并非事实或通过setup模块配置,但也由Ansible自动设置。这些魔法变量也可用于获取与特定受管主机相关的信息。
最常用的有四个:
魔法变量 | 说明 |
hostvars | 包含受管主机的变量,可以用于获取另一台受管主机的变量的值。 如果还没有为受管主机收集事实,则它不会包含该主机的事实。 |
group_names | 列出当前受管主机所属的所有组 |
groups | 列出清单中的所有组和主机 |
inventory_hostname | 包含清单中配置的当前受管主机的主机名称。 因为各种原因有可能与事实报告的主机名称不同 |
另外还有许多其他的“魔法变量”。有关更多信息,请参见以下链接:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable。
若要深入了解它们的值,一个途径是使用debug模块报告特定主机的hostvars变量的内容:
[root@yibie ansible] ansible 192.168.57.30 -m debug -a 'var=hostvars["localhost"]'