Search code examples
loopsansiblejinja2

ansible loop list and range


I have a list:

['bob', 'john', 'jack', 'rick']

I have a fixed range: 10,20 step: 2

I want to build this variable:

my_var:
  - name: bob
    content: '10'
  - name: john
    content: '12'
  - name: jack
    content: '14'
  - name: rick
    content: '16'

It seems I have to use loop but I don't understand how !


Solution

  • Loop the lists with the zip filter. For example, the playbook

    - hosts: localhost
      vars:
        my_users: [bob, john, jack, rick]
      tasks:
        - set_fact:
            my_var: "{{ my_var|default([]) +
                        [{'name': item.1, 'content': item.0}] }}"
          loop: "{{ range(10,20,2)|zip(my_users)|list }}"
        - debug:
            var: my_var
    

    gives

      my_var:
        - {content: 10, name: bob}
        - {content: 12, name: john}
        - {content: 14, name: jack}
        - {content: 16, name: rick}
    

    The iteration is not needed if you can use the collection community.general. For example, the playbook below gives the same result

    - hosts: localhost
      vars:
        my_users: [bob, john, jack, rick]
        my_var: "{{ range(10,20,2)|
                    zip(my_users)|
                    map('zip', ['content', 'name'])|
                    map('map', 'reverse')|
                    map('community.general.dict')|
                    list }}"
      tasks:
        - debug:
            var: my_var
    

    The values of the attribute content are integers in both options above. Convert the integers to strings if you need them. For example, in the loop, change the task

        - set_fact:
            my_var: "{{ my_var|default([]) +
                        [{'name': item.1, 'content': item.0|string}] }}"
          loop: "{{ range(10,20,2)|zip(my_users)|list }}"
    

    , or change the declaration

        my_var: "{{ range(10,20,2)|map('string')|
                    zip(my_users)|
                    map('zip', ['content', 'name'])|
                    map('map', 'reverse')|
                    map('community.general.dict')|
                    list }}"
    

    Both options give the same result (note the quoted numbers (strings) instead of the unquoted numbers in the first two options)

      my_var:
        - {content: '10', name: bob}
        - {content: '12', name: john}
        - {content: '14', name: jack}
        - {content: '16', name: rick}