Search code examples
jsonansiblejmespathjson-query

how to get json_query display property name in ansible playbook


I have this json block as an example:

"msg": {
        "10.10.28.10": {
            "core": 23,
            "cpuCoreUsage": 0.0,
            "cputhreshold": 80,
            "status": "healthy",
            "status_code": 0,
            "status_reason": "Checks passed",
            "timestamp": 1614281443,
            "total": 0
        },
        "10.10.28.5": {
            "core": 18,
            "cpuCoreUsage": 2.0,
            "cputhreshold": 80,
            "status": "healthy",
            "status_code": 0,
            "status_reason": "Checks passed",
            "timestamp": 1614281443,
            "total": 0
        },
        "capacity": 1080
}

I'm trying to figure out how I can get this output with property name and status to look like something like this.

DESIRED OUTPUT:
IP: 10.10.28.5, status: healthy, status_code: 0
IP: 10.10.28.10, status: healthy, status_code: 0

I can print everything except the IP part with this:

  - name: STATUS QUERY
    debug:
      msg: "code: {{ item }}"
    loop: "{{ data.json | json_query(status_code_query) | list }}"
    vars:
            status_code_query: "*.{statuscode: status_code, status: status}"

Solution

  • I wouldn't use JMESPath for this, the reason is, although it is pretty good at querying JSON, it is not really good at displaying JSON keys.

    The keys() function is the closest you can find there, but it will yield you an array and since you cannot come back to a parent node you cannot do something like:

    *.{IP: keys($)[0], statuscode: status_code, status: status}
    

    Although this is a pretty frequently requested feature: https://github.com/jmespath/jmespath.js/issues/22


    Now to solve your use case, you can use the keys() function, but the one of Python.

    You also have a issue in the fact that all your values of data.json are not dictionaries: in "capacity": 1080, the value is a simple int.

    You can go work around this odd data structure using a when test and verify if you value is indeed a mapping (or in other words a dictionary).

    Given the playbook:

    - hosts: all
      gather_facts: yes
    
      tasks:
        - debug: 
            msg: >-
              IP: {{ item }}, 
              status: {{ data.json[item].status }}, 
              status_code: {{ data.json[item].status_code }}
          loop: "{{ data.json.keys() }}"
          when: data.json[item] is mapping
          vars:
            data:
              json:
                10.10.28.10:
                  core: 23
                  cpuCoreUsage: 0
                  cputhreshold: 80
                  status: healthy
                  status_code: 0
                  status_reason: Checks passed
                  timestamp: 1614281443
                  total: 0
                10.10.28.5:
                  core: 18
                  cpuCoreUsage: 2
                  cputhreshold: 80
                  status: healthy-
                  status_code: 0-
                  status_reason: Checks passed
                  timestamp: 1614281443
                  total: 0
                capacity: 1080
    

    This yields the recap:

    PLAY [all] **********************************************************************************************************
    
    TASK [Gathering Facts] **********************************************************************************************
    ok: [localhost]
    
    TASK [debug] ********************************************************************************************************
    ok: [localhost] => (item=10.10.28.10) => {
        "msg": "IP: 10.10.28.10,  status: healthy,  status_code: 0"
    }
    ok: [localhost] => (item=10.10.28.5) => {
        "msg": "IP: 10.10.28.5,  status: healthy-,  status_code: 0-"
    }
    skipping: [localhost] => (item=capacity) 
    
    PLAY RECAP **********************************************************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    This said, it is also a perfect use case for the dict2items filter:

    - hosts: all
      gather_facts: yes
    
      tasks:
        - debug: 
            msg: >-
              IP: {{ item.key }}, 
              status: {{ item.value.status }}, 
              status_code: {{ item.value.status_code }}
          loop: "{{ data.json | dict2items }}"
          when: item.value is mapping
          vars:
            data:
              json:
                10.10.28.10:
                  core: 23
                  cpuCoreUsage: 0
                  cputhreshold: 80
                  status: healthy
                  status_code: 0
                  status_reason: Checks passed
                  timestamp: 1614281443
                  total: 0
                10.10.28.5:
                  core: 18
                  cpuCoreUsage: 2
                  cputhreshold: 80
                  status: healthy-
                  status_code: 0-
                  status_reason: Checks passed
                  timestamp: 1614281443
                  total: 0
                capacity: 1080
    

    Would yield the same recap.