Home > Back-end >  Iterate over nested loops
Iterate over nested loops

Time:06-30

I am trying to iterate over level3 variable in Ansible. I've prepared a playbook like this:

---
- hosts: localhost
  gather_facts: no
  connection: local

  vars:
    level1:
      - abc
      - def

    level2:
      - { name: "app1", level3: ["aaaa","bbbb"]}
      - { name: "app2", level3: ["eeeee"]}

  tasks:

    - name: test
      debug: msg="{{ item.0 }} {{ item.1.name }} {{ item.2 }}"
      with_nested:
        - "{{ level1 }}"
        - "{{ level2 }}"
        - "{{ level2.level3 }}"

But I get error:

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

TASK [test] ********************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'list object' has no attribute 'level3'"}

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

What is bad with my config? I want to have on output each element.

CodePudding user response:

level2.level3 does not exist. level2 is a list so e.g. level2.0.level3 exists.

I'm not entirely sure from your question but I think what you are looking for is:

    - debug:
        msg: "{{ item.0 }} {{ item.1.0.name }} {{ item.1.1 }}"
      loop: "{{ level1 | product(level2 | subelements('level3')) }}"

You can keep the older with_ syntax using the nested lookup if you wish. The produced result is a bit different so you have to adapt to the datastructure:

    - debug:
        msg: "{{ item.0 }} {{ item.1.name }} {{ item.2 }}"
      with_nested:
        - "{{ level1 }}"
        - "{{ level2 | subelements('level3') }}"

which can eventually be written back to a loop: syntax as follow:

    - debug:
        msg: "{{ item.0 }} {{ item.1.name }} {{ item.2 }}"
      loop: "{{ q('nested', level1, level2 | subelements('level3')) }}"

All examples give the same result (delta the spitted item for each iteration, example output with first proposition)

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

TASK [debug] *********************************************************************************************************************************************
ok: [localhost] => (item=['abc', [{'name': 'app1', 'level3': ['aaaa', 'bbbb']}, 'aaaa']]) => {
    "msg": "abc app1 aaaa"
}
ok: [localhost] => (item=['abc', [{'name': 'app1', 'level3': ['aaaa', 'bbbb']}, 'bbbb']]) => {
    "msg": "abc app1 bbbb"
}
ok: [localhost] => (item=['abc', [{'name': 'app2', 'level3': ['eeeee']}, 'eeeee']]) => {
    "msg": "abc app2 eeeee"
}
ok: [localhost] => (item=['def', [{'name': 'app1', 'level3': ['aaaa', 'bbbb']}, 'aaaa']]) => {
    "msg": "def app1 aaaa"
}
ok: [localhost] => (item=['def', [{'name': 'app1', 'level3': ['aaaa', 'bbbb']}, 'bbbb']]) => {
    "msg": "def app1 bbbb"
}
ok: [localhost] => (item=['def', [{'name': 'app2', 'level3': ['eeeee']}, 'eeeee']]) => {
    "msg": "def app2 eeeee"
}

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