Ansible: Loop dentro do loop

Ansible: Loop dentro do loop

No ansible [core 2.13.3] meu arquivo var.yml é assim:

vlans:
  Servers:
    vlan_id: 10
    ip: 192.168.22.20
    mask: 255.255.255.0
    mode:
      tagged: 1/1,1/2
      untagged: 1/3
  Clients:
    vlan_id: 20
    mode:
      tagged: 1/1,1/3
  Printers:
    vlan_id: 30

O objetivo é lançar uma tarefa para cada elemento das vlans (Servidores, Clientes, Impressoras...) e para cada modo (marcado, não marcado, proibido...).

Eu iterei com sucesso em vlans, mas não em vlans e modo. Não consigo encontrar o bom caminho para o sucesso do loop aninhado. Tente tudo como subelemento, with_subelements, loop_nested sem sucesso.

  - name: Set member of vlan
    arubaoss_vlan:
      command: config_vlan_port
      config: "create"
      vlan_id: "{{ item.value.vlan_id }}"
      port_id: "{{ item.value.port | default('') }}"
      port_mode: "{{ item.value.mode | default('POM_UNTAGGED') | regex_replace('^tagged$', 'POM_TAGGED_STATIC') | regex_replace('^untagged$', 'POM_UNTAGGED') | regex_replace('^forbid$', 'POM_FORBIDDEN') }}"
      api_version: "{{ ansible_api_version }}"
      use_ssl: "{{ ansible_use_ssl }}"
      port: "{{ ansible_port }}"
      host: "{{ ansible_host }}"
      username: "{{ ansible_user }}"
      password: "{{ ansible_password }}"
    loop: "{{ lookup('dict', vlans) }}"
    when: "'port' in dict(item)"
    tags:
      - vlans
      - vlans_mode

Como posso fazer um loop aninhado no Ansible?

  - name: Debug2
    debug:
      msg: "Name: {{ item.key }} - mode: {{ item.value.mode }}"
    loop: "{{ lookup('dict', vlans) }}"
    when: "'mode' in dict(item.value)"
    tags:
      - debug

Retorno da depuração 2:

ok: [sw39stack01.group.corp] => (item={'key': 'Servidores', 'valor': {'vlan_id': 10, 'ip': '192.168.22.20', 'máscara': '255.255 .255.0', 'mode': {'tagged': '1/1,1/2', 'untagged': '1/3'}}}) => { "msg": "Nome: Servidores - modo: {'tagged': '1/1,1/2', 'untagged': '1/3'}" } ok: [sw39stack01.group.corp] => (item={'key': 'Clientes', 'value': {'vlan_id': 20, 'mode': {'tagged': '1/1,1/3'}}}) => { "msg": "Nome: Clientes - modo: {'tagged ': '1/1,1/3'}" } pulando: [sw39stack01.group.corp] => (item={'chave': 'Impressoras', 'valor': {'vlan_id': 30}}) => { "ansible_loop_var": "item", "item": { "key": "Impressoras", "valor": { "vlan_id": 30 } } }

Atenciosamente,

Responder1

Converta os dicionáriosmodopara listas

  modes: |
    {% for k,v in vlans.items() %}
    {{ k }}:
      mode: {{ v.mode|d({})|dict2items }}
    {% endfor %}
  vlans2: "{{ vlans|combine(modes|from_yaml, recursive=true) }}"

  vlans2:
    Clients:
      mode:
      - key: tagged
        value: 1/1,1/3
      vlan_id: 20
    Printers:
      mode: []
      vlan_id: 30
    Servers:
      ip: 192.168.22.20
      mask: 255.255.255.0
      mode:
      - key: tagged
        value: 1/1,1/2
      - key: untagged
        value: 1/3
      vlan_id: 10

Converta o dicionáriovlans2para uma lista e iterar comsubelementos valor.modo

    - debug:
        msg: "{{ item.0.key }} {{ item.1.key }} {{ item.1.value }}"
      loop: "{{ vlans2|dict2items|subelements('value.mode') }}"

dá (resumido)

  msg: Servers tagged 1/1,1/2
  msg: Servers untagged 1/3
  msg: Clients tagged 1/1,1/3

Exemplo de um manual completo

- hosts: localhost

  vars:

    vlans:
      Servers:
        vlan_id: 10
        ip: 192.168.22.20
        mask: 255.255.255.0
        mode:
          tagged: 1/1,1/2
          untagged: 1/3
      Clients:
        vlan_id: 20
        mode:
          tagged: 1/1,1/3
      Printers:
        vlan_id: 30

    modes: |
      {% for k,v in vlans.items() %}
      {{ k }}:
        mode: {{ v.mode|d({})|dict2items }}
      {% endfor %}
    vlans2: "{{ vlans|combine(modes|from_yaml, recursive=true) }}"

  tasks:

    - debug:
        var: modes|from_yaml
    - debug:
        var: vlans2
    - debug:
        msg: "{{ item.0.key }} {{ item.1.key }} {{ item.1.value }}"
      loop: "{{ vlans2|dict2items|subelements('value.mode') }}"

Responder2

O arquivo de inventário é editado assim:

vlans:
  - name: Servers
    vlan_id: 10
    ip: 192.168.22.20
    mask: 255.255.255.0
    mode:
      - tagged: 1/1,1/2
      - untagged: 1/3
  - name: Clients
    vlan_id: 20
    mode:
      - tagged: 1/1,1/3
  - name: Printers
    vlan_id: 30

E a consulta é usada:

  - name: Debug1
    ansible.builtin.debug: var=item
    loop: "{{ query('subelements', vlans, 'mode', {'skip_missing': True}) }}"
    tags:
      - debug

A saída funciona conforme esperado:

ok: [sw] => (item=[{'name': 'Servers', 'vlan_id': 10, 'ip': '192.168.22.20', 'mask': '255.255.255.0'}, {'tagged': '1/1,1/2'}]) => {
    "ansible_loop_var": "item",
    "item": [
        {
            "ip": "192.168.22.20",
            "mask": "255.255.255.0",
            "name": "Servers",
            "vlan_id": 10
        },
        {
            "tagged": "1/1,1/2"
        }
    ]
}
ok: [sw] => (item=[{'name': 'Servers', 'vlan_id': 10, 'ip': '192.168.22.20', 'mask': '255.255.255.0'}, {'untagged': '1/3'}]) => {
    "ansible_loop_var": "item",
    "item": [
        {
            "ip": "192.168.22.20",
            "mask": "255.255.255.0",
            "name": "Servers",
            "vlan_id": 10
        },
        {
            "untagged": "1/3"
        }
    ]
}

informação relacionada