3

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.

JavaAllDay
  • 53
  • 1
  • 5

1 Answers1

2

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
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
  • I got the following error, ```"VARIABLE IS NOT DEFINED!: 'dict object' has no attribute 'more'". by the way I've updated the json right before you responded. – JavaAllDay Jul 05 '21 at 09:19
  • 1
    https://gist.github.com/zeitounator/b9479f40b41814af8d963f68138fcc0a – Zeitounator Jul 05 '21 at 13:40
  • The above error was encountered if element tree doe not contain `more`. Otherwise the provided solution works. – JavaAllDay Jul 05 '21 at 15:33
  • 2
    This is not a situation you have described. You have to be specific by providing a relevant data set. I updated the solution so that it will work in this case. – Zeitounator Jul 05 '21 at 17:16
  • correct, I missed that use case. I was able to filter some more and handle other cases with your updated solution. Appreciate your help on this. all set. – JavaAllDay Jul 05 '21 at 19:22