Ansible, with_nested, How to asign dynamic variables in loop

ansibleansible-playbook

I'm trying to iterate through the number of entries dynamically in an array and use the output as an index.

Pretty sure I'm doing something wrong.

How can I assign a variable to the sequence end that represents the count of my current array?

ansible-playbook 2.9.6

run.yml:

---
- hosts: localhost

  tasks:
  - name: Import config
    include_vars: 
      file: ./config.yml

  - name: DEBUG
    debug: msg="{{ item[0].team_name }}: {{ item[0].applications.name }}: index: {{ item[1] }}"
    with_nested:
      - "{{ teams }}"
      - "{{ lookup('sequence', 'start=1 end='+(item[0].applications|length))|string }}"

config.yml:

teams:
  - team_name: Name-of-Team_A
    applications:
      - name: app_name_a
      - name: app_name_b
  - team_name: Name-of-Team_B
    applications:
      - name: app_name_c
      - name: app_name_d

Execution:

ansible-playbook run.yml

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

TASK [Gathering Facts] **************************************************************************************************************************************************************
ok: [localhost]

TASK [Import config] ****************************************************************************************************************************************************************
ok: [localhost]

TASK [DEBUG] ************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'item' is undefined"}

PLAY RECAP **************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Desired outcome:

msg: 'Name-of-Team_A: app_name_a: index: 1' 
msg: 'Name-of-Team_A: app_name_b: index: 2' 
msg: 'Name-of-Team_B: app_name_c: index: 1' 
msg: 'Name-of-Team_B: app_name_d: index: 2'

Best Answer

A: For example, the task below

- debug:
    msg: "{{ item.0.team_name }}: {{ item.1.name }}: {{ index1|int + 1 }}"
  with_subelements:
    - "{{ teams }}"
    - applications
  vars:
    team_names: "{{ teams|
                    map(attribute='team_name')|
                    list }}"
    index0: "{{ team_names.index(item.0.team_name) }}"
    applications: "{{ teams|
                      map(attribute='applications')|
                      list }}"
    application_names: "{{ applications[index0|int]|
                           map(attribute='name')|
                           list }}"
    index1: "{{ application_names.index(item.1.name) }}"

gives

  msg: 'Name-of-Team_A: app_name_a: 1'
  msg: 'Name-of-Team_A: app_name_b: 2'
  msg: 'Name-of-Team_B: app_name_c: 1'
  msg: 'Name-of-Team_B: app_name_d: 2'

This solution is limited to unique lists.


A better structure for this use-case is a dictionary. For example, the task below gives the same results

- debug:
    msg: "{{ item.0.key }}: {{ item.1 }}: {{ teams[item.0.key].index(item.1) + 1 }}"
  with_subelements:
    - "{{ teams|dict2items }}"
    - value
  vars:
    teams:
      Name-of-Team_A:
        - app_name_a
        - app_name_b
      Name-of-Team_B:
        - app_name_c
        - app_name_d

The lists must be unique. The method index will find the first match.