在Ansible中过滤JSON文档

问题描述:

我有一个来自GitHub存储库的JSON回复,其中包含某个版本的可能下载列表(文档中的assets数组)。在Ansible中过滤JSON文档

我想获取浏览器下载URL当资产的namex64.AppImage结尾时。

在Ansible,过滤器是内置APON jmespath和使用它的终端工具,我可以用下面的表达式查询的网址:

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" 
} 

在JMESPath过滤器类型错误的问题在issue 27299讨论。

您可以使用此patched json_query.py过滤器插件。

或将双重转换应用于您的对象作为解决方法:| to_json | from_json |
这会将对象转换为JSON(因此为纯字符串)并返回,因此json_query会将字符串视为受支持的类型。

  • 循环每一个资产
  • 打印项目的浏览器的URL,如果它不使用JMESPathx64.AppImage

解决方案结束:

- 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错误。这个错误来自the following checkjmespath库:

 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`)]') }} 
+1

的问题是在这里讨论:https://github.com/ansible/ansible/issues/27299#issuecomment-331068246和解决方法就是使用'| to_json | from_json |' –

+0

@KonstantinSuvorov你提出的解决办法是最好的解决方案,因为它避免了循环在上述文档。如果您发布答案,我会接受它。 –