Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible: iterate over a list of dictionaries - loop vs. with_items

Tags:

loops

ansible

I'm getting different results when using loop vs with_items when trying to iterate over a list of dictionaries.

I've tried using loop|dict2items (the structure isn't a dictionary, & it tells me as much. heh) and loop with the flatten filter.

Here is the list of dictionaries:

    "msg": [
        {
            "id": "id1", 
            "ip": "ip1", 
            "name": "name1"
        }, 
        {
            "id": "id2", 
            "ip": "ip2", 
            "name": "name2"
        }, 
        {
            "id": "id3", 
            "ip": "ip3", 
            "name": "name3"
        }, 
        {
            "id": "id4", 
            "ip": "ip4", 
            "name": "name4"
        }
    ]
}

Here is the task in the playbook:

 - name: Add privateIp windows_instances to inventory
        add_host:
          name: "{{ item.ip }}"
          aws_name: "{{ item.name }}"
          groups: windows_instances
          aws_instanceid: "{{ item.id }}"
          ansible_user: "{{ windows_user }}"
          ansible_password: "{{ windows_password }}"
          ansible_port: 5985
          ansible_connection: winrm
          ansible_winrm_server_cert_validation: ignore
        loop:
          - "{{ list1 | flatten(levels=1) }}"

When attempting to run the above code, I get the "list object has no attribute" error. I've tried different flatten levels to no avail.

HOWEVER...

If I simply replace the loop above with:

with_items:
  - "{{ list1 }}"

Everything works perfectly. I'm missing something in the with_items > loop translation here...

like image 864
Travis Avatar asked Mar 29 '19 20:03

Travis


People also ask

What is the difference between With_items and loop in Ansible?

The with_ keywords rely on Lookup Plugins - even items is a lookup. The loop keyword is equivalent to with_list, and is the best choice for simple loops. The loop keyword will not accept a string as input, see Ensuring list input for loop: query vs. lookup.

How do you use nested loops in Ansible?

Ansible's syntax also supports the idea of nested looping. Nested loops in many ways are similar in nature to a set of arrays that would be iterated over using the with_nested operator. Nested loops provide us with a succinct way of iterating over multiple lists within a single task.

Why loops are used in Ansible?

Ansible loop is used to repeat any task or a part of code multiple times in an Ansible-playbook. It includes the creation of multiple users using the user module, installing multiple packages using apt or yum module or changing permissions on several files or folders using the file module.

Is there a for loop in Ansible?

When creating loops, Ansible provides these two directives: loop and with_* keyword. The loop keyword was recently added to Ansible 2.5. The loop keyword is usually used to create simple and standard loops that iterate through several items.


Video Answer


1 Answers

Don't put a - before your list.

And here, you have a list of dicts, so you don't need to flatten neither.

This playbook:

- hosts: localhost
  gather_facts: no

  vars:
    demo_list:
      - ip: 1.2.3.4
        id: 1
        name: demo1
      - ip: 2.2.3.4
        id: 2
        name: demo2
      - ip: 3.2.3.4
        id: 3
        name: demo3

  tasks:

    - name: the list
      debug:
        msg: "{{ demo_list }}"

    - name: unflattened list
      debug:
        msg: "{{ item.id }} {{ item.ip }} {{ item.name }}"
      loop:
        "{{ demo_list }}"

    - name: flattened list == unflattened list in this case
      debug:
        msg: "{{ item.id }} {{ item.ip }} {{ item.name }}"
      loop:
        "{{ demo_list | flatten(levels=1) }}"

gives this result:

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

TASK [the list] ****************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "id": 1, 
            "ip": "1.2.3.4", 
            "name": "demo1"
        }, 
        {
            "id": 2, 
            "ip": "2.2.3.4", 
            "name": "demo2"
        }, 
        {
            "id": 3, 
            "ip": "3.2.3.4", 
            "name": "demo3"
        }
    ]
}

TASK [unflattened list] ********************************************************************************
ok: [localhost] => (item=None) => {
    "msg": "1 1.2.3.4 demo1"
}
ok: [localhost] => (item=None) => {
    "msg": "2 2.2.3.4 demo2"
}
ok: [localhost] => (item=None) => {
    "msg": "3 3.2.3.4 demo3"
}

TASK [flattened list == unflattened list in this case] *************************************************
ok: [localhost] => (item=None) => {
    "msg": "1 1.2.3.4 demo1"
}
ok: [localhost] => (item=None) => {
    "msg": "2 2.2.3.4 demo2"
}
ok: [localhost] => (item=None) => {
    "msg": "3 3.2.3.4 demo3"
}

PLAY RECAP *********************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0
like image 162
sebthebert Avatar answered Oct 10 '22 20:10

sebthebert