python - ANSIBLE:使用多个变量循环复杂的字典
问题描述
我希望能够确定多个主机上特定目录列表的平均大小。我首先在主机上找到我想要的目录,评估它们的大小并将结果放入一个不错的字典中:
- name: find log dirs
shell: "find / -type d -name 'log' 2>/dev/null | sort"
register: log_list
- name: evaluate dir sizes
shell: "du -sk {{ item }} | awk '{ print $1 }'"
register: folder_size
loop : "{{ log_list.stdout_lines }}"
- name: build dict
set_fact:
folder_info: "{{ folder_info|default({}) | combine({item.item: {'path': item.item, 'size': item.stdout|int}}) }}"
loop: "{{ folder_size.results }}"
回到 Ansible 控制器,我将所有这些字典放在一个不错的大字典中,并且还整理了一个目录列表:
- name: gather folder info
set_fact:
all_dirs: "{{ all_dirs|default([]) + hostvars[item].dir_list|unique }}"
all_folder_info: "{{ all_folder_info|default({}) | combine({hostvars[item].inventory_hostname:hostvars[item].folder_info}) }}"
loop: "{{ groups['backoffice'] }}"
调试 all_folder_info 给了我这样的东西:
TASK [debug] *******************************************************************
ok: [localhost] => {
"all_folder_info": {
"some.host.com": {
"/some/directory/": {
"path": "/some/directory",
"size": 220
},
"/some/other/directory": {
"path": "/some/other/directory",
"size": 8
},
"/some/third/directory": {
"path": "/some/third/directory",
"size": 319404
}
},
我现在需要遍历这个巨大的字典来提取我想要的信息并对其进行数学运算,但我被卡住了。我试过这样压缩,Ansible说不能模板:
- name: debug
debug:
var: (all_folder_info[item.0].[item.1].size | sum) / (all_folder_info[item.0].[item.1].size | length)
loop: "{{ groups['backoffice']|zip_longest(all_dirs|unique)|list }}"
这似乎充其量只是将两个列表放入键:值对中。我究竟做错了什么 ?
解决方案
为了避免需要进行嵌套循环,我们可以使用过滤器来获取我们想要的单个主机的值。这个片段应该给你你想要的。
- debug:
msg: "{{ item }} average size: {{ all_folder_info[item].values() | map(attribute='size') | sum / all_folder_info[item] | length }}"
loop: "{{ groups['backoffice'] }}"
分解它:
现在all_folder_info['some.host.com']
是一个字典,但我更喜欢只包含值的列表,以便我可以使用map
过滤器来操作它。我发现你可以在.values()
没有键的情况下返回一个值列表—— all_folder_info['some.host.com'].values()
:
[
{"path": "/some/directory", "size": 220},
{"path": "/some/other/directory", "size": 8},
{"path": "/some/third/directory", "size": 319404}
]
然后对其应用map
过滤器以仅提取size
属性 -- all_folder_info['some.host.com'].values() | map(attribute='size') | list
:
[220, 8, 319404]
由于列表仅包含整数,因此我们可以使用sum
过滤器对列表的总数求和。
推荐阅读
- javafx - 如何在 JAVAFX 中创建“添加标签”按钮?
- autodesk-forge - 如何在锻造中获取点击对象(机械设备)的 URN?
- angular - 如何使用角度插值作为数组中的索引?
- machine-learning - 如何计算单个 CNN 层中的权重和偏差值的数量?
- c# - MongoDB GroupBy SUM 与 C# 中的过滤器
- asp.net-core - 如何从 ASP.Net Core (3.1) 中的模型中引用资源文件?
- python - 在python中的df上并行应用函数
- typescript - 接受泛型类型作为输入参数的可变参数泛型函数
- multithreading - 为什么自旋锁会成为多线程程序中的性能问题?
- sympy - 为什么 sympy 的 subs 函数有时不能替换符号的值?