首页 > 解决方案 > 在 Ansible 中使用 JINJA2 从 JSON 中提取带有条件的嵌套 dict 值

问题描述

我正在尝试从 Ansible's 中提取特定别名的 CDN 域名cloudfront_facts,并带有以下(汇总)输出:

{
  "cdn_facts": {
   "ansible_facts": {
    "cloudfront": {
      "summary": {
       "distributions": [
        {
          "Aliases": [
           "media.example.com"
          ],
          "DomainName": "a1b2c3d4e5f6g.cloudfront.net"
        },
        {
          "Aliases": [
           "example.com"
          ],
          "DomainName": "g7f6e5d4c3b2a.cloudfront.net"
        }
      ]
     }
    }
  }
}

换句话说,对于别名,example.com我想设置一个值为g7f6e5d4c3b2a.cloudfront.net.

我尝试了以下尝试打印出该值,但它只是产生一个空列表。

- debug:
    msg: "{{ cdn_facts.ansible_facts.cloudfront.summary.distributions | selectattr('Aliases[0]', 'equalto', 'example.com') | map(attribute='DomainName') | list }}"

我什至不知道如何调试它,因为cdn_facts.ansible_facts.cloudfront.summary.distributions产生了一系列字典,但selectattrmap没有产生任何东西。

标签: pythonjsonansiblejinja2

解决方案


您的数据中没有任何内容具有名为 的属性Aliases[0],这就是您的selectattr过滤器失败的原因。

对于从深度嵌套的字典中提取数据,json_query过滤器通常是比尝试链接原生 Jinja 过滤器更好的选择。例如,给定 alias example.com,以下表达式将提取相应的DomainName属性:

cdn_facts.ansible_facts.cloudfront.summary.distributions[?Aliases[0] == `example.com`]|[0].DomainName

我们可以在这样的剧本中使用它:

---
- hosts: localhost
  gather_facts: false
  tasks:
    - include_vars:
        file: data.json
        name: data

    - debug:
        msg: >-
          {{ item }} ->
          {{
          (data|json_query('cdn_facts.ansible_facts.cloudfront.summary.distributions[?Aliases[0] == `{}`]|[0].DomainName'.format(item)))
          }}
      loop:
        - media.example.com
        - example.com

这将输出:

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => (item=media.example.com) => {
    "msg": "media.example.com -> a1b2c3d4e5f6g.cloudfront.net"
}
ok: [localhost] => (item=example.com) => {
    "msg": "example.com -> g7f6e5d4c3b2a.cloudfront.net"
}

这些json_query模块使用jmespath搜索语法。您可以通过将数据粘贴到https://jmespath.org的文本框中,然后在其上方的字段中输入搜索表达式来试验 jmespath 表达式。或者,您可以获取jpterm命令行工具。


推荐阅读