Search code examples
jsonansiblejmespathjson-query

Check for objects in JSON other than the one mentioned in a condition


I need to check if there are exit codes other than 0 in the JSON file below.

{
    "domains": {
        "app1": {
            "status": "Running"
        },
        "app2": {
            "status": "Terminated",
            "exit code": 2
        },
        "app3": {
            "status": "Running"
        },
        "app4": {
            "status": "Running"
        },
        "app5": {
            "status": "Terminated",
            "exit code": 0
        }
    }
}

Upon finding exit code other than 0, I want the Ansible task to fail. I tried the following code:

- name: Execute command to obtain json list.
  command: cat test.json
  register: result

- name: save the Json data to a Variable as a Fact
  set_fact:
     jsondata: "{{ result.stdout | from_json }}"

- name: Find string
  when: jsondata.stdout is search('Terminated')
  debug:
     msg: "{{ jsondata.stdout }}"
  failed_when: "{{ jsondata.stdout | jsonquery(domains.*[exit code] != 0) }}"

But, this does not seem to work.


Solution

  • You do have multiple issues in your failing condition:

    1. when and its *_when derivates should never be templated — so you should get rid of the expressions delimiters {{ ... }}
    2. you are using a property stdout on your jsondata fact, that does not have one
    3. the filter name is json_query, not jsonquery
    4. you have to quote your JMESPath query passed to the filter: json_query('my_query_here_quoted')
    5. because you are doing a projection, using .*, you have to reset it in order to make a subsequent filter projection: domains.* | [?my_condition]
    6. because your array key contains a space you have to double quote it: [?"exit code"]
    7. because your condition is an integer you have to put it inside backticks. Also, your condition have to go inside the brackets, and start with a question mark: [?"exit code" == `0`]
    8. to get rid of the elements that do not have an exit code at all, a simpler solution would be to do a greater than: [?"exit code" > `0`]
    9. There is a fail task, it is maybe better suited in your case than a debug with a failed_when

    With all this, you should end with the task:

    - name: Fail when we have an abnormal exit status
      fail:
        msg: |-
          Some process have an abnormal exit:
          {{ _abnormal_exit }}  
      when: _abnormal_exit | length > 0
      vars:
        _abnormal_exit: >-
          {{
            jsondata | json_query('domains.* | [?"exit code" > `0`]')
          }}
    

    Given the two tasks:

    - name: Get content of test.json
      command: cat test.json
      register: result
    
    - name: Fail when we have an abnormal exit status
      fail:
        msg: |-
          Some process have an abnormal exit:
          {{ _abnormal_exit }}  
      when: _abnormal_exit | length > 0
      vars:
        _abnormal_exit: >-
          {{
            result.stdout
            | from_json
            | json_query('domains.* | [?"exit code" > `0`]')
          }}
    

    It would yield:

    TASK [Get content of test.json] *****************************************
    changed: [localhost]
    
    TASK [Fail when we have an abnormal exit status] ************************
    fatal: [localhost]: FAILED! => changed=false 
      msg: |-
        Some process have an abnormal exit:
        [{'status': 'Terminated', 'exit code': 2}]