Ansible — перечислить список при цикле по продукту списка (вложенный цикл)

Я использую вложенный цикл в Ansible («создайте 3 виртуальные машины для каждого из 10 пользователей»):

  - 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:

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

Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
2 580
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Если бы в 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"
        }
    }
}

И т.п.

Вот это вообще гениально! :) Спасибо! На самом деле я искал фильтр enumerate, но понятия не имел, как его добавить.

Bogd 09.04.2019 19:00

Рад помочь! Если вас устраивает этот ответ, вы можете поставить галочку слева от вас.

larsks 09.04.2019 19:04

Из любопытства - насколько мне известно, enumerate возвращает список кортежей. Однако на выходе ansible отображается список списков. Является ли это поведение специфичным для ansible или какой-то особенностью python, о которой я не знаю? Чтобы ответить на ваш другой комментарий - я также приму ответ, как только у меня будет возможность его проверить. Еще раз, спасибо!

Bogd 09.04.2019 19:07

Подозреваю, что Jinja просто конвертирует кортежи в списки, но точно не знаю. Я не думаю, что различие имеет смысл в этой ситуации.

larsks 09.04.2019 19:52

Несмотря на то, что ответ larsks совершенно действителен (и я уже несколько месяцев использую его решение в своих сборниках игр - еще раз спасибо за это, larsks!), я только что узнал, что есть другое, более "нативное" решение. к моей проблеме. Поэтому я добавляю это сюда, на случай, если кто-то еще наткнется на проблему в будущем.

В Ansible 2.5 параметр index_var был введен в loop_control. (см. документы ). Вы можете использовать это напрямую, без необходимости в дополнительных настраиваемых фильтрах.

Синтаксис выглядит следующим образом:

- 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

Спасибо Богду за то, что направил меня в этом направлении.

Другие вопросы по теме