Ansible-在列表产品上循环时枚举列表(嵌套循环)

时间:2019-04-09 15:30:43

标签: loops ansible enumerate indexed

我在Ansible中使用嵌套循环(“为10个用户中的每个用户创建3个VM”):

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

我的问题是-我有什么方法可以获取第二个列表中某项的索引?

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

我了解with_indexed_itemsflatten + loop_control.index,但是我不知道如何写,这样我将得到一个仅在第二个列表上循环的索引,并为每个新用户从0重新开始(第一个列表中的每个新元素)。

TL; DR-我正在寻找与此Python构造等效的版本:

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

谢谢!

3 个答案:

答案 0 :(得分:2)

如果Ansible拥有一个enumerate过滤器,这将非常容易。它没有,但是我们可以给它一个。我将以下内容放入了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,
        }

对于列表[a, b, c],这将返回一个新列表[[0,a], [1,b], [2,c]]。我们可以像这样在您的剧本中使用它:

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

此调试任务的输出将类似于:

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

等等。

答案 1 :(得分:1)

即使Larsks的回答是完全正确的(并且我已经在我的剧本中使用他的解决方案几个月了-再次感谢您,larsks!),但我发现还有另一个更“可解决的-本机”解决方案。所以我在这里添加它,以防万一将来有人偶然发现这个问题

在Ansible 2.5中,index_var下引入了loop_control设置。 (请参见docs)。您可以直接使用它,而无需其他自定义过滤器。

语法如下:

- name: count our fruit
  debug:
    msg: "{{ item }} with index {{ my_idx }}"
  loop:
    - apple
    - banana
    - pear
  loop_control:
    index_var: my_idx

答案 2 :(得分:1)

从 Ansible 2.8 开始,有扩展循环增加了对列表索引的支持。检查https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#extended-loop-variables

基本添加:

loop_control:
  extended: yes

并使用 ansible_loop.index0ansible_loop.index

感谢 Bogd 指引我朝那个方向前进。