何时在Ansible中使用from_json过滤器?

时间:2016-12-21 13:29:13

标签: ansible

我何时应该使用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"}
          ]
        }
      ]
    }
    

1 个答案:

答案 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会给你空响应。