如何制作 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 }
问题是,application
和 local_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 %}
我有一个字典,其中包含来自 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 }
问题是,application
和 local_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 %}
多亏
#! /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 %}