Ansible nested loop

Viewed 84

Is it possible for Ansible to do a nested loop as I want to do a filtering and set fact.

The first fact that I have is

    "username_and_role": [
        {
            "Name": "Jack",
            "Role": "Admin User"
        },
        {
            "Name": "Tom",
            "Role": "Buyer"
        },
        {
            "Name": "Jill",
            "Role": "Seller"
        }
    ]

The second fact that I have is

    "username_and_status": [
        {
            "isLockedOut": "no",
            "Name": "Jack"
        },
        {
            "isLockedOut": "no",
            "Name": "Tom"
        },
        {
            "isLockedOut": "no",
            "Name": "Jill"
        },
        {
            "isLockedOut": "no",
            "Name": "Brody"
        },
        {
            "isLockedOut": "no",
            "Name": "Steve"
        }
    ]

My objective is that I want to retrieve isLockedOut from second data. If name in username_and_role is equal to name in username_and_status, retrieve the isLockedOut from username and status. and set a fact that show name, role and isLockedOut.

I've tried a few methods and it doesn't work as it didn't do the checking.

  set_fact:
    my_new_list: "{{[username_and_role, {'status': nameIsMatch}] }}"
    cacheable: yes
  with_items: "{{username_and_role}}"
  vars: 
    nameIsMatch: "{% if item.Name == username%}item.isLockedOut{% else %}Name Does not Match{%endif %}"
  loop: "{{username_and_status}}"

This is code has no error but it just did not do the checking between username_and_role & username_and_status

2 Answers

Convert the lists to dictionaries, e.g.

    - set_fact:
        username_and_role: "{{ username_and_role|
                               items2dict(key_name='Name',
                                          value_name='Role') }}"

gives

  username_and_role:
    Jack: Admin User
    Jill: Seller
    Tom: Buyer
    - set_fact:
        username_and_status: "{{ username_and_status|
                                 items2dict(key_name='Name',
                                            value_name='isLockedOut') }}"

gives

  username_and_status:
    Brody: 'no'
    Jack: 'no'
    Jill: 'no'
    Steve: 'no'
    Tom: 'no'

Now you can retrieve the status by using the dictionary, e.g.

    - debug:
        msg: >
          name: {{ item }}
          role: {{ username_and_role[item]|d('NA') }}
          status: {{ username_and_status[item]|d('NA') }}
      loop: "{{ username_and_status.keys()|list }}"

gives

  msg: |-
    name: Jack role: Admin User status: no

  msg: |-
    name: Tom role: Buyer status: no

  msg: |-
    name: Jill role: Seller status: no

  msg: |-
    name: Brody role: NA status: no

  msg: |-
    name: Steve role: NA status: no

just to precise the nice answer of @vladimir-botka, if you just want the persons which are in both variables, you could add a condition when

- debug:
    msg: >
      name: {{ item }}
      role: {{ username_and_role[item] }}
      status: {{ username_and_status[item] }}
  when: username_and_role[item] is defined and username_and_status[item] is defined
  loop: "{{ username_and_status.keys()|list }}"

- debug:
    var: username_and_role | to_nice_json

result:

ok: [localhost] => 
  username_and_role | to_nice_json: |-
    {
        "Jack": "Admin User",
        "Jill": "Seller",
        "Tom": "Buyer"
    }
Related