Search code examples
ansibleyamljinja2

Loop over a YAML dictionary


When looping over a nested YAML structure I am getting the following error:

[host] (item=script.sh) => {"ansible_loop_var": "item", "changed": false, "item": "script.sh", "msg": "AnsibleUndefinedVariable: 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'ips'"}

Here is the YAML structure:

cluster_topology:
  regions:
    ca-west-1:
        ips:
          - 1.1.1.1
          - 2.2.2.2
    ca-east-1:
        ips:
          - 3.3.3.3
          - 4.4.4.4

Here is the Jinja2 template:

{% for region in cluster_topology.regions %}
echo {{ region }}
echo {{ region.ips }}
{% endfor %}

I have tried lots of different iterations of the YAML structure, as well as accessing the ips field using both dot notation and bracket notation but the same error occurs.

Is anyone able to advise what I am missing?


Solution

  • To loop over a dictionary, you can either use the for key, value in my_dict.items() of Jinja.

    Given:

    - debug:
        msg: |-
          {% for region, value in cluster_topology.regions.items() %}
          echo {{ region }}
          echo {{ value.ips }}
          {% endfor %}
      vars:
        cluster_topology:
          regions:
            ca-west-1:
                ips:
                  - 1.1.1.1
                  - 2.2.2.2
            ca-east-1:
                ips:
                  - 3.3.3.3
                  - 4.4.4.4
    

    Which yields:

    ok: [localhost] => 
      msg: |-
        echo ca-west-1
        echo ['1.1.1.1', '2.2.2.2']
        echo ca-east-1
        echo ['3.3.3.3', '4.4.4.4']
    

    Or, you can use the dict2items filter.

    This task yielding the same result as the above one:

    - debug:
        msg: |-
          {% for region in cluster_topology.regions | dict2items %}
          echo {{ region.key }}
          echo {{ region.value.ips }}
          {% endfor %}
      vars:
        cluster_topology:
          regions:
            ca-west-1:
                ips:
                  - 1.1.1.1
                  - 2.2.2.2
            ca-east-1:
                ips:
                  - 3.3.3.3
                  - 4.4.4.4