我何时应该使用Ansible中的from_json
filter?
我发现有时使用它有时会产生影响。
请考虑以下示例,说明我遇到的不一致。
以相反的顺序包括:问题 - 预期结果 - 实际结果 - 剧本 - 数据。数据来自this question,剧本基于this answer。
问题:
为什么将以下表达式的左侧部分(json_query
之前)存储在变量中然后对变量使用json_query
会导致表达式的计算方式不同?
"{{ lookup('file','test.json') | json_query(query) }}"
为什么添加from_json
过滤器会改变结果(但如果处理变量则不会):
"{{ lookup('file','test.json') | from_json | json_query(query) }}"
预期结果:
最后四个任务应该给出相同的结果。或者,最后两个任务应该提供与前两个任务相同的结果。
实际结果(仅限最后四项):
一项任务结果有所不同。
TASK [This query is run against lookup value with from_json stored in a variable] ***
ok: [localhost] => {
"msg": [
678
]
}
TASK [This query is run against lookup value without from_json stored in a variable] ***
ok: [localhost] => {
"msg": [
678
]
}
TASK [This query is run directly against lookup value with from_json] **********
ok: [localhost] => {
"msg": [
678
]
}
TASK [This query is run directly against lookup value without from_json - the result is empty - why?] ***
ok: [localhost] => {
"msg": ""
}
剧本:
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- set_fact:
from_lookup_with_from_json: "{{ lookup('file','test.json') | from_json }}"
- set_fact:
from_lookup_without_from_json: "{{ lookup('file','test.json') }}"
- name: Save the lookup value stored in a variable in a file for comparison
copy: content="{{ from_lookup_with_from_json }}" dest=./from_lookup_with_from_json.txt
- name: Save the lookup value stored in a variable in a file for comparison (they are the same)
copy: content="{{ from_lookup_without_from_json }}" dest=./from_lookup_without_from_json.txt
- name: This query is run against lookup value with from_json stored in a variable
debug: msg="{{ from_lookup_with_from_json | json_query(query) }}"
vars:
query: "Foods[].{id: Id, for: (Tags[?Key=='For'].Value)[0]} | [?for=='Tigger'].id"
- name: This query is run against lookup value without from_json stored in a variable
debug: msg="{{ from_lookup_without_from_json | json_query(query) }}"
vars:
query: "Foods[].{id: Id, for: (Tags[?Key=='For'].Value)[0]} | [?for=='Tigger'].id"
- name: This query is run directly against lookup value with from_json
debug: msg="{{ lookup('file','test.json') | from_json | json_query(query) }}"
vars:
query: "Foods[].{id: Id, for: (Tags[?Key=='For'].Value)[0]} | [?for=='Tigger'].id"
- name: This query is run directly against lookup value without from_json - the result is empty - why?
debug: msg="{{ lookup('file','test.json') | json_query(query) }}"
vars:
query: "Foods[].{id: Id, for: (Tags[?Key=='For'].Value)[0]} | [?for=='Tigger'].id"
数据(test.json
):
{ "Foods" :
[ { "Id": 456
, "Tags":
[ {"Key":"For", "Value":"Heffalump"}
, {"Key":"Purpose", "Value":"Food"}
]
}
, { "Id": 678
, "Tags":
[ {"Key":"For", "Value":"Tigger"}
, {"Key":"Purpose", "Value":"Food"}
]
}
, { "Id": 911
, "Tags":
[ {"Key":"For", "Value":"Roo"}
, {"Key":"Purpose", "Value":"Food"}
]
}
]
}
答案 0 :(得分:11)
json_query
需要Python对象(dict)作为输入,如果用字符串提供它,它会得到空字符串作为结果。
由于Ansible模板引擎棘手的工作,你会得到不同的结果 我绝对应该在我的网站上写一篇关于它的帖子......
评估jijna2表达式后,Ansible尝试将复杂类型转换为Python对象(如dict或list)。请参阅我的other答案。
在你的情况下:
1
- set_fact:
from_lookup_with_from_json: "{{ lookup('file','test.json') | from_json }}"
from_lookup_with_from_json
是一个字典,因为您手动将JSON字符串从文件转换为带有from_json
过滤器的字典。
2
- set_fact:
from_lookup_without_from_json: "{{ lookup('file','test.json') }}"
from_lookup_with_from_json
成为dict,因为当jinja2表达式以}}
结尾时,Ansible会转换它。因此from_json
实际上不需要作为链中的最后一个过滤器。
3
debug: msg="{{ lookup('file','test.json') | from_json | json_query(query) }}"
再次,您在此处手动转换JSON字符串。所以json_query
得到dict作为输入。
4
debug: msg="{{ lookup('file','test.json') | json_query(query) }}"
在这种情况下,您将JSON-string(不是dict)作为json_query
过滤器的输入。由于一切都发生在一个jinja2表达式中,Ansible不会尝试转换它们之间的任何内容。
您也可以通过这种方式获得空字符串结果:
- set_fact:
from_lookup_force_string: "{{ lookup('file','test.json') | string }}"
在这种情况下,from_lookup_force_string
将不会被Ansible模板引擎转换,而json_query
会给你空响应。