Ansible 迭代字典的字典

Ansible iterate on dict of dict

我如何使用 Ansible 迭代包含另一个字典的字典?

mydict 可以包含 X“foo”并且 fooX(如 foo1)可以包含(至少)一个或多个参数“bar”。

我真的无法更改 vars 类型,目前是:

mydict: 字典
mydict.foo1: 字典
mydict.foo1.params: 字典

Ansible 剧本:localvars.yml

---
- hosts: localhost
  connection: local
  gather_facts: false

  vars:
    mydict:
      foo1:
        dest: /tmp/foo1.txt
        content: "foo1"
        params:
          bar1:
            alias: foo1foo
          bar2:
            alias: foo1foo
      foo2:
        dest: /tmp/foo2.txt
        content: "foo2"
        params:
          bar1:
            alias: foo1foo

  tasks:
  - name: Print records
    debug:
      msg: |-
          Item {{ item.key }} dest {{ item.value.dest }} content {{ item.value.content }} params {{ item.value.params }}"
    loop: "{{ mydict | dict2items }}"    

Ansible 命令:ansible-playbook -vv -i localhost, localvars.yml

预期结果:

为“fooX”中的每个“barX”参数动态获取 mydict.fooX.params.barX.alias
为每个“fooX”动态获取 mydict.fooX.dest

感谢您的帮助

我试过了:

- name: Using dict2items
  ansible.builtin.debug:
    msg: |-
      "item.key = {{ item.key }}
      item.value = {{ item.value }}"
  loop: "{{ mydict | dict2items }}"

像 mydict.foo1.dest 一样可以很好地获取 mydict 中的所有值,但我很难获取所有参数值

感谢您的帮助

这有点难看,但我相信它符合您的要求:

  - name: Print records
    vars:
      _records_to_items: "{{ mydict | dict2items }}"
      _params_to_items: "{{ _records_to_items | map(attribute='value.params') | map('dict2items') }}"
      _consolidate: "{{ _records_to_items | zip(_params_to_items) }}"
      my_msg: |-
        Item: {{ item.0.0.key }}
        dest: {{ item.0.0.value.dest }}
        content {{ item.0.0.value.content }}
        curent param
          name: {{ item.1.key }}
          value: {{ item.1.value }}
    debug:
      msg: "{{ my_msg | split('\n') }}"
    loop: "{{ _consolidate | subelements([1]) }}"
    loop_control:
      label: "Processing params for {{ item.0.0.key }}"

这给出了(运行 根据您的上述数据):

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

TASK [Print records] **********************************************************************************************************************************************************************************************
ok: [localhost] => (item=Processing params for foo1) => {
    "msg": [
        "Item: foo1",
        "dest: /tmp/foo1.txt",
        "content foo1",
        "curent param",
        "  name: bar1",
        "  value: {'alias': 'foo1foo'}"
    ]
}
ok: [localhost] => (item=Processing params for foo1) => {
    "msg": [
        "Item: foo1",
        "dest: /tmp/foo1.txt",
        "content foo1",
        "curent param",
        "  name: bar2",
        "  value: {'alias': 'foo1foo'}"
    ]
}
ok: [localhost] => (item=Processing params for foo2) => {
    "msg": [
        "Item: foo2",
        "dest: /tmp/foo2.txt",
        "content foo2",
        "curent param",
        "  name: bar1",
        "  value: {'alias': 'foo1foo'}"
    ]
}

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

最简单的选项是包含文件中属性 params 的迭代,例如创建一个文件

shell> cat iterate-params.yml
- debug:
    msg: |-
      item: {{ outer_item.key }}
      dest: {{ outer_item.value.dest }}
      content: {{ outer_item.value.content }}
      param: {{ item }}
  loop: "{{ outer_item.value.params|dict2items }}"
  loop_control:
    label: "{{ outer_item.key }}: {{ item.key }}"

并将其包含在循环中

    - include_tasks: iterate-params.yml
      loop: "{{ mydict|dict2items }}"
      loop_control:
        loop_var: outer_item
        label: "{{ outer_item.key }}"

给予

TASK [debug] *******************************************************
included: /export/scratch/tmp8/iterate-params.yml for localhost => (item=foo1)
included: /export/scratch/tmp8/iterate-params.yml for localhost => (item=foo2)

TASK [debug] *******************************************************
ok: [localhost] => (item=foo1: bar1) => 
  msg: |-
    item: foo1
    dest: /tmp/foo1.txt
    content: foo1
    param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=foo1: bar2) => 
  msg: |-
    item: foo1
    dest: /tmp/foo1.txt
    content: foo1
    param: {'key': 'bar2', 'value': {'alias': 'foo1foo'}}

TASK [debug] *******************************************************
ok: [localhost] => (item=foo2: bar1) => 
  msg: |-
    item: foo2
    dest: /tmp/foo2.txt
    content: foo2
    param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}

如果可以使用最新的过滤器 community.general.dict_kv,下一个选项是将属性 params 转换为列表和迭代 with_subelements

    - debug:
        msg: |-
          dest: {{ item.0.dest }}
          content: {{ item.0.content }}
          param: {{ item.1 }}
      with_subelements:
        - "{{ _values|zip(_params)|map('combine') }}"
        - params
      loop_control:
        label: "{{ item.0.dest }}"
      vars:
        _list: "{{ mydict|dict2items }}"
        _values: "{{ _list|map(attribute='value') }}"
        _params: "{{ _list|map(attribute='value.params')|
                           map('dict2items')|
                           map('community.general.dict_kv', 'params') }}"

给予

TASK [debug] ***********************************************************
ok: [localhost] => (item=/tmp/foo1.txt) => 
  msg: |-
    dest: /tmp/foo1.txt
    content: foo1
    param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=/tmp/foo1.txt) => 
  msg: |-
    dest: /tmp/foo1.txt
    content: foo1
    param: {'key': 'bar2', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=/tmp/foo2.txt) => 
  msg: |-
    dest: /tmp/foo2.txt
    content: foo2
    param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}