3

I'm writing an ansible playbook that creates users in an internal system through a call to an API where the request body contains all of the user information in json format.

Right now my playbook hold all of those variables in a list of dictionaries like this:

userInfoDict: "{{[ {'FirstName': 'John', 'LastName': 'Lennon', 'Number': '', 'email': 'john@example.com'}, {'FirstName': 'Paul', 'LastName': 'McCartney', 'Number': '', 'email': 'paul@example.com'} ]}}" 

Where the "Number" field is blank, I have a play to grab available phone numbers from an internal DB, and that list of numbers is held in a variable called numberList

What I want to do, is to iterate through UserInfoDict, and set the Number field to the next value in my list of numbers, But I haven't been able to do that.

Is there any way to do something like this in ansible? Where you access an object at an index of a list?

 - set_fact:
      finalUserInfo: "{{userInfoDict[i].Number : item}}"
   loop: "{{numberList}}

Something like this ^

Sernut
  • 33
  • 4

1 Answers1

4

You can use the zip filter to combine the two lists together. This implies that you have an entry in your numberList for each element in your userInfoDict (side note: which is a misleading var name IMO since it is a list). I created such a list below from what I understood from your question.

You can loop directly on the zipped lists and access their relevant values.

If you absolutely need to create a new list of dicts with the combined info, there are several ways to do so. I used the json_query filter as a demo below (this requires pip install jmespath on the controller).

(Note: in the below playbook, the rather ugly ... to_json | from_json ... is needed to overcome a bug in jmespath <-> ansible communication where each elements of the zipped lists are otherwise interpreted as strings.)

---
- name: Zip demo
  hosts: localhost
  gather_facts: false

  vars:
    userInfoDict: [{'FirstName':'John','LastName':'Lennon','Number':'','email':'john@example.com'},{'FirstName':'Paul','LastName':'McCartney','Number':'','email':'paul@example.com'}]
    numberList: ["+33123456789", "+33612345678"]

  tasks:
    - name: Looping over zipped lists directly
      vars:
        fancy_message: |-
          User first name is: {{ item.0.FirstName }}
          User last name is: {{ item.0.LastName }}
          User number is: {{ item.1 }}
          User email is: {{ item.0.email }}
      debug:
        msg: "{{ fancy_message.split('\n') }}"
      loop: "{{ userInfoDict | zip(numberList) | list }}"
      loop_control:
        label: "{{ item.0.FirstName }} {{ item.0.LastName }}"

    - name: Creating a new list of dicts with json_query
      vars:
        new_dict_query: >-
          [*].{
            "FirstName": [0].FirstName,
            "LastName": [0].LastName,
            "Number": [1],
            "email": [0].email
          }
        new_dict_list: >-
          {{
             userInfoDict
             | zip(numberList)
             | list
             | to_json
             | from_json
             | json_query(new_dict_query)
           }}
      debug:
        var: new_dict_list

which gives:

PLAY [Zip demo] *****************************************************************************************************************************************************************************************************************************

TASK [Looping over zipped lists directly] ***************************************************************************************************************************************************************************************************
ok: [localhost] => (item=John Lennon) => {
    "msg": [
        "User first name is: John",
        "User last name is: Lennon",
        "User number is: +33123456789",
        "User email is: john@example.com"
    ]
}
ok: [localhost] => (item=Paul McCartney) => {
    "msg": [
        "User first name is: Paul",
        "User last name is: McCartney",
        "User number is: +33612345678",
        "User email is: paul@example.com"
    ]
}

TASK [Creating a new list of dicts with json_query] *****************************************************************************************************************************************************************************************
ok: [localhost] => {
    "new_dict_list": [
        {
            "FirstName": "John",
            "LastName": "Lennon",
            "Number": "+33123456789",
            "email": "john@example.com"
        },
        {
            "FirstName": "Paul",
            "LastName": "McCartney",
            "Number": "+33612345678",
            "email": "paul@example.com"
        }
    ]
}

PLAY RECAP **********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
  • 3
    [*I am calling John right now, and he has a french phone number so I should be able to understand it all*](https://en.wikipedia.org/wiki/Fictitious_telephone_number#France). PS: there is a real, no kidding tip in this link. – β.εηοιτ.βε Sep 23 '20 at 18:18