Clayton Louden
Clayton Louden

Reputation: 1076

Ansible: Selecting a nested value with json_query

I'm trying to verify a couple of service endpoints via a REST API and ansbile's uri module

    - name: Wait until service is fully deployed
      local_action:
        module: uri
        url: http://somerestserver/{{ app_name }}-{{ item }}/tasks
        methon: GET
      register: response
      loop: "{{ range(0, instances) | list }}"

The response varialbe looks something like this:

"response": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                "item": 0,
                "json": {
                    "tasks": [
                        {
                            "appId": "node-0",
                            "healthCheckResults": [
                                {
                                    "alive": true,
                                    ...
                                }
                            ],
                            ...
                        }
                    ]
                },
                "msg": "OK (674 bytes)",
            },
            {
                "item": 1,
                "json": {
                    "tasks": [
                        {
                            "appId": "node-1",
                            "healthCheckResults": [
                                {
                                    "alive": true,
                                    ...
                                }
                            ],
                        }
                    ]
                },
                "msg": "OK (674 bytes)",
            },
            {
                "item": 2,
                "json": {
                    "tasks": [
                        {
                            "appId": "node-2",
                            "healthCheckResults": [
                                {
                                    "alive": true,
                                    ...
                                }
                            ],
                        }
                    ]
                },
                "msg": "OK (674 bytes)",
            }
        ]
    }

What I'd like to do now is to wait until all my services report alive: true

    - name: Wait until service is fully deployed
      local_action:
        module: uri
        url: http://somerestserver/{{ app_name }}-{{ item }}/tasks
        methon: GET
      register: response
      loop: "{{ range(0, instances) | list }}"
      until: <All services report alive>

Is there an easy way to do this? I tried

until: response | json_query('results[*].json.tasks[*].healthCheckResults[*].alive') == [true]*instances

which unfortunately doesn't work

Upvotes: 1

Views: 2736

Answers (1)

larsks
larsks

Reputation: 311606

So, today I learned that can combine loop and until on a single task, which was a surprise. So that's cool.

In any case, you are so close to a solution. Given your input data, your query will result in something like:

[
  [
    [
      true
    ]
  ],
  [
    [
      true
    ]
  ],
  [
    [
      true
    ]
  ]
]

That's never going to match the [true, true, true] list to which you're comparing it. You just need to apply a couple jmespath flatten operators, like this:

results[*].json.tasks[*].healthCheckResults[*].alive[][]

Given you sample input, that results in:

[true, true, true]

In your playbook, that would be:

- name: Wait until service is fully deployed
  local_action:
    module: uri
    url: http://somerestserver/{{ app_name }}-{{ item }}/tasks
    methon: GET
  register: response
  loop: "{{ range(0, instances) | list }}"
  until: response|json_query('results[*].json.tasks[*].healthCheckResults[*].alive[][]') == [true]*instances

In the future, you can try out your queries by pasting your data into the text box at http://jmespath.org/ and then typing your queries above it.

Upvotes: 2

Related Questions