loopsansibleenumerateindexed

Ansible - Enumerate list when looping on list product (nested loop)


I am using a nested loop in Ansible ("create 3 VMs for each of the 10 users"):

  - name: Add hosts to inventory
    add_host:
      name: "{{ '%s-%02d-%02d' | format(vm_prefix, item.0, item.1.number) }}"
      groups: vms
    loop: "{{userlist | product(vms_per_user) | list }}"  

My question is - do I have any way of getting the index of an item in the second list?

  - name: Add hosts to inventory
    add_host:
      name: "{{ '%s-%02d-%02d' | format(vm_prefix, item.0, item.1.number) }}"
      groups: vms
      vm_index: "{{ get the index of this particular VM in vms_per_user }}"
    loop: "{{userlist | product(vms_per_user) | list }}"  

I know about with_indexed_items and flatten + loop_control.index, but I cannot figure out how to write this so that I will get an index that loops only on the second list, and restarts from 0 for every new user (every new element in the first list).

TL;DR - I am looking for the ansible equivalent of this Python construct:

for user in users:
  for (index, vm_name) in enumerate(vms_per_user):
     do_something_with user, index, vm_name

Thank you!


Solution

  • If Ansible had an enumerate filter this would be pretty easy. It doesn't, but we can give it one. I put the following content into filter_plugins/enumerate.py:

    #!/usr/bin/python
    
    
    def filter_enumerate(v):
        return list(enumerate(v))
    
    
    class FilterModule (object):
        def filters(self):
            return {
                'enumerate': filter_enumerate,
            }
    

    For a list [a, b, c], this will return a new list [[0,a], [1,b], [2,c]]. We can use that in your playbook like this:

    ---
    - hosts: localhost
      gather_facts: false
      vars:
        userlist:
          - alice
          - bob
          - mallory
        vms_per_user:
          - vm1
          - vm2
          - vm3
        vm_prefix: foo-
    
      tasks:
        - debug:
            msg:
              add_host:
                name: "{{ vm_prefix }}{{ item.0 }}-{{ item.1.1 }}"
                groups: vms
                vm_index: "{{ item.1.0 }}"
          loop: "{{ userlist | product(vms_per_user|enumerate) | list }}"
    

    The output of this debug task will look something like:

    ok: [localhost] => (item=[u'alice', [0, u'vm1']]) => {                                                                                                                                         
        "msg": {                                                                                                                                                                                   
            "add_host": {                                                                                                                                                                          
                "groups": "vms",                                                                                                                                                                   
                "name": "foo-alice-vm1",                                                                                                                                                           
                "vm_index": "0"                                                                                                                                                                    
            }                                                                                                                                                                                      
        }                                                                                                                                                                                          
    }                                                                                                                                                                                              
    ok: [localhost] => (item=[u'alice', [1, u'vm2']]) => {                                                                                                                                         
        "msg": {                                                                                                                                                                                   
            "add_host": {                                                                                                                                                                          
                "groups": "vms",                                                                                                                                                                   
                "name": "foo-alice-vm2",                                                                                                                                                           
                "vm_index": "1"                                                                                                                                                                    
            }                                                                                                                                                                                      
        }                                                                                                                                                                                          
    }                                                                                                                                                                                              
    ok: [localhost] => (item=[u'alice', [2, u'vm3']]) => {                                                                                                                                         
        "msg": {                                                                                                                                                                                   
            "add_host": {                                                                                                                                                                          
                "groups": "vms", 
                "name": "foo-alice-vm3", 
                "vm_index": "2"
            }
        }
    }
    

    Etc.