JavaAllDay
JavaAllDay

Reputation: 63

query key from complex json by combining dict2items and JMESPath with ansible

I'm looking to return value based on query result, so far I'm not getting the desired result. json looks like this and is coming from ansible var

{
  "header": {
    "nodes": {
        "node1": {
            "last_shutdown": "date",
            "level": {
                "kind_node": {}
            },
            "state": {
                "running": "true",
                "more": {
                    "type": "admin"
            }
        }
    },
        "node2": {
            "last_shutdown": "date",
            "level": {
                "kind_node": {}
            },
            "state": {
                "running": "true",
                "more": {
                    "type": "engine"
            }
        }
    },
        "node3": {
            "last_shutdown": "date",
            "level": {
                "kind_node": {}
            },
            "state": {
                "running": "true",
                "more": {
                    "type": "engine"
            }
        }
      }
    }
  }
}
  

So far I've tried to use dict2items but no luck. Currently, I'm getting an empty list.

     set_fact:
       my_var: "{{ nodes | dict2items | json_query('[?value.state.more.type==`admin`]') }}"

Basically, this task should set my_var ==> node1 since it's the admin. Any help is greatly appreciated.

Upvotes: 3

Views: 559

Answers (1)

Zeitounator
Zeitounator

Reputation: 44799

You don't need json_query for this. It would work but I strongly suggest you use it only when default core ansible filters cannot do the job at all.

Moreover, your jmespath expression (which I did not test to validate) would return a full list of elements where the parameter is matched, not simply a node name.

In a nutshell (note: updated so that it will work even if some element do not contain the more attribute inside the state key)

- set_fact:
    my_var: >-
      {{
        nodes 
        | dict2items
        | selectattr('value.state.more', 'defined')
        | selectattr('value.state.more.type', '==', 'admin')
        | map(attribute='key')
        | first
      }}

In other words:

  1. transform dict to a list or key/value pairs
  2. select only elements having value.state.more defined
  3. select only elements having "admin" in the value.state.more.type parameter
  4. extract only the key parameter for each element
  5. get the first element in the list

Upvotes: 2

Related Questions