Search code examples
ansiblejmespath

How do I get Ansible's json_query to return a value from this JSON document


After several hours of beating my head against this (not to mention leaving it for a day) I'm pretty much stumped on trying to figure out why I can't JMESPath to return a value in Ansible.

I have a task which runs a shell command and returns the following output:

[
    {
        "ansible_loop_var": "item",
        "changed": false,
        "cmd": [
            "pvesh",
            "create",
            "/access/users/user@pve/token/pve-apikey",
            "-privsep=0",
            "--output=json"
        ],
        "delta": "0:00:00.707130",
        "end": "2022-09-22 12:28:43.746253",
        "failed": false,
        "invocation": {
            "module_args": {
                "_raw_params": "pvesh create /access/users/\"user@pve\"/token/\"pve-apikey\" -privsep=0 --output=json",
                "_uses_shell": false,
                "argv": null,
                "chdir": null,
                "creates": null,
                "executable": null,
                "removes": null,
                "stdin": null,
                "stdin_add_newline": true,
                "strip_empty_ends": true,
                "warn": false
            }
        },
        "item": {
            "token": "pve-apikey",
            "user": "user@pve"
        },
        "msg": "",
        "rc": 0,
        "start": "2022-09-22 12:28:43.039123",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "{\"full-tokenid\":\"user@pve!pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"dc2aa48f-daf6-4efe-b95e-83774a588988\"}",
        "stdout_lines": [
            "{\"full-tokenid\":\"user@pve!pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"dc2aa48f-daf6-4efe-b95e-83774a588988\"}"
        ]
    }
]

I'm now trying to obtain the UUID returned as value in the stdout_line using json_query and this is far as I can get:

    - debug:
        msg: "{{ token | community.general.json_query(query) }}"
      vars:
        query: '[].stdout'

This json_query returns the following output:

"msg": [
        "{\"full-tokenid\":\"tfuser@pve!tfe-pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"e47e82d4-6798-47ea-9592-c7cf55cc8b61\"}"
    ]

I believe that this is a list, so I've tried extending the json_query as [].stdout[].value but that returns null. I've tried various permutations but so far nothing seems to work.

Any advice on how to proceed would be very welcome!


Solution

  • The items of the list stdout_lines are strings. You can test it. For example,

        - debug:
            var: output.0.stdout_lines.0|type_debug
    

    gives

      output.0.stdout_lines.0|type_debug: AnsibleUnsafeText
    

    Convert the items to dictionaries. For example

        - debug:
            var: output.0.stdout_lines.0|from_yaml
    

    gives

      output.0.stdout_lines.0|from_yaml:
        full-tokenid: user@pve!pve-apikey
        info:
          privsep: '0'
        value: dc2aa48f-daf6-4efe-b95e-83774a588988
    

    To get the UUID, declare the variable

        UUID: "{{ output|map(attribute='stdout_lines')|
                         map('map', 'from_yaml')|list|
                         json_query('[].value') }}"
    

    This gives the list of the values

      UUID:
      - dc2aa48f-daf6-4efe-b95e-83774a588988
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        output: "{{ lookup('file', 'output.json') }}"
        UUID: "{{ output|map(attribute='stdout_lines')|
                         map('map', 'from_yaml')|list|
                         json_query('[].value') }}"
    
      tasks:
    
        - debug:
            var: output.0.stdout_lines.0|type_debug
        - debug:
            var: output.0.stdout_lines.0|from_yaml
        - debug:
            var: UUID