ansible动态解析inventory
ansible调用inventory模块时总会调用一个文件或脚本来进行处理, 但我想要动态的解析inventory, 即直接传入一个字符串而不是文件, 直接调用ansible的接口来进行解析(不同格式的inventory也可以手动解析,比如yaml格式可以使用pyyaml解析,不过直接使用ansible接口会更方便一些)
但问题是ansible没有直接可供调用的接口, 不过可以直接查看ansible源码,找到相应的解析函数,封装一下即可
查找源码, 根据 InventoryManager 传递的source变量找到parse_sources这个函数
1class InventoryManager(object):
2 def parse_sources(self, cache=False):
3 ''' iterate over inventory sources and parse each one to populate it'''
4
5 self._setup_inventory_plugins()
6 ...
然后再根据
1def _setup_inventory_plugins(self):
2 ''' sets up loaded inventory plugins for usage '''
3
4 inventory_loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', C.DEFAULT_INVENTORY_PLUGIN_PATH, 'inventory_plugins')
5 ...
找到对应的解析plugin, 我使用的是ini格式的inventory, 所以自定义一下ansible.plugins.inventory.ini.InventoryModule这个模块即可
1from ansible.plugins.inventory.ini import InventoryModule
2from ansible.inventory.data import InventoryData
3from ansible.parsing.dataloader import DataLoader
4from ansible.module_utils._text import to_text
5from ansible.template import Templar
6
7
8class InventoryCustomModule(InventoryModule):
9 def mine_parse(self, b_data):
10 self.loader = DataLoader()
11 self.inventory = InventoryData()
12 self.templar = Templar(loader=self.loader)
13 try:
14 data = to_text(b_data, errors='surrogate_or_strict').splitlines()
15 except UnicodeError:
16 data = []
17 for line in b_data.splitlines():
18 if line and line[0] in self.b_COMMENT_MARKERS:
19 data.append(u'')
20 else:
21 data.append(to_text(line, errors='surrogate_or_strict'))
22 return self._parse("", data)
-
如何使用:
1text = '''\ 2[MY-HOST] 3MY_HOST-1 ansible_ssh_host=127.0.0.1 4MY_HOST-2 ansible_ssh_host=127.0.0.2 5MY_HOST-3 ansible_ssh_host=127.0.0.3 6MY_HOST-4 ansible_ssh_host=127.0.0.4 7 8[MY-HOST:vars] 9vip=127.0.0.10 10ppp=test 11 12[MY-HOST1] 13MY_HOST1-1 ansible_ssh_host=127.0.0.11 14MY_HOST1-2 ansible_ssh_host=127.0.0.12 15 16[MY-HOST:children] 17MY-HOST1 18''' 19module = InventoryCustomModule() 20module.mine_parse(text) 21 22for _, group in module.inventory.groups.items(): 23 print(group, group.child_groups, group.vars) 24 for host in group.hosts: 25 print(host, host.vars)结果:
1(ungrouped, [], {}) 2(all, [ungrouped], {}) 3(MY-HOST, [MY-HOST1], {u'vip': u'127.0.0.10', u'ppp': u'test'}) 4(MY_HOST-1, {u'ansible_ssh_host': u'127.0.0.1', 'inventory_file': None, 'inventory_dir': None}) 5(MY_HOST-2, {u'ansible_ssh_host': u'127.0.0.2', 'inventory_file': None, 'inventory_dir': None}) 6(MY_HOST-3, {u'ansible_ssh_host': u'127.0.0.3', 'inventory_file': None, 'inventory_dir': None}) 7(MY_HOST-4, {u'ansible_ssh_host': u'127.0.0.4', 'inventory_file': None, 'inventory_dir': None}) 8(MY-HOST1, [], {}) 9(MY_HOST1-1, {u'ansible_ssh_host': u'127.0.0.11', 'inventory_file': None, 'inventory_dir': None}) 10(MY_HOST1-2, {u'ansible_ssh_host': u'127.0.0.12', 'inventory_file': None, 'inventory_dir': None})可以看出已经没什么大的问题了, 但有一个点, all组下的groups列表只有
ungrouped, 正常情况下MY-HOST组也应该继承all组,可能是还需要一些其他的操作吧,继续翻源码,找到了InventoryData的reconcile_inventory方法, 修改一下即可1module = InventoryCustomModule() 2module.mine_parse(text) 3module.inventory.reconcile_inventory()
ansible自定义模块传递list变量会变成字符串
我自定义了一个模块,需要传入一个list变量group_names
1from ansible.module_utils.basic import AnsibleModule
2
3
4def main():
5 module = AnsibleModule(
6 argument_spec=dict(group_names={
7 "required": True
8 }))
9
10 i = module.params.get('group_names')
11 msg = {"group_names": i, "type": str(type(i))}
12 module.fail_json(changed=False, msg=msg)
13
14
15if __name__ == "__main__":
16 main()
但发现传入的变量最后变成的str type
1FAILED! => {"changed": false, "failed": true, "msg": {"group_names": "['test']", "type": "<type 'str'>"}}
最后查找资料后才知道, 传递的变量需要增加type参数, 否则都是str
1module = AnsibleModule(
2 argument_spec=dict(group_names={
3 "required": True,
4 "type": "list"
5 }))
常见问题FAQ
1Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!
查看目标机器是否安装 libselinux-python
1yum install libselinux-python
修改ansible.cfg
1interpreter_python = /usr/bin/python
知识共享署名-非商业性使用-相同方式共享4.0国际许可协议