在 Ansible 中过滤 JSON 文档
Filter a JSON document in Ansible
我收到来自 GitHub 存储库的 JSON 回复,其中包含特定版本的可能下载列表(文档中的 assets
数组)。
当资产的 name
以 x64.AppImage
结尾时,我想获取 浏览器下载 URL。
在 Ansible 中,过滤器是根据 jmespath
构建的,使用它的终端工具,我可以使用以下表达式查询 url:
assets[?ends_with(name, 'x64.AppImage')].browser_download_url
使用以下剧本,查询 JSON 文档并将其存储在 json_reply
变量中。
---
- hosts: local
tasks:
- name: Get list of Rambox releases
uri:
url: "https://api.github.com/repos/saenzramiro/rambox/releases/latest"
body_format: json
register: json_reply
- name: Filter reply
debug: URL -> "{{ item }}"
with_items:
- "{{ json_reply.json | json_query(json_filter) }}"
vars:
- json_filter: assets[?ends_with(name, 'x64.AppImage')].browser_download_url
但是,执行此操作会出现以下错误:
fatal: [localhost]: FAILED! => {
"msg": "JMESPathError in json_query filter plugin:\nIn function ends_with(), invalid type for value: latest-mac.json, expected one of: ['string'], received: \"unknown\""
}
其中 latest-mac.json
是 assets
数组中的第一个对象。
如何让 Ansible 遍历所有 assets
数组并应用我的过滤器?
PS:
如果我不查询 name
是否以我直接指定的单词结尾,过滤器就会起作用:
assets[?name == 'Rambox-0.5.13-x64.AppImage')].browser_download_url
JSON 例子:
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/8001922",
"prerelease": false,
"created_at": "2017-10-04T21:14:15Z",
"published_at": "2017-10-05T01:10:55Z",
"assets": [
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/assets/4985942",
"id": 4985942,
"name": "latest-mac.json",
"uploader": {
"login": "saenzramiro",
"id": 2694669
},
"browser_download_url": "https://github.com/saenzramiro/rambox/releases/download/0.5.13/latest-mac.json"
},
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/assets/4985640",
"id": 4985640,
"name": "Rambox-0.5.13-x64.AppImage",
"uploader": {
"login": "saenzramiro",
"id": 2694669
},
"browser_download_url": "https://github.com/saenzramiro/rambox/releases/download/0.5.13/Rambox-0.5.13-x64.AppImage"
}
],
"tarball_url": "https://api.github.com/repos/saenzramiro/rambox/tarball/0.5.13"
}
- 遍历每个资产
- 如果项目以
x64.AppImage
结尾,则打印项目的浏览器 URL
不使用JMESPath
的解决方法:
- name: Filter reply
debug: var=item.browser_download_url
with_items: "{{ json_reply.json.assets }}"
when: item.browser_download_url | regex_search('x64.AppImage$')
正如@helloV 所说,您可以使用 Ansible 循环来完成此操作,尽管没有理由涉及正则表达式匹配。您可以使用您已经在使用的相同测试:
- name: Filter reply
debug:
var: item.browser_download_url
with_items: "{{ json_reply.json.assets }}"
when: item.name.endswith('x64.AppImage')
根本问题似乎是 Ansible 错误。错误来自 jmespath
库中的 the following check:
if actual_typename not in allowed_types:
raise exceptions.JMESPathTypeError(
function_name, current,
self._convert_to_jmespath_type(actual_typename), types)
在调用此代码时,json 响应中值的数据类型为 AnsibleUnsafeText
,而 allowed_types
为 [str, unicode]
。我认为值从原生类型到 AnsibleUnsafeText
类型的转换可能是 uri
模块强加的某种标准 Ansible 模块行为。我们可以通过使用 curl
来解决它,像这样:
- name: Get list of Rambox releases
command: >
curl -s "https://api.github.com/repos/saenzramiro/rambox/releases/latest"
register: json_reply
然后:
- name: Filter reply
debug:
var: item.browser_download_url
with_items: >
{{ json_reply.stdout|from_json|json_query('assets[?ends_with(name, `x64.AppImage`)]') }}
JMESPath 过滤器中的类型错误问题在 issue 27299 中讨论。
您可以使用这个 patched json_query.py 过滤器插件。
或者对您的对象应用双重转换作为解决方法:| to_json | from_json |
。
这会将对象转换为 JSON(因此是纯字符串)并返回,因此 json_query 会将字符串视为受支持的类型。
我收到来自 GitHub 存储库的 JSON 回复,其中包含特定版本的可能下载列表(文档中的 assets
数组)。
当资产的 name
以 x64.AppImage
结尾时,我想获取 浏览器下载 URL。
在 Ansible 中,过滤器是根据 jmespath
构建的,使用它的终端工具,我可以使用以下表达式查询 url:
assets[?ends_with(name, 'x64.AppImage')].browser_download_url
使用以下剧本,查询 JSON 文档并将其存储在 json_reply
变量中。
---
- hosts: local
tasks:
- name: Get list of Rambox releases
uri:
url: "https://api.github.com/repos/saenzramiro/rambox/releases/latest"
body_format: json
register: json_reply
- name: Filter reply
debug: URL -> "{{ item }}"
with_items:
- "{{ json_reply.json | json_query(json_filter) }}"
vars:
- json_filter: assets[?ends_with(name, 'x64.AppImage')].browser_download_url
但是,执行此操作会出现以下错误:
fatal: [localhost]: FAILED! => {
"msg": "JMESPathError in json_query filter plugin:\nIn function ends_with(), invalid type for value: latest-mac.json, expected one of: ['string'], received: \"unknown\""
}
其中 latest-mac.json
是 assets
数组中的第一个对象。
如何让 Ansible 遍历所有 assets
数组并应用我的过滤器?
PS:
如果我不查询 name
是否以我直接指定的单词结尾,过滤器就会起作用:
assets[?name == 'Rambox-0.5.13-x64.AppImage')].browser_download_url
JSON 例子:
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/8001922",
"prerelease": false,
"created_at": "2017-10-04T21:14:15Z",
"published_at": "2017-10-05T01:10:55Z",
"assets": [
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/assets/4985942",
"id": 4985942,
"name": "latest-mac.json",
"uploader": {
"login": "saenzramiro",
"id": 2694669
},
"browser_download_url": "https://github.com/saenzramiro/rambox/releases/download/0.5.13/latest-mac.json"
},
{
"url": "https://api.github.com/repos/saenzramiro/rambox/releases/assets/4985640",
"id": 4985640,
"name": "Rambox-0.5.13-x64.AppImage",
"uploader": {
"login": "saenzramiro",
"id": 2694669
},
"browser_download_url": "https://github.com/saenzramiro/rambox/releases/download/0.5.13/Rambox-0.5.13-x64.AppImage"
}
],
"tarball_url": "https://api.github.com/repos/saenzramiro/rambox/tarball/0.5.13"
}
- 遍历每个资产
- 如果项目以
x64.AppImage
结尾,则打印项目的浏览器 URL
不使用JMESPath
的解决方法:
- name: Filter reply
debug: var=item.browser_download_url
with_items: "{{ json_reply.json.assets }}"
when: item.browser_download_url | regex_search('x64.AppImage$')
正如@helloV 所说,您可以使用 Ansible 循环来完成此操作,尽管没有理由涉及正则表达式匹配。您可以使用您已经在使用的相同测试:
- name: Filter reply
debug:
var: item.browser_download_url
with_items: "{{ json_reply.json.assets }}"
when: item.name.endswith('x64.AppImage')
根本问题似乎是 Ansible 错误。错误来自 jmespath
库中的 the following check:
if actual_typename not in allowed_types:
raise exceptions.JMESPathTypeError(
function_name, current,
self._convert_to_jmespath_type(actual_typename), types)
在调用此代码时,json 响应中值的数据类型为 AnsibleUnsafeText
,而 allowed_types
为 [str, unicode]
。我认为值从原生类型到 AnsibleUnsafeText
类型的转换可能是 uri
模块强加的某种标准 Ansible 模块行为。我们可以通过使用 curl
来解决它,像这样:
- name: Get list of Rambox releases
command: >
curl -s "https://api.github.com/repos/saenzramiro/rambox/releases/latest"
register: json_reply
然后:
- name: Filter reply
debug:
var: item.browser_download_url
with_items: >
{{ json_reply.stdout|from_json|json_query('assets[?ends_with(name, `x64.AppImage`)]') }}
JMESPath 过滤器中的类型错误问题在 issue 27299 中讨论。
您可以使用这个 patched json_query.py 过滤器插件。
或者对您的对象应用双重转换作为解决方法:| to_json | from_json |
。
这会将对象转换为 JSON(因此是纯字符串)并返回,因此 json_query 会将字符串视为受支持的类型。