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

tec*_*raf 5 ansible

我什么时候应该在Ansible中使用from_json 过滤器

我发现有时使用它有时会产生影响.

请考虑以下示例,说明我得到的不一致.

反向顺序包括:问题 - 预期结果 - 实际结果 - 剧本 - 数据.数据来自这个问题,剧本基于这个答案.

  • 问题:

    为什么将json_query以下表达式的左侧部分(之前)存储在变量中然后json_query对变量使用会导致表达式的计算方式不同?

    "{{ lookup('file','test.json') | json_query(query) }}"
    
    Run Code Online (Sandbox Code Playgroud)

    为什么添加from_json过滤器会改变结果(但如果处理变量则不会):

    "{{ lookup('file','test.json') | from_json | json_query(query) }}"
    
    Run Code Online (Sandbox Code Playgroud)
  • 预期结果:

    最后四个任务应该给出相同的结果.或者,最后两个任务应该提供与前两个任务相同的结果.

  • 实际结果(仅限最后四个任务):

    一项任务结果不同.

    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": ""
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 剧本:

    ---
    - 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"
    
    Run Code Online (Sandbox Code Playgroud)
  • 数据(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"}
          ]
        }
      ]
    }
    
    Run Code Online (Sandbox Code Playgroud)

Kon*_*rov 14

json_query 需要Python对象(dict)作为输入,如果用字符串提供它,它会给出空字符串作为结果.

由于Ansible模板引擎棘手的工作,你会得到不同的结果.
我绝对应该在我的网站上写一篇关于它的帖子......

在评估jijna2表达式后,Ansible尝试将复杂类型转换为Python对象(如dict或list).看到我的其他答案.

在你的情况下:

1.

- set_fact:
    from_lookup_with_from_json: "{{ lookup('file','test.json') | from_json }}"
Run Code Online (Sandbox Code Playgroud)

from_lookup_with_from_json是一个字典,因为您手动将JSON字符串从文件转换为带有from_json过滤器的dict .

2.

- set_fact:
    from_lookup_without_from_json: "{{ lookup('file','test.json') }}"
Run Code Online (Sandbox Code Playgroud)

from_lookup_with_from_json成为dict,因为当jinja2表达式结束时,Ansible会转换它}}.所以from_json实际上不需要作为链中的最后一个过滤器.

3.

  debug: msg="{{ lookup('file','test.json') | from_json | json_query(query) }}"
Run Code Online (Sandbox Code Playgroud)

再次,您在此处手动转换JSON字符串.所以json_query得到dict作为输入.

4.

  debug: msg="{{ lookup('file','test.json') | json_query(query) }}"
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将JSON-string(不是dict)作为输入json_query过滤.由于一切都发生在一个jinja2表达式中,Ansible不会尝试转换其间的任何内容.

您也可以通过这种方式获得带有变量的空字符串结果:

- set_fact:
    from_lookup_force_string: "{{ lookup('file','test.json') | string }}"
Run Code Online (Sandbox Code Playgroud)

在这种情况下from_lookup_force_string,Ansible tempating引擎不会转换,并json_query会给你空响应.

  • `json_query` 是一个命名不当的过滤器,因为它操作的是字典而不是 JSON。也许 dict_query 会更好。 (2认同)