Score:1

json_query help - not producing expected output

cn flag

I am trying to build an array to use for with_nested, but I cannot get past why json_query isn't outputting the actual hosts assigned to each cluster:

Play:

- name: Index clusters.json
  shell: cat {{ tower_var_path }}/clusters.json
  register: result_clusters

- name: Save the Json data to a Variable as a Fact
  set_fact: 
    clusters_jsondata: "{{ result_clusters.stdout | from_json }}"

- debug:
    msg: " {{ clusters_jsondata }}"

- name: Set cluster facts
  set_fact:
    cluster: "{{ cluster|default([]) + [ {
      'name': item,
      'hosts': item | json_query('*.hosts[*].name')
       } ] }}"  
  with_items: "{{ clusters_jsondata.clusters }}"      

- debug: 
    msg: "{{ cluster }}"

clusters.json data:

    {
    "clusters": {
        "Cluster_1": {
            "hosts": [
                {
                    "folder": "/path",
                    "name": "host1.domain.com"
                },
                {
                    "folder": "/path",
                    "name": "host2.domain.com"
                }
            ],

        },
        "Cluster_2": {
            "hosts": [
                {
                    "folder": "/path",
                    "name": "host3.domain.com"
                },
                {
                    "folder": "/path",
                    "name": "host4.domain.com"
                }
            ],

        },
    }

Expected results:

TASK [debug] *********************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "hosts": "host1.domain.com, host2.domain.com",
            "name": "Cluster_1"
        },
        {
            "hosts": "host3.domain.com, host4.domain.com",
            "name": "Cluster_2"
        }
    ]
}

Actual results:

    TASK [debug] *********************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "hosts": null,
            "name": "Cluster_1"
        },
        {
            "hosts": null,
            "name": "Cluster_2"
        }
    ]
}
Score:2
fr flag

In a nutshell, you can get your result with a single expression without any loops.

The following playbook:

---
- hosts: localhost
  gather_facts: false

  vars:
    # Your original data on a single line for legibility
    result_clusters:
      stdout: >-
        {"clusters":{"Cluster_1":{"hosts":[{"folder":"/path","name":"host1.domain.com"},{"folder":"/path","name":"host2.domain.com"}]},"Cluster_2":{"hosts":[{"folder":"/path","name":"host3.domain.com"},{"folder":"/path","name":"host4.domain.com"}]}}}

  tasks:
    - name: get my expected output from json data in a single task
      vars:
        query: >-
          [].{name: key, hosts: join(', ', value.hosts[].name)}
        clusters: "{{ (result_clusters.stdout | from_json).clusters }}"
      debug:
        msg: "{{ clusters | dict2items | json_query(query) }}"

Gives:

PLAY [localhost] ******************************************************

TASK [get my expected output from json data in a single task] *********
ok: [localhost] => {
    "msg": [
        {
            "hosts": "host1.domain.com, host2.domain.com",
            "name": "Cluster_1"
        },
        {
            "hosts": "host3.domain.com, host4.domain.com",
            "name": "Cluster_2"
        }
    ]
}

PLAY RECAP ************************************************************
localhost: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Note: although the above gives very precisely the output you asked for, I strongly suspect you are looking for a result slightly different. Replacing the above query with:

        query: >-
          [].{name: key, hosts: value.hosts[].name}

will give this instead:

TASK [get my expected output from json data in a single task] **************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "hosts": [
                "host1.domain.com",
                "host2.domain.com"
            ],
            "name": "Cluster_1"
        },
        {
            "hosts": [
                "host3.domain.com",
                "host4.domain.com"
            ],
            "name": "Cluster_2"
        }
    ]
}

cn flag
Perfect! Thank you. Much different that what I was thinking, so would you be so kind to provide a link to a resource that might explain how you came to this approach?
Zeitounator avatar
fr flag
I can hardly find a link that points to a summary of my experience dealing with such issues over the past 8+ years ;) Meanwhile, three good starting points related to the subject: [jinja2 builtin filters](https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-builtin-filters), [ansilble filters](https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html) and [jmespath tutorial](https://jmespath.org/tutorial.html)
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.