Ansible 为所有主机追加 dict 结果 [英] Ansible append dict results for all hosts
问题描述
我正在尝试使用 Ansible 向多个返回 dict 的主机发送命令.然后我想附加每个主机的dict结果来累积所有主机的结果.最后,我想打印累积结果的 dict 以供以后处理或写入文件.由于结果显示为字符串,我似乎无法组合字典.有没有办法解决这个问题?另外,有没有更 Ansible 有效的方法来实现这一点?
I am attempting to use Ansible to send a command to several hosts that returns a dict. I then want to append the the dict results of each host to accumulate the results of all the hosts. Finally, I want to print the dict of accumulated results for later processing or to write to a file. It appears I am failing to combine the dicts due to results showing as string. Is there a way to remedy this? Also, is there a more Ansible efficient way to accomplish this?
示例手册:
---
- hosts: myhosts
gather_facts: False
vars:
mydict: {}
tasks:
- name: Get dict result
shell: "cat /path/dict_output"
register: output
- set_fact:
result_dict="{{ output.stdout}}"
- debug: var=result_dict
调试输出:
TASK [debug] ****************************************************************************************************************************************************************
ok: [host-a] => {
"result_dict": {
"host_b": [
{
"ip-1": {
"port": "22",
"service": "ssh"
}
},
{
"ip-2": {
"port": "21",
"service": "ftp"
}
}
]
}
}
ok: [host-b] => {
"result_dict": {
"host_a": [
{
"ip-1": {
"port": "22",
"service": "ssh"
}
},
{
"ip-2": {
"port": "21",
"service": "ftp"
}
}
]
}
}
我尝试合并每个主机的结果:
- set_fact:
mydict: "{{ mydict | combine(output.stdout) }}"
- debug: var=mydict
失败的结果:
TASK [set_fact] *************************************************************************************************************************************************************
fatal: [host-b]: FAILED! => {"msg": "|combine expects dictionaries, got u\"{'host_b': [{'ip-1': {'service': 'ssh', 'port': '22'}}, {'ip-2': {'service': 'ftp', 'port': '21'}}]}\""}
fatal: [host-a]: FAILED! => {"msg": "|combine expects dictionaries, got u\"{'host_a': [{'ip-1': {'service': 'ssh', 'port': '22'}}, {'ip-2': {'service': 'ftp', 'port': '21'}}]}\""}
期望的累积结果输出:
{'host_a': [{'ip-1': {'port': '22', 'service': 'ssh'}},
{'ip-2': {'port': '21', 'service': 'ftp'}}],
'host_b': [{'ip-1': {'port': '22', 'service': 'ssh'}},
{'ip-2': {'port': '21', 'service': 'ftp'}}]}
推荐答案
在收集所有主机的所有信息后,您可以在本地主机上运行的单个任务中创建该哈希映射.
You can create that hashmap in a single task running on localhost after you gathered all the info on all the hosts.
您可以从 hostvars
哈希图中的任何主机浏览事实,并通过 groups['name_of_group']
访问组中所有机器的列表.
You can browse facts from any hosts in the hostvars
hashmap, and access a list of all machines in a group through groups['name_of_group']
.
知道这两个信息,基本思路是:
Knowing those 2 info, the basic idea is:
- 提取所有主机变量对于您组中的机器,并确保我们从中得到一个列表 =>
groups[myhosts"] |地图(提取",主机变量)|列表
- 过滤该结果以仅保留
result_dict
.我们可以使用map
过滤器 再次 =>map(attribute="result_dict")
.我们已经非常接近您正在寻找的内容,它将是一个哈希映射列表(每个主机一个元素).但是您正在寻找单个哈希图,所以.... - 循环此结果以创建单个哈希图,其中包含每个主机的条目.
- Extract all hostvars for the machines in your group and make sure we get a list out of that =>
groups["myhosts"] | map("extract", hostvars) | list
- Filter that result to retain only the
result_dict
. We can do this using themap
filter again =>map(attribute="result_dict")
. We are already very close to what your are looking for, it will be a list of hashmaps (one element for each host). But you are looking for a single hashmap, so.... - Loop on this result to create a single hashmap with an entry for each host.
在您的其他任务满足您的要求后运行以下游戏:
The following play ran after your other tasks should meet your requirements:
- name: consolidate and display my result
hosts: localhost
tasks:
- name: Consolidate result in a single hashmap
set_fact:
my_final_map: "{{ my_final_map | default({}) | combine(item) }}"
loop: >-
{{
groups["myhosts"]
| map("extract", hostvars)
| map(attribute="result_dict")
| list
}}
- name: Display consolidated result
debug:
var: my_final_map
注释后注意:如果您的组中有一些主机没有运行任务(因为它们无法访问或出于其他原因),您可以排除未定义的result_dict
使用 selectattr
过滤器
Note after comment: If you have some host in the group that did not run the task (because they were unreachable or for other reasons), you can exclude hosts with undefined result_dict
using the selectattr
filter
loop: >-
{{
groups["myhosts"]
| map("extract", hostvars)
| selectattr("result_dict", "defined")
| map(attribute="result_dict")
| list
}}
这篇关于Ansible 为所有主机追加 dict 结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!