Ansible v2.16.2数据合并报错:如何构建含主机事实的结构化数据
解决方案
步骤1:构建包含主机facts的基础字典
你需要将目标主机的facts汇总为字典结构(而非数组),键为主机名,值包含对应facts信息。推荐在localhost上执行汇总操作,避免在每个目标主机重复维护数据:
--- - name: 收集并整合主机数据 hosts: myhosts gather_facts: yes tasks: # 在每个主机上暂存自身facts到localhost - name: 暂存当前主机facts set_fact: _host_fact: "{{ inventory_hostname }}": facts: [ "{{ ansible_facts | to_json | from_json }}" ] delegate_to: localhost delegate_facts: no - name: 汇总所有主机数据到provided_hosts hosts: localhost vars: provided_hosts: {} tasks: - name: 合并所有主机facts set_fact: provided_hosts: "{{ provided_hosts | combine(item, recursive=true) }}" loop: "{{ hostvars | json_query('*.hostvars.localhost._host_fact') }}"
执行后会生成你期望的基础结构:
"provided_hosts": { "SomeHost001": { "facts": [ { ...ansible_facts... } ] }, "AnotherHost002": { "facts": [ { ...ansible_facts... } ] }, "RandomHost-003": { "facts": [ { ...ansible_facts... } ] } }
步骤2:添加vCenter关联信息
假设你有主机与vCenter的映射关系(可根据实际业务逻辑调整,比如自定义变量、主机名规则或facts字段),以下是基于自定义映射表的实现:
# 在localhost的Play中追加以下任务 - name: 定义主机与vCenter映射(示例) set_fact: host_vcenter_map: SomeHost001: vcenter1 AnotherHost002: vcenter2 RandomHost-003: vcenter1 - name: 为每个主机添加vCenter信息 set_fact: provided_hosts: >- {{ provided_hosts | combine( { item.key: provided_hosts[item.key] | combine( { 'vcenter': vcenters[item.value] } ) }, recursive=true ) }} loop: "{{ host_vcenter_map | dict2items }}"
如果关联逻辑基于主机facts(比如ansible_virtualization_host),可直接替换映射表来源:
host_vcenter_map: "{{ hostvars | dict2items | items2dict(key_name='key', value_name='value.ansible_virtualization_host') }}"
关键错误修正说明
你之前的Playbook存在两个核心问题:
- 初始数据结构错误:将
provided_hosts设为列表(groups['myhosts']是列表),但你需要的是字典结构,键为主机名。 combine过滤器用法错误:combine的正确语法是dict1 | combine(dict2, recursive=true, list_merge='append'),你错误传入字符串'vcenters'作为参数,导致语法报错。
最终效果
完成后provided_hosts会包含完整结构:
"provided_hosts": { "SomeHost001": { "facts": [ { ...ansible_facts... } ], "vcenter": { "hostname": "vc01.somewhere.com", "ip_addr": "192.168.10.90" } }, ... }
内容的提问来源于stack exchange,提问作者SiLeNCeD
相关产品推荐
相关产品推荐

