Ansible如何遍历复杂嵌套字典计算多主机指定目录平均大小
问题原因
- 变量名不匹配:你在汇总全量目录列表时调用了不存在的
hostvars[item].dir_list变量,被管控节点上收集到的目录实际存储在log_list.stdout_lines中,这会直接导致all_dirs内容异常。 - 工具选择错误:
zip_longest的作用是对两个列表按位置配对生成键值对,和你需要的「单个目录遍历所有主机取对应大小」的两层遍历逻辑完全不匹配,强行使用会频繁触发key不存在的模板渲染错误。
修复实现
步骤1:修正汇总逻辑
先修正全量目录和主机目录信息的汇总代码,增加默认值避免部分主机无数据时执行报错:
- name: 汇总全量目录信息与唯一目录列表 set_fact: all_dirs: "{{ all_dirs | default([]) + hostvars[item].log_list.stdout_lines | default([]) }}" all_folder_info: "{{ all_folder_info | default({}) | combine({hostvars[item].inventory_hostname: hostvars[item].folder_info | default({})}) }}" loop: "{{ groups['backoffice'] }}" - name: 对全量目录列表去重 set_fact: all_dirs: "{{ all_dirs | unique }}"
可选优化:如果存在同一目录路径有的带末尾斜杠、有的不带的情况,可以在被管控节点构建
folder_info时统一对路径做标准化处理,把路径末尾的斜杠去掉,避免同一个目录被识别为两条不同数据:# 替换原build dict任务中的combine部分即可 folder_info: "{{ folder_info|default({}) | combine({item.item | regex_replace('/$', ''): {'path': item.item | regex_replace('/$', ''), 'size': item.stdout|int}}) }}"
步骤2:计算目录平均大小
直接遍历全量目录列表,对每个目录统计所有主机上的有效大小,再计算平均值:
- name: 计算每个目录的平均大小 set_fact: dir_avg_size: "{{ dir_avg_size | default({}) | combine({item: {'总大小_KB': total_size | int, '有该目录的主机数': host_count, '平均大小_KB': (total_size / host_count) | round(2)}}) }}" vars: # 提取所有主机上当前目录的大小,过滤掉不存在该目录的主机数据 valid_size_list: "{{ groups['backoffice'] | map('extract', hostvars) | map(attribute='folder_info.' + item + '.size', default=0) | select('gt', 0) | list }}" total_size: "{{ valid_size_list | sum }}" host_count: "{{ valid_size_list | length }}" loop: "{{ all_dirs }}" # 输出最终结果 - name: 打印各目录平均大小 debug: var: dir_avg_size
最终输出的dir_avg_size会以目录路径为key,存储对应目录的总大小、统计的主机数量和平均大小,完全符合需求。
内容的提问来源于stack exchange,提问作者Gé Fa
相关产品推荐
相关产品推荐

