将任意值设置为Fact Caching,以便在下一次运行Playbook时可以使用该值
首先
在Ansible 1.8中新增的功能Fact Caching,在playbook执行时,会保存gather facts阶段收集到的主机信息一段时间,以便在其他主机上执行不同playbook时使用。
我最初听到Fact Caching功能的概要时,期望能够记录任意数值。
具体来说,我希望能在以下情况下使用该功能。
每个主机都需要在适当的配置文件中指定一个共同的关键词短语。在第一次执行playbook时,将随机生成一个关键词短语,并将其用于执行。
之后,假设由于系统负载增加等原因添加了主机。在再次使用相同的playbook来构建新增主机时,需要提取之前生成的关键词短语,并在配置文件中指定。
然而就如之前所述,Fact Caching仅存储主机的信息。因为它是”Fact” Caching,这是理所当然的。
根据阅读源代码并试图解决这个问题,我成功地找到了一种方法,能够向事实缓存中写入任意值,并在下文中做了说明。
事前准备
由于CentOS在2014年12月12日时点仍然使用epel的Ansible版本为1.7.2,因此可以通过epel-testing等来安装1.8以上的版本。
# yum install epel-release
# yum install --enablerepo=epel-testing ansible
首先,在这里我们决定将Fact Caching的存储目标设定为redis。
在CentOS 7上,我们需要在Ansible的执行主机上安装redis和python-redis。它们都可以在epel中找到。
安装完成后,启动redis。
# yum install redis python-redis
# systemctl start redis
在CentOS 6上,由于python-redis版本过旧,因此epel中的包无法用于事实缓存。建议使用pip来进行安装。
# yum install redis python-pip
# pip install redis
# service redis start
在ansible.cfg文件中进行了以下设置。
[defaults]
fact_caching = redis
fact_caching_timeout = 315360000 # 10年くらい
Fact Caching在什么情况下会写入值?
从源代码中可以得出以下大致情况。
我阅读的源代码主要是lib\ansible\playbook\__init__.py。
-
- Ansibleが持つcache(playbook実行時の値の保管場所)にはsetup cacheとvars cacheという2つがある
ただし、利用者がアクセスできるのはsetup cacheとvars cacheを混ぜた後なので、値を利用するという意味では特に区別する必要はない
Fact Cachingはsetup cacheの保存に関する機能であり、vars cacheには影響しない。vars cacheは設定によらずメモリ上に保存され、playbook実行終了とともに消滅する
モジュールが返した実行結果に”ansible_facts”というキーが含まれていた場合、”ansible_facts”の値がcacheに書き込まれる
ここで”ansible_facts”を返したモジュールがset_factかinclude_varsの場合はvars cacheに書き込まれる。他のモジュールだった場合はsetup cacheに書き込まれる
gather fact実行時には内部でsetupモジュールが呼ばれている
setupモジュールは”ansible_facts”を返すset_fact、include_vars以外のモジュールなのでsetup cacheに書き込まれる
registerを使った場合はvars cacheに書き込まれる
通过这些可以得出的结论是,如果自己创建一个返回包含”ansible_facts”键的执行结果的模块,就可以将任意值保存在Fact Caching(setup cache)中。
所以,最后想到的是复制set_fact模块并重命名。
关于Action插件的内容
由于 set_fact.py 是 set_fact 模块的源文件,不存在实际的处理内容。
这是因为 set_fact 模块的实际内容是以 action 插件的形式实现的。
动作插件作为模块几乎具有相同的行为,但与常规模块的不同之处在于,作为动作插件实现的处理将在执行Ansible的主机而不是远程主机上执行。
列出了一个作为action插件实体实现的模块的示例是raw。即使操作对象没有安装Python,raw模块也可以运行(可能)。这是因为raw模块的执行主体不是远程主机,而是正在执行Ansible的主机。
set_fact模块的实现是由runner/action_plugins/set_fact.py作为源文件的动作插件。
此外,为了执行action插件,即使没有实体,也需要放置同名模块的源文件。这个文件是modules/core/utilities/logic/set_fact.py。
为了创建一个名为set_cache的模块,它是set_fact的副本,只需要复制两个文件。在这里,我们决定创建一个符号链接而不是复制文件。以下是在CentOS 7上的示例。如果是CentOS 6,则python2.7的部分将变为python2.6。
# ln -s /usr/lib/python2.7/site-packages/ansible/modules/core/utilities/logic/set_{fact,cache}.py
# ln -s /usr/lib/python2.7/site-packages/ansible/runner/action_plugins/set_{fact,cache}.py
可以在其他目录中创建符号链接,但在这种情况下,需要在ansible.cfg的[defaults]部分的action_plugins项中指定放置动作插件的目录。此外,有多种方法可以指定放置模块的目录,但如果使用ansible.cfg,则应在[defaults]部分的library项中指定。
顺便提一下,ansible.cfg中可以看到被注释掉的library_path项,但这是不正确的,换句话说,应该不存在library_path这个设置项。
一个简单的示例
创建以下类型的playbook和清单,
- hosts: host1
gather_facts: false
tasks:
- set_cache:
aaa: 111
tags: test1
- hosts: host2
gather_facts: false
tasks:
- debug: var=hostvars['host1']['aaa']
tags: test2
host1
host2
请先执行以下步骤:
# ansible-playbook test.yml -i test.hosts -t test1
执行以下操作。
# ansible-playbook test.yml -i test.hosts -t test2
如果实施结果包括以下内容,则表示顺利进行。
ok: [host1] => {
"hostvars['host1']['aaa']": "111"
}
最后
如果以前要保存值,可以使用Ansible执行主机本身创建一个包含关键短语的YAML文件,例如使用template模块,然后在后续的playbook执行中使用include_vars模块等读取该YAML文件。然而,相比之下,这种方法更加简便易用。