如何在自定义Ansible模块中访问ansible_all_ipv4_addresses等事实?
我正在开发自定义Ansible模块,需要直接在模块代码中访问ansible_all_ipv4_addresses这类事实,但不确定如何无需从playbook显式传递就能获取这些信息。
比如在SaltStack中可以通过grains访问系统信息,但我没找到Ansible自定义模块里的等效方式。我的需求是:在自定义模块内获取ansible_all_ipv4_addresses事实,不需要在playbook里手动将其作为参数传递。
以下是我尝试的示例代码:
from ansible.module_utils.basic import AnsibleModule def run_module(): module = AnsibleModule( argument_spec={}, supports_check_mode=True ) # 如何在这里访问ansible_all_ipv4_addresses? ipv4_addresses = ??? module.exit_json(changed=False, ipv4=ipv4_addresses) if __name__ == '__main__': run_module()
是否存在类似SaltStack grains的方式,能在自定义模块内直接访问ansible_all_ipv4_addresses这类事实?如果没有,在自定义模块中访问这些事实的推荐方案是什么?
核心结论
Ansible自定义模块没有类似SaltStack Grains的内置机制,可以直接访问控制节点预收集的ansible_all_ipv4_addresses这类事实。原因是:Ansible的事实是在控制节点通过setup模块收集并存储的,而自定义模块是在目标节点上独立运行的进程,两者之间没有自动的事实传递通道。
推荐方案
方案1:通过Playbook显式传递事实(最常用)
这是Ansible生态中标准的做法,仅需在调用模块时将需要的事实作为参数传入,模块通过argument_spec定义参数接收即可。
修改后的模块代码:
from ansible.module_utils.basic import AnsibleModule def run_module(): module = AnsibleModule( argument_spec={ 'ipv4_addresses': {'type': 'list', 'required': True} }, supports_check_mode=True ) # 从模块参数中获取传递的事实 ipv4_addresses = module.params['ipv4_addresses'] module.exit_json(changed=False, ipv4=ipv4_addresses) if __name__ == '__main__': run_module()
对应的Playbook调用示例:
- name: 调用自定义模块 hosts: all tasks: - name: 传递IPv4地址事实给自定义模块 custom_module: ipv4_addresses: "{{ ansible_all_ipv4_addresses }}"
方案2:模块内自行收集系统信息(完全独立)
如果不想依赖Playbook传递事实,可以让模块直接在目标节点上执行系统命令或调用Python库获取IPv4地址,脱离Ansible预收集事实的依赖。
示例代码(通过系统命令解析):
from ansible.module_utils.basic import AnsibleModule def get_all_ipv4_addresses(module): """在目标节点上直接收集非回环IPv4地址""" rc, out, err = module.run_command(['ip', '-4', 'addr', 'show']) if rc != 0: module.fail_json(msg='获取IPv4地址失败', error=err) addresses = [] for line in out.splitlines(): if 'inet ' in line: ip = line.split()[1].split('/')[0] if not ip.startswith('127.'): addresses.append(ip) return addresses def run_module(): module = AnsibleModule( argument_spec={}, supports_check_mode=True ) # 自行收集IPv4地址 ipv4_addresses = get_all_ipv4_addresses(module) module.exit_json(changed=False, ipv4=ipv4_addresses) if __name__ == '__main__': run_module()
注:该方案兼容性强,无需额外安装Python依赖库,适合大多数Linux节点。
内容的提问来源于stack exchange,提问作者Tony

