如何制作 Jinja 中唯一的对列表?

How to make a list of pairs unique in Jinja?

我有一个字典,其中包含来自 Ansible vars 文件的数组值。

ipfilter:
  zone1:
    - { application: "app 1", local_ip: 1.1.1.1 }
    - { application: "app 1", local_ip: 1.1.1.1 }
    - { application: "app 2", local_ip: 2.2.2.2 }
  zone2:
    - { application: "app 3", local_ip: 3.3.3.3 }
    - { application: "app 4", local_ip: 4.4.4.4 }
    - { application: "app 4", local_ip: 4.4.4.4 }

问题是,applicationlocal_ip 的元组不是唯一的,因为对象包含额外的数据,我在示例中省略了这些数据,因为它与以下脚本。

该脚本是 Ansible 传送到 Solaris 服务器的 Jinja 模板:

#! /bin/bash
set -eu
cat <<';' |
{% for zone, rules in ipfilter.items() %}
{%   for rule in rules %}
 {{zone}} {{rule.application}} {{rule.local_ip}}
{%   endfor %}
{% endfor %}
;
sort | uniq | while read zone application local_ip; do
  ipfcfg delete "$zone" "$application" "$local_ip"
done

外层循环遍历字典,内层循环遍历数组值。

我无法使 Jinja 的元组列表唯一。因此我不得不在 Bash 中使用 sort | uniq | while read 循环。这远非完美并且有其自身的局限性。

如何使元组列表在 Jinja 中唯一?

要从您的示例中获取唯一列表对,您可以简单地使用:

ipfilter.values() | sum(start=[]) | unique

但这对你的情况不起作用,因为你从原始数据中省略了其他键,所以 unique 过滤器将不起作用。

您必须在执行任务之前使用一些 Ansible 变量模板魔术来解决此问题:

# construct list of tuples
- set_fact:
    tmp_app: '{"app":"{{item.application}}","ip":"{{item.local_ip}}"}'
  with_items: "{{ ipfilter.values() | sum(start=[]) }}"
  register: tmp_apps
# pass uniq list to template
- template:
    src: script.j2
    dest: script.sh
  vars:
    uniq_apps: "{{ tmp_apps.results | map(attribute='ansible_facts.tmp_app') | list | unique }}"

和 script.j2:

#! /bin/bash
set -eu
{% for app in uniq_apps %}
ipfcfg delete "{{app.app}}" "{{app.ip}}"
{% endfor %}

多亏 and 回答了另一个问题,我才能够在 Jinja 中完成我的所有工作。

#! /bin/bash
set -eu
{% set all_rules = [] %}
{% for zone, rules in ipfilter.items() %}
{%   for rule in rules %}
{%     set x = all_rules.extend([{'zone': zone, 'application': rule.application, 'local_ip': rule.local_ip}]) %}
{%   endfor %}
{% endfor %}
{% for item in all_rules|unique %}
ipfcfg delete {{item.zone|quote}} {{item.application|quote}} {{item.local_ip|quote}}
{% endfor %}