【问题标题】:Ansible append dict results for all hosts所有主机的 Ansible 附加字典结果
【发布时间】:2019-12-13 15:24:14
【问题描述】:

我正在尝试使用 Ansible 向多个返回 dict 的主机发送命令。然后我想附加每个主机的 dict 结果以累积所有主机的结果。最后,我想打印累积结果的字典以供以后处理或写入文件。由于结果显示为字符串,我似乎无法合并字典。有没有办法解决这个问题?另外,有没有更高效的 Ansible 方法来实现这一点?

示例手册:

---
  - 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'}}]}

【问题讨论】:

    标签: python python-3.x dictionary ansible


    【解决方案1】:

    收集所有主机上的所有信息后,您可以在 localhost 上运行的单个任务中创建该哈希图。

    您可以在hostvars hashmap 中浏览来自任何主机的事实,并通过groups['name_of_group'] 访问组中所有机器的列表。

    了解这两个信息,基本思路是:

    • Extract 组中机器的所有主机变量,并确保我们从中得到一个列表 => groups["myhosts"] | map("extract", hostvars) | list
    • 过滤该结果以仅保留result_dict。我们可以再次使用map filter => map(attribute="result_dict") 来做到这一点。我们已经非常接近您正在寻找的内容,它将是一个哈希图列表(每个主机一个元素)。但你正在寻找一个单一的哈希图,所以....
    • 循环此结果以创建单个哈希映射,其中每个主机都有一个条目。

    在您的其他任务应该满足您的要求之后运行以下游戏:

    - 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 filter

          loop: >-
            {{
              groups["myhosts"]
              | map("extract", hostvars)
              | selectattr("result_dict", "defined") 
              | map(attribute="result_dict")
              | list
            }}
    

    【讨论】:

    • 谢谢,这很好用。只是两个后续问题。你能解释一下循环是如何在这里工作的并分享任何使用参考吗?是否可以在不需要 JMESPath 提取元素的情况下获得结果?
    • 好吧,我在回答中解释了循环的工作原理,至少在该表达式中提取数据的过程以及我们最终循环的内容。我的解释中有什么不清楚的地方?我会更新的。如果您真的不想使用 json_query(在这种情况下实际上不是强制性的),您可以将最后一个 json_query 过滤器替换为:map(attribute='result_dict') | list
    • 感谢 json_query 的替代品。我正在使用的机器没有这种依赖性。读几遍循环逻辑就有意义了。我想我只是不熟悉语法。我会在那里做一些研究。不过,这工作得很好。非常感谢,谢谢!
    • 我刚刚编辑了(当你接受了...),添加了替代品,并提供了更多的参考细节。如果您担心我如何在任务中编写循环本身,这只是一个 yaml 问题。 yaml-multiline.info 应该在几秒钟内让你清楚(预计阅读时间 5 分钟)。
    • 有没有办法排除合并结果时无法访问的主机?播放失败,因为它找不到无法访问的主机的 result_dict。
    猜你喜欢
    • 2022-07-05
    • 2018-04-30
    • 2017-11-09
    • 2013-11-14
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多