我在Ansible中使用Jinja模板有一个问题。我有这个嵌套字典:
"fruits": {
"summer": {
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
},
"july": {
"fruit": {
"peach": "peach"
},
"vars": {}
},
"august": {
"fruit": {
"watermelon": "watermelon",
"strawberry": "strawberry"
},
"vars": {}
}
}}
,我想删除对象"peach"。我试过pop方法,它工作,但我想使用过滤器rejecattr
我试着:
tasks:
- set_fact:
test: |
{%- for x,y in fruits.items() -%}
{%- for j,k in y.items() -%}
{{ k.fruit | dict2items | rejectattr ('key', 'eq', 'peach') | items2dict }}
{%- endfor -%}
{%- endfor -%}`
它给了我以下内容:
"test": "{
"cherry": "cherry"}
{}
{"watermelon": "watermelon", "strawberry": "strawberry"}"
但是我想要得到开始的结构,less "peach"对象。
任何建议吗?谢谢你
Ansible对于修改深度嵌套的数据结构(或者一般来说修改数据结构)来说不是一个很好的工具。虽然我确信有人会带着一个聪明的json_query
过滤器或其他东西来,但通过编写一个自定义过滤器插件来解决这个问题是微不足道的。如果我们在filter_plugins/badfruit.py
中输入以下内容:
def filter_badfruit(v, *exclude):
for months in v.values():
for data in months.values():
data["fruit"] = {k: v for k, v in data["fruit"].items() if k not in exclude}
return v
class FilterModule(object):
filter_map = {"badfruit": filter_badfruit}
def filters(self):
return self.filter_map
那么我们可以这样写剧本:
- hosts: localhost
gather_facts: false
vars:
"fruits": {
"summer": {
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
},
"july": {
"fruit": {
"peach": "peach"
},
"vars": {}
},
"august": {
"fruit": {
"watermelon": "watermelon",
"strawberry": "strawberry"
},
"vars": {}
}
}}
tasks:
- debug:
var: >-
fruits|badfruit('peach')
得到如下输出:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"fruits|badfruit('peach')": {
"summer": {
"august": {
"fruit": {
"strawberry": "strawberry",
"watermelon": "watermelon"
},
"vars": {}
},
"july": {
"fruit": {},
"vars": {}
},
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
}
}
}
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
过滤器的编写使得我们可以提供多个键来排除:
- debug:
var: >-
fruits|badfruit('peach', 'strawberry')
Q:"我想使用过滤器rejecattr .">
A:代码中的rejecattr行可以原样使用。组合字典
test_str: |
summer:
{% for i in fruits.summer|dict2items %}
{{ i.key }}:
{{ i.value|combine({'fruit': i.value.fruit|dict2items|rejectattr('key', 'eq', 'peach')|items2dict}) }}
{% endfor %}
test: "{{ test_str|from_yaml }}"
给出预期结果
test:
summer:
august:
fruit:
strawberry: strawberry
watermelon: watermelon
vars: {}
july:
fruit: {}
vars: {}
june:
fruit:
cherry: cherry
vars: {}
可选,将排除的项放入字典中,例如
exclude:
fruit: ['peach']
走在树上。变量test也将展开为预期的结果
test_str: |
{% for season,sa in fruits.items() %}
{{ season }}:
{% for month,ma in sa.items() %}
{{ month }}:
{% for a,b in ma.items() %}
{{ a }}:
{
{% for k,v in b.items() %}
{% if k not in exclude[a] %}
{{ k }}: {{ v }},
{% endif %}
{% endfor %}
}
{% endfor %}
{% endfor %}
{% endfor %}
test: "{{ test_str|from_yaml }}"