skip to Main Content

I’m having trouble with a jquery statement in Ansible. My host name has "-" in its name which I need to specify to bring back the results I need. I have tried various ways to escape the "-" but with no joy. As it stands below is my current task:

- name: Query with hyphen
     debug:
      msg: "{{ results.json.list | json_query(querystr) }}"
     vars:
        querystr: "[?hostname=={{ host }}].{hostname: hostname, status: status}"
        host: '["server-bbbv-14"]'

I get no error but this is the result I receive:

"msg": []

Here is my json result I’m querying:

"json": {
    "list": [
            {
                "status": "1",
                "hostname": "server-bbbv-10"
            },
            {
                "status": "3",
                "hostname": "server-bbbv-14"
            },
            {
                "status": "3",
                "hostname": "server-bbbv-17"
            },
            {
                "status": "1",
                "hostname": "server-bbbv-11"
            }
      [
}

I have also tried ‘"server-bbbv-14"’ which give me the same output.

I tried "server-bbbv-14" and ‘server-bbbv-14’ and got below error:

"msg": "Error in jmespath.search in json_query filter plugin:ninvalid literal for int() with base 10: '-'"

I tried [‘server-bbbv-14’] and recevied:

"msg": "Error in jmespath.search in json_query filter plugin:n'literal'"

For sanity I tried searching on the status and it works as expected bringing back results that match the given status I put in.

Please note, the vars of host is actually going to be the built in Ansible variable inventory_hostname but as that did not work I have tried setting this manually to get it working first.

Please help.

2

Answers


  1. Below is the correct query

        - debug:
            msg: "{{ results.json.list | json_query(querystr) }}"
          vars:
            host: server-bbbv-14
            querystr: '[?hostname==`{{ host }}`].{hostname: hostname, status: status}'
    

    gives

      msg:
      - hostname: server-bbbv-14
        status: '3'
    

    Note: It’s not necessary to use json_query. You can use selectattr instead. The below expression gives the same result

        - debug:
            msg: "{{ results.json.list | selectattr('hostname', '==', host) }}"
          vars:
            host: server-bbbv-14
    


    A simpler solution would be to create a dictionary first

      hostname_status: "{{ results.json.list|
                           items2dict(key_name='hostname', value_name='status') }}"
    

    gives

      hostname_status:
        server-bbbv-10: '1'
        server-bbbv-11: '1'
        server-bbbv-14: '3'
        server-bbbv-17: '3'
    

    This makes the above query trivial.


    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        results:
          json:
            list:
              - {hostname: server-bbbv-10, status: '1'}
              - {hostname: server-bbbv-14, status: '3'}
              - {hostname: server-bbbv-17, status: '3'}
              - {hostname: server-bbbv-11, status: '1'}
    
        hostname_status: "{{ results.json.list|
                             items2dict(key_name='hostname', value_name='status') }}"
    
      tasks:
    
        - debug:
            msg: "{{ results.json.list | json_query(querystr) }}"
          vars:
            host: server-bbbv-14
            querystr: '[?hostname==`{{ host }}`].{hostname: hostname, status: status}'
    
        - debug:
            var: hostname_status
    

    Login or Signup to reply.
  2. There is no need to escape hyphens. Your jmespath query is incorrect. Moreover, using jmespath here is not really the best option. In a nutshell, the following playbook.yml meets your expectations:

    ---
    - hosts: localhost
      gather_facts: false
    
      vars:
        results:
          json:
            list:
              - status: "1"
                hostname: "server-bbbv-10"
              - status: "3"
                hostname: "server-bbbv-14"
              - status: "3"
                hostname: "server-bbbv-17"
              - status: "1"
                hostname: "server-bbbv-11"
    
        search_hostname: "server-bbbv-14"
    
      tasks:
    
        - name: Get the result with json_query
          vars:
            # Warning: single quotes matter here, see jmespath spec
            # https://jmespath.org/specification.html#raw-string-literals
            query_string: "[?hostname=='{{ search_hostname }}']"
          ansible.builtin.debug:
            msg: "{{ results.json.list | json_query(query_string) }}"
    
        - name: Alternative syntax for json_query raw string
          vars:
            query_string: "[?hostname==`{{ search_hostname }}`]"
          ansible.builtin.debug:
            msg: "{{ results.json.list | json_query(query_string) }}"
    
        - name: Get the same result with stock ansible filters
          ansible.builtin.debug:
            msg: "{{ results.json.list | selectattr('hostname', '==', search_hostname) }}"
    

    Running that playbook with the task profiler shows both method return the same result and that using the stock filters in this specific case is twice as fast on my machine

    $ ANSIBLE_CALLBACKS_ENABLED=profile_tasks ansible-playbook playbook.yml 
    
    PLAY [localhost] ***************************************************************
    
    TASK [Get the result with json_query] ******************************************
    Friday 25 August 2023  12:38:27 +0200 (0:00:00.010)       0:00:00.010 ********* 
    ok: [localhost] => {
        "msg": [
            {
                "hostname": "server-bbbv-14",
                "status": "3"
            }
        ]
    }
    
    TASK [Alternative syntax for json_query raw string] ****************************
    Friday 25 August 2023  12:38:27 +0200 (0:00:00.056)       0:00:00.066 ********* 
    ok: [localhost] => {
        "msg": [
            {
                "hostname": "server-bbbv-14",
                "status": "3"
            }
        ]
    }
    
    TASK [Get the same result with stock ansible filters] **************************
    Friday 25 August 2023  12:38:27 +0200 (0:00:00.055)       0:00:00.122 ********* 
    ok: [localhost] => {
        "msg": [
            {
                "hostname": "server-bbbv-14",
                "status": "3"
            }
        ]
    }
    
    PLAY RECAP *********************************************************************
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    Friday 25 August 2023  12:38:27 +0200 (0:00:00.034)       0:00:00.156 ********* 
    =============================================================================== 
    Get the result with json_query ------------------------------------------ 0.06s
    Alternative syntax for json_query raw string ---------------------------- 0.06s
    Get the same result with stock ansible filters -------------------------- 0.03s
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search