首页 > 解决方案 > Ansible 过滤器将特定键从字典中提取到另一个字典中

问题描述

使用 nios 查找模块,我可以获得记录的字典列表

- set_fact:
    records: "{{ lookup('community.general.nios', 'record:a', filter={'name~': 'abc.com'}) }}"

这会返回类似

- ref: record:a/someBase64:name/view
  name: abc.com
  ipv4addr: 1.2.3.4
  view: default
- ref: record:a/someBase64:name/view
  name: def.abc.com
  ipv4addr: 1.2.3.5
  view: default
- ref: record:a/someBase64:name/view
  name: ghi.abc.com
  ipv4addr: 1.2.3.6
  view: default

我想将其转换为 dicts 的 dict{name}: a: {ipv4addr}

abc.com:
  a: 1.2.3.4
def.abc.com:
  a: 1.2.3.5
ghi.abc.com:
  a: 1.2.3.6

这样我就可以运行类似的查找来获取其他记录类型(例如 cname)并将它们组合到同一个字典中。items2dict 过滤器似乎已经完成了一半,但我想要在a:下面添加键。

标签: dictionaryansible

解决方案


如果您只是想要一个将名称映射到 ipv4 地址的字典,例如:

{
  "abc.com": "1.2.3.4",
  ...
}

你可以使用一个简单的json_query表达式。看一下 set_fact以下示例中的任务:

- hosts: localhost
  gather_facts: false
  vars:
    data:
      - ref: record:a/someBase64:name/view
        name: abc.com
        ipv4addr: 1.2.3.4
        view: default
      - ref: record:a/someBase64:name/view
        name: def.abc.com
        ipv4addr: 1.2.3.5
        view: default
      - ref: record:a/someBase64:name/view
        name: ghi.abc.com
        ipv4addr: 1.2.3.6
        view: default
  tasks:
    - set_fact:
        name_map: "{{ dict(data|json_query('[].[name, ipv4addr]')) }}"

    - debug:
        var: name_map

运行该剧本将输出:

PLAY [localhost] ***************************************************************

TASK [set_fact] ****************************************************************
ok: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "name_map": {
        "abc.com": "1.2.3.4",
        "def.abc.com": "1.2.3.5",
        "ghi.abc.com": "1.2.3.6"
    }
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

您可以使用类似的结构来提取其他数据(例如cname记录)。这将为您提供每种数据类型的字典,而不是按照您的要求将所有内容合并到一个字典中,但这最终可能会更容易使用。


要获得您想要的结构,您可以set_fact在循环中使用,如下所示:

- hosts: localhost
  vars:
    data:
      - ref: record:a/someBase64:name/view
        name: abc.com
        ipv4addr: 1.2.3.4
        view: default
      - ref: record:a/someBase64:name/view
        name: def.abc.com
        ipv4addr: 1.2.3.5
        view: default
      - ref: record:a/someBase64:name/view
        name: ghi.abc.com
        ipv4addr: 1.2.3.6
        view: default

  gather_facts: false
  tasks:
    - set_fact:
        name_map: "{{ name_map|combine({item.name: {'a': item.ipv4addr}}) }}"
      loop: "{{ data }}"
      vars:
        name_map: {}

    - debug:
        var: name_map

这将产生:

PLAY [localhost] ***************************************************************

TASK [set_fact] ****************************************************************
ok: [localhost] => (item={'ref': 'record:a/someBase64:name/view', 'name': 'abc.com', 'ipv4addr': '1.2.3.4', 'view': 'default'})
ok: [localhost] => (item={'ref': 'record:a/someBase64:name/view', 'name': 'def.abc.com', 'ipv4addr': '1.2.3.5', 'view': 'default'})
ok: [localhost] => (item={'ref': 'record:a/someBase64:name/view', 'name': 'ghi.abc.com', 'ipv4addr': '1.2.3.6', 'view': 'default'})

TASK [debug] *******************************************************************
ok: [localhost] => {
    "name_map": {
        "abc.com": {
            "a": "1.2.3.4"
        },
        "def.abc.com": {
            "a": "1.2.3.5"
        },
        "ghi.abc.com": {
            "a": "1.2.3.6"
        }
    }
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


推荐阅读