Ansible - 在列表产品(嵌套循环)上循环时枚举列表
Ansible - Enumerate list when looping on list product (nested loop)
我在 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 }}"
我的问题是 - 我有什么方法可以获取第二个列表中的项目索引吗?
- 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_items
和 flatten + loop_control.index
,但我不知道如何写这个,这样我才能得到一个只在第二个列表上循环的索引,并从 0 重新开始新用户(第一个列表中的每个新元素)。
TL;DR - 我正在寻找这个 Python 构造的 ansible 等价物:
for user in users:
for (index, vm_name) in enumerate(vms_per_user):
do_something_with user, index, vm_name
谢谢!
如果 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]
,这将 return 一个新列表 [[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"
}
}
}
等等
即使 larsks 的回答完全有效(我已经在我的剧本中使用他的解决方案几个月了 - 再次感谢你,larsks!),我只是发现还有另一个,更多 "ansible-native"解决我的问题。所以我在这里添加它,以防万一其他人在未来偶然发现这个问题
在 Ansible 2.5 中,在 loop_control
下引入了 index_var
设置。 (参见 docs )。您可以直接使用它,无需额外的自定义过滤器。
语法如下所示:
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
从 Ansible 2.8 开始,有扩展循环增加了对列表索引的支持。检查 https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#extended-loop-variables
基本加上:
loop_control:
extended: yes
并使用ansible_loop.index0
或ansible_loop.index
感谢 Bogd 指导我朝这个方向发展。
我在 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 }}"
我的问题是 - 我有什么方法可以获取第二个列表中的项目索引吗?
- 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_items
和 flatten + loop_control.index
,但我不知道如何写这个,这样我才能得到一个只在第二个列表上循环的索引,并从 0 重新开始新用户(第一个列表中的每个新元素)。
TL;DR - 我正在寻找这个 Python 构造的 ansible 等价物:
for user in users:
for (index, vm_name) in enumerate(vms_per_user):
do_something_with user, index, vm_name
谢谢!
如果 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]
,这将 return 一个新列表 [[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"
}
}
}
等等
即使 larsks 的回答完全有效(我已经在我的剧本中使用他的解决方案几个月了 - 再次感谢你,larsks!),我只是发现还有另一个,更多 "ansible-native"解决我的问题。所以我在这里添加它,以防万一其他人在未来偶然发现这个问题
在 Ansible 2.5 中,在 loop_control
下引入了 index_var
设置。 (参见 docs )。您可以直接使用它,无需额外的自定义过滤器。
语法如下所示:
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
从 Ansible 2.8 开始,有扩展循环增加了对列表索引的支持。检查 https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#extended-loop-variables
基本加上:
loop_control:
extended: yes
并使用ansible_loop.index0
或ansible_loop.index
感谢 Bogd 指导我朝这个方向发展。