嵌套列表中的Ansible动态查找

时间:2018-08-10 09:13:03

标签: ansible

我有一个静态变量,它保存清单中所有主机的IP地址(如何动态获取是一个单独的问题),如下所示:

server_ips:
  www1.example.com:
    ipv4:
      - 192.168.0.10
      - 192.168.0.11
    ipv6:
      - '2a00:abcd:1234::100'
      - '2a00:abcd:1234::101'
  www2.example.com:
    ipv4:
    ipv6:
      - '2a00:abcd:1234::200'
      - '2a00:abcd:1234::201'
  db1.example.com:
    ipv4:
      - 192.168.1.2
    ipv6:

这些名称与我的清单中的主机一致:

[webservers]
www1.example.com
www2.example.com

[dbservers]
db1.example.com

对于在dbservers组上运行的任务,我需要一个webserver组中所有IP的列表(这使查询事实直接变得棘手,因为可能没有为那些主机收集事实) -在这种情况下,它需要提取:

- 192.168.0.10
- 192.168.0.11
- '2a00:abcd:1234::100'
- '2a00:abcd:1234::101'
- '2a00:abcd:1234::200'
- '2a00:abcd:1234::201'

这些任务将执行以下操作,例如配置防火墙和数据库访问:

- name: Allow web server access to DB server
  ufw:
    rule: allow
    name: mysql
    from_ip: "{{ item }}"
  loop: "{{ <loop expression goes here> }}"

这是我遇到问题的loop表达式中的内容。

查询有两个部分:提取主机列表,然后收集ip地址-分别对ipv4和ipv6做就可以了。

我可以用类似这样的表达式来达到目的

{{ server_ips | map('extract', groups['webservers']) }}
{{ server_ips | intersect(groups['webservers']) }}

但是,这两者似乎都使结果变平,因此尽管它们找到了正确的项目,但是ipv4ipv6列表元素不存在,因此我无法继续进行下一步。交换这些列表也没有帮助。

subelements查找似乎是获取IP部分(虽然我实际上需要子子元素)并跳过空条目的一种好方法,但是我看不出如何达到这一点。

我应该如何进行查找?

1 个答案:

答案 0 :(得分:0)

您尝试重新设计功能,Ansible已提供。您可以定义自己的DIY库存,尽管Ansible已经有一个库存。尽管Ansible知道如何遍历其库存,但您仍定义了自己的DIY库存迭代。

如果要将数据分配给各个主机,请使用Best Practices中所示的host_vars目录。

host_vars/www1.example.com.yml

ipv4:
  - 192.168.0.10
  - 192.168.0.11
ipv6:
  - '2a00:abcd:1234::100'
  - '2a00:abcd:1234::101'

host_vars/www2.example.com.yml

ipv4:
ipv6:
  - '2a00:abcd:1234::200'
  - '2a00:abcd:1234::201'

然后,您为每个主机定义一个任务,并将{{ipv4}}{{ipv6}}列表用于您要执行的任何操作。

如果您需要在其他主机(如防火墙)上执行操作,请使用Ansible's delegation

这将从您的server_ips字典中提取所有IP地址:

- hosts: localhost
  connection: local
  gather_facts: no

  vars:

    server_ips:
      www1.example.com:
        ipv4:
          - 192.168.0.10
          - 192.168.0.11
        ipv6:
          - '2a00:abcd:1234::100'
          - '2a00:abcd:1234::101'
      www2.example.com:
        ipv4:
        ipv6:
          - '2a00:abcd:1234::200'
          - '2a00:abcd:1234::201'
      xyz.example.com:
        ipv4:
          - 192.168.1.2
        ipv6:

    ipv4: >-
      {% set ipv4 = []                                                                        -%}
      {% for ips in server_ips.values() | selectattr ('ipv4') | map (attribute='ipv4') | list -%}
      {%   for ip in ips                                                                      -%}
      {%     set _ = ipv4.append(ip)                                                          -%}
      {%   endfor                                                                             -%}
      {% endfor                                                                               -%}
      {{ ipv4 }}

    ipv6: >-
      {% set ipv6 = []                                                                        -%}
      {% for ips in server_ips.values() | selectattr ('ipv6') | map (attribute='ipv6') | list -%}
      {%   for ip in ips                                                                      -%}
      {%     set _ = ipv6.append(ip)                                                          -%}
      {%   endfor                                                                             -%}
      {% endfor                                                                               -%}
      {{ ipv6 }}

    ips: >-
      {{ ipv4 + ipv6 }}

  tasks:
    - debug: var=server_ips
    - debug: var=ipv4
    - debug: var=ipv6
    - debug: var=ips

但是要构建防火墙规则,您必须构建交叉产品。您必须遍历所有来源的每个目的地,以获得所有规则。