1

I am trying to query the following Infoblox data with Ansible and JMESPath json_query:

{
    "ip_records.json": {
        "result": [
            {
                "_ref": "fixedaddress/blabla",
                "ipv4addr": "10.10.10.10",
                "network_view": "Bla"
            },
            {
                "_ref": "record:host/blabla",
                "ipv4addrs": [
                    {
                        "_ref": "record:host_ipv4addr/blabla",
                        "host": "bla.bla.com",
                        "ipv4addr": "10.10.10.10"
                    }
                ],
                "name": "bla.bla.com",
                "view": " "
            },
            {
                "_ref": "record:a/blabla",
                "ipv4addr": "10.10.10.10",
                "name": "bla.bla.com",
                "view": "bla"
            }
        ]
    }
}

I want to get only the _ref value for the item with fixedaddress in the _ref value.

Forgot to add that there might also be multiple records with fixedaddress but different IP's. So I also want to filter on a specific IP as the same time.

I have created queries to filter

  • only on IP address given as input
  • the string fixedaddress
  • a combination of both

The first two work as expected. But, I want to combine both conditions and would expect to get the single item as output, but I get nothing. I tried using && and | to combine both, as showed below.

- name: "Search IP Record: Task 2.2: Filter Results."
  vars:
    jmesquery: "[] | [?ipv4addr==`{{ infoblox_ip }}`]._ref"
  set_fact:
    ip_records_refs: "{{ ip_records.json.result | json_query(jmesquery) }}"

- name: "Search IP Record: Task 2.4: Filter Results."
  vars:
    jmesquery: "[] | [?_ref.contains(@,`fixedaddress`)]._ref"
  set_fact:
    ip_records_refs: "{{ ip_records.json.result | to_json | from_json | json_query(jmesquery) }}"

- name: "Search IP Record: Task 2.6: Filter Results."
  vars:
    # jmesquery: "[] | ([?ipv4addr==`{{ infoblox_ip }}` && _ref.contains(@,`fixedaddress`)])._ref"
    jmesquery: "[] | [?ipv4addr==`{{ infoblox_ip }}`].ref | [?_ref.contains(@,`fixedaddress`)]._ref"
  set_fact:
    ip_records_refs: "{{ ip_records.json.result | to_json | from_json | json_query(jmesquery) }}"

Output:

TASK [Search IP Record: Task 2.3 Dump variable Content] ***********
ok: [localhost] => {
    "ip_records_refs": [
        "fixedaddress/blabla",
        "record:a/blabla"
    ]
}

TASK [Search IP Record: Task 2.5 Dump variable Content] ***********
ok: [localhost] => {
    "ip_records_refs": [
        "fixedaddress/blabla"
    ]
}

TASK [Search IP Record: Task 2.7 Dump variable Content] ***********
ok: [localhost] => {
    "ip_records_refs": []
}
Marc
  • 41
  • 4

2 Answers2

1

You are misusing the pipe expression.

From your trial, it is hard to tell exactly what you think it does, but here is a simple explanation: you might not see it, but a JMESPath filter on an array does not return you a JSON array, rather it returns you a projection.
You cannot chain a filter on top of projection, you need to reset it first, in order to get the resulting JSON array, and this is what the pipe expression is meant for.

In your case, you do not want to have a filter on top of a projection, you want a filter with multiple conditions, so, your last set_fact query should read:

jmesquery: >-
  [?
    _ref.contains(@,`fixedaddress`) 
    && ipv4addr == `{{ infoblox_ip }}`
  ]._ref

And your two first queries should be simplified to:

jmesquery: "[?_ref.contains(@,`fixedaddress`)]._ref"

and

jmesquery: "[?ipv4addr == `{{ infoblox_ip }}`]._ref"
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • I will test this on Monday. Am away for now. Another question: can you suggest any good sites with extensive tutorials regarding (complicated) JMESPath queries? It seems I can only find simple ones that only touch the surface of these queries. – Marc Dec 01 '22 at 07:48
  • Well, you have everything on [their website](https://jmespath.org/specification.html): tutorial, simple examples and then the specifications to dig further. – β.εηοιτ.βε Dec 01 '22 at 18:34
0

Q: "Get _ref value for the item with 'fixedaddress' in the _ref key."

A: The query below

  jmesquery: "[?_ref.contains(@,`fixedaddress`)]._ref"
  ip_records_refs: "{{ ip_records.json.result|json_query(jmesquery) }}"

gives the expected result

  ip_records_refs:
  - fixedaddress/blabla

Example of a complete playbook for testing

- hosts: localhost

  vars:

    ip_records:
      json:
        result:
        - _ref: fixedaddress/blabla
          ipv4addr: 10.10.10.10
          network_view: Bla
        - _ref: record:host/blabla
          ipv4addrs:
          - _ref: record:host_ipv4addr/blabla
            host: bla.bla.com
            ipv4addr: 10.10.10.10
          name: bla.bla.com
          view: ' '
        - _ref: record:a/blabla
          ipv4addr: 10.10.10.10
          name: bla.bla.com
          view: bla

    # Get _ref value for the item with 'fixedaddress' in the _ref key
    jmesquery: "[?_ref.contains(@,`fixedaddress`)]._ref"
    ip_records_refs: "{{ ip_records.json.result|json_query(jmesquery) }}"
    
  tasks:

    - debug:
        var: ip_records
    - debug:
        var: ip_records_refs
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • I forgot to include additional info regarding filtering also on IP. Modified my post above. – Marc Dec 01 '22 at 07:44