ansible笔记


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组, 可能是还需要一些其他的操作吧,继续翻源码,找到了InventoryDatareconcile_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
作者: honmaple
链接: https://honmaple.me/articles/2018/09/ansible笔记.html
版权: CC BY-NC-SA 4.0 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat
alipay

加载评论