Перебор двух списков в Ansible

#ansible #ansible-facts

#ansible #ansible-факты

Вопрос:

Я пишу ansible playbook, который создает пользователей во внутренней системе посредством вызова API, где тело запроса содержит всю информацию о пользователе в формате json.

Прямо сейчас мой сборник содержит все эти переменные в списке словарей, подобных этому:

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

Там, где поле «Номер» пустое, у меня есть возможность получить доступные телефонные номера из внутренней базы данных, и этот список номеров хранится в переменной с именем numberList

Что я хочу сделать, так это выполнить итерацию через UserInfoDict и установить в поле Number следующее значение в моем списке чисел, но я не смог этого сделать.

Есть ли какой-нибудь способ сделать что-то подобное в ansible? Где вы получаете доступ к объекту по индексу списка?

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

Что-то вроде этого ^

Ответ №1:

Вы можете использовать zip фильтр для объединения двух списков вместе. Это означает, что у вас есть запись в вашем numberList для каждого элемента в вашем userInfoDict (примечание: это вводящее в заблуждение имя переменной IMO, поскольку это список). Я создал такой список ниже из того, что я понял из вашего вопроса.

Вы можете выполнять цикл непосредственно по архивированным спискам и получать доступ к их соответствующим значениям.

Если вам абсолютно необходимо создать новый список dicts с объединенной информацией, есть несколько способов сделать это. Я использовал json_query фильтр в качестве демонстрации ниже (для этого требуется pip install jmespath контроллер).

(Примечание: в приведенном ниже сборнике задач довольно уродливое ... to_json | from_json ... решение необходимо для устранения ошибки в jmespath <-> ansible communication, где каждый элемент заархивированных списков иначе интерпретируется как строки.)

 ---
- 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
  

что дает:

 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
  

Комментарии:

1. Я сейчас звоню Джону, и у него есть французский номер телефона, так что я должен быть в состоянии все это понять . PS: в этой ссылке есть реальный, без шуток, совет.