首页 > 解决方案 > Ansible 字典嵌套 For 循环

问题描述

我以前尝试过使用这样的字典结构,但只让它在模板中工作。servers我需要遍历所有不匹配的第一级键的子网/子网_cidrs inventory_hostname

---
- name: Test Playbook
  hosts: localhost
  gather_facts: no

  vars:
    servers: 
      alpha.lan:
        eth0:
          subnet: 192.168.0.0
          subnet_mask: 255.255.255.0
          subnet_cidr: 24
        eth1:
          subnet: 192.168.1.0
          subnet_mask: 255.255.255.0
          subnet_cidr: 24
      bravo.lan:
        eth0:
          subnet: 172.16.0.0
          subnet_mask: 255.255.252.0
          subnet_cidr: 22
        eth1:
          subnet: 172.16.4.0
          subnet_mask: 255.255.252.0
          subnet_cidr: 22

  tasks:
    - debug:
        msg: "{{something['subnet']}}/{{something['subnet_cidr']}}"
      loop: "{{servers...}}"

所以如果这个剧本是在 alpha.lan 上运行的,我会得到

"msg": "172.16.0.0/22"
"msg": "172.16.4.0/22"

这就是我让它在模板中工作的方式,能够在最终输出中使用 item 和 item2 的值:

{% for key,item in servers.items() if key != inventory_hostname %}
{% for key2,item2 in item.items() %}
{{item2['subnet']}}/{{item2['subnet_cidr']}}
{% endfor %}
{% endfor %}

我希望能够在防火墙命令中独立使用或测试每个第三级密钥(子网、子网掩码、子网_cidr)。提前感谢您的帮助。

我尝试使用的一些信息源: https:
//docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html
https ://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-filters

标签: ansiblejinja2nested-loops

解决方案


给定字典服务器剧本

- hosts: alpha.lan,bravo.lan
  tasks:
    - debug:
        msg: "{{ item.value.subnet }}/{{ item.value.subnet_cidr }}"
      loop: "{{ servers[host]|dict2items }}"
      loop_control:
        label: "{{ item.key }}"
      vars:
        host: "{{ servers|difference([inventory_hostname])|first }}"

给出(删节)

TASK [debug] ****
ok: [alpha.lan] => (item=eth0) => 
  msg: 172.16.0.0/22
ok: [alpha.lan] => (item=eth1) => 
  msg: 172.16.4.0/22
ok: [bravo.lan] => (item=eth0) => 
  msg: 192.168.0.0/24
ok: [bravo.lan] => (item=eth1) => 
  msg: 192.168.1.0/24

问:第一级键的列表,……遍历服务器……同时遍历每个服务器的第二级键

给定字典

servers: 
  alpha.lan:
    eth0:
      subnet: 192.168.0.0
      subnet_cidr: 24
    eth1:
      subnet: 192.168.1.0
      subnet_cidr: 24
  bravo.lan:
    eth0:
      subnet: 172.16.0.0
      subnet_cidr: 22
    eth1:
      subnet: 172.16.4.0
      subnet_cidr: 22
  charlie.lan:
    eth0:
      subnet: 172.17.0.0
      subnet_cidr: 22
    eth1:
      subnet: 172.17.4.0
      subnet_cidr: 22

和任务

shell> cat loop-net.yml
- debug:
    msg: "inventory: {{ inventory_hostname }}
          server: {{ outer_item }}
          net: {{ item.value.subnet }}/{{ item.value.subnet_cidr }}"
  loop: "{{ servers[outer_item]|dict2items }}"
  loop_control:
    label: "{{ item.key }}"

下面的剧本

shell> cat pb.yml
- hosts: alpha.lan,bravo.lan,charlie.lan
  tasks:
    - include_tasks: loop-net.yml
      loop: "{{ servers.keys()|difference([inventory_hostname]) }}"
      loop_control:
        loop_var: outer_item

shell> ansible-playbook pb.yml | grep msg | sort
  msg: 'inventory: alpha.lan server: bravo.lan net: 172.16.0.0/22'
  msg: 'inventory: alpha.lan server: bravo.lan net: 172.16.4.0/22'
  msg: 'inventory: alpha.lan server: charlie.lan net: 172.17.0.0/22'
  msg: 'inventory: alpha.lan server: charlie.lan net: 172.17.4.0/22'
  msg: 'inventory: bravo.lan server: alpha.lan net: 192.168.0.0/24'
  msg: 'inventory: bravo.lan server: alpha.lan net: 192.168.1.0/24'
  msg: 'inventory: bravo.lan server: charlie.lan net: 172.17.0.0/22'
  msg: 'inventory: bravo.lan server: charlie.lan net: 172.17.4.0/22'
  msg: 'inventory: charlie.lan server: alpha.lan net: 192.168.0.0/24'
  msg: 'inventory: charlie.lan server: alpha.lan net: 192.168.1.0/24'
  msg: 'inventory: charlie.lan server: bravo.lan net: 172.16.0.0/22'
  msg: 'inventory: charlie.lan server: bravo.lan net: 172.16.4.0/22'

下面的任务给出了相同的结果

    - debug:
        msg: "inventory: {{ inventory_hostname }}
              server: {{ item.0.key }}
              net: {{ item.1.net }}"
      with_subelements:
        - "{{ my_servers|from_yaml|dict2items }}"
        - value
      vars:
        my_servers: |
          {% for key,item in servers.items() if key != inventory_hostname %}
            {{ key }}:
          {% for key2,item2 in item.items() %}
              - {ifc: {{ key2 }}, net: {{ item2.subnet }}/{{ item2.subnet_cidr }}}
          {% endfor %}
          {% endfor %}

推荐阅读