首页 > 解决方案 > 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 }}"

这似乎充其量只是将两个列表放入键:值对中。我究竟做错了什么 ?

标签: pythonansibleyamljinja2

解决方案


为了避免需要进行嵌套循环,我们可以使用过滤器来获取我们想要的单个主机的值。这个片段应该给你你想要的。

- 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过滤器对列表的总数求和。


推荐阅读