Home > Mobile >  How to make a specific dict in Ansible from json output
How to make a specific dict in Ansible from json output

Time:11-10

I have an Ansible job that run on 2 or more urls. Each url returns the same variables with different values. Here is the JSON data registry of the job:

{
  "msg": {
    "results": [
      {
        "url": "http://0.0.0.1:xxx1",
        "othervar": "othervar",
        "othervar2": "othervar2",
        "json": {
          "messages": [
            {
              "message": "This is message number 1",
              "message2": "This is message2 number 1"
            },
            {
                "message": "This is message number 2",
                "message2": "This is message2 number 2"
            },
            {
                "message": "This is message number 3",
                "message2": "This is message2 number 3"
            }
          ]
        }
      },
      {
        "url": "http://0.0.0.2:xxx2",
        "othervar": "othervar",
        "othervar2": "othervar2",
        "json": {
          "messages": [
            {
              "message": "This is message number 1",
              "message2": "This is message2 number 1"
            },
            {
                "message": "This is message number 2",
                "message2": "This is message2 number 2"
            },
            {
                "message": "This is message number 3",
                "message2": "This is message2 number 3"
            }
          ]
        }
      }
    ]
  }
}

I want to make a specific dict containing only the url variable and also message and message2 variables. I have 2 options for my expected results:

option 1:

"message": [
    {
      "url": "http://0.0.0.1:xxx1",
      "content": [
          {
            "message": "This is message number 1",
            "message2": "This is message2 number 1"
          },
          {
              "message": "This is message number 2",
              "message2": "This is message2 number 2"
          },
          {
              "message": "This is message number 3",
              "message2": "This is message2 number 3"
          }
        ]
    },
    {
        "url": "http://0.0.0.2:xxx2",
        "content": [
            {
              "message": "This is message number 1",
              "message2": "This is message2 number 1"
            },
            {
                "message": "This is message number 2",
                "message2": "This is message2 number 2"
            },
            {
                "message": "This is message number 3",
                "message2": "This is message2 number 3"
            }
          ]
      }

option 2:

"message": [
  {
    "url": "http://0.0.0.0:xxx1",
    "message": "This is message number 1",
    "message2": "This is message2 number 1"
  },
  {
    "url": "http://0.0.0.0:xxx1",
    "message": "This is message number 2",
    "message2": "This is message2 number 2"
  },
  {
    "url": "http://0.0.0.0:xxx1",
    "message": "This is message number 2",
    "message2": "This is message2 number 2"
  },
  {
    "url": "http://0.0.0.0:xxx2",
    "message": "This is message number 1",
    "message2": "This is message2 number 1"
  },
  {
    "url": "http://0.0.0.0:xxx2",
    "message": "This is message number 2",
    "message2": "This is message2 number 2"
  },
  {
    "url": "http://0.0.0.0:xxx2",
    "message": "This is message number 2",
    "message2": "This is message2 number 2"
  }
]

I am able to get each variable (url only, message only, message2 only) but how can i merge them into a dict like option 1 or option 2?

CodePudding user response:

The easiest way is to start with option 1 which is the closest from your original data. You can for example declare it as var in your play:

    my_results: "{{ results | json_query('[].{\"url\": url, \"content\": json.     messages}') }}"

Note that json_query requires the community.general collection (usually available if you installed the ansible meta package) and pip install jmespath

This gives (debuging the above variable):

TASK [debug] *******************************************************************
ok: [localhost] => {
    "my_results": [
        {
            "content": [
                {
                    "message": "This is message number 1",
                    "message2": "This is message2 number 1"
                },
                {
                    "message": "This is message number 2",
                    "message2": "This is message2 number 2"
                },
                {
                    "message": "This is message number 3",
                    "message2": "This is message2 number 3"
                }
            ],
            "url": "http://0.0.0.1:xxx1"
        },
        {
            "content": [
                {
                    "message": "This is message number 1",
                    "message2": "This is message2 number 1"
                },
                {
                    "message": "This is message number 2",
                    "message2": "This is message2 number 2"
                },
                {
                    "message": "This is message number 3",
                    "message2": "This is message2 number 3"
                }
            ],
            "url": "http://0.0.0.2:xxx2"
        }
    ]
}

From there, If you need to loop on structure which looks like you option 2, it's very easy to acheive using the subelements lookup:

    - name: loop on a structure looking like option 2
      debug:
        msg:
          - "url is {{ item.0.url }}"
          - "message one is {{ item.1.message }}"
          - "message two is {{ item.1.message2 }}"
      loop: "{{ q('subelements', my_results, 'content') }}"
      loop_control:
        label: "{{ item.0.url }}"

which gives:

TASK [loop on a structure looking like option 2] *******************************
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.1:xxx1",
        "message one is This is message number 1",
        "message two is This is message2 number 1"
    ]
}
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.1:xxx1",
        "message one is This is message number 2",
        "message two is This is message2 number 2"
    ]
}
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.1:xxx1",
        "message one is This is message number 3",
        "message two is This is message2 number 3"
    ]
}
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.2:xxx2",
        "message one is This is message number 1",
        "message two is This is message2 number 1"
    ]
}
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.2:xxx2",
        "message one is This is message number 2",
        "message two is This is message2 number 2"
    ]
}
ok: [localhost] => (item=item.0.url) => {
    "msg": [
        "url is http://0.0.0.2:xxx2",
        "message one is This is message number 3",
        "message two is This is message2 number 3"
    ]
}

Here is a playbook for a full test:

---
- hosts: localhost
  gather_facts: false

  vars:
    # Your orig data minified
    results: [{"url":"http://0.0.0.1:xxx1","othervar":"othervar","othervar2":"othervar2","json":{"messages":[{"message":"This is message number 1","message2":"This is message2 number 1"},{"message":"This is message number 2","message2":"This is message2 number 2"},{"message":"This is message number 3","message2":"This is message2 number 3"}]}},{"url":"http://0.0.0.2:xxx2","othervar":"othervar","othervar2":"othervar2","json":{"messages":[{"message":"This is message number 1","message2":"This is message2 number 1"},{"message":"This is message number 2","message2":"This is message2 number 2"},{"message":"This is message number 3","message2":"This is message2 number 3"}]}}]

    my_results: "{{ results | json_query('[].{\"url\": url, \"content\": json.messages}') }}"

  tasks:
    - name: debug my_results var to check
      debug:
        var: my_results

    - name: loop on a structure looking like option 2
      debug:
        msg:
          - "url is {{ item.0.url }}"
          - "message one is {{ item.1.message }}"
          - "message two is {{ item.1.message2 }}"
      loop: "{{ q('subelements', my_results, 'content') }}"
      loop_control:
        label: item.0.url

CodePudding user response:

The following code loads your input json, then creates a new array with the structure you ask in option 1, by creating new items while iterating on your messages list:

---
- name: Playbook for infinispan Hosts
  hosts: localhost
  tasks:
    - name: load json from file
      shell: cat test.json
      register: result
    - name: save the input json data to a variable
      set_fact:
        jsondata: "{{ result.stdout | from_json }}"
    - name: display the input dict
      debug:
        var: jsondata
    - name: parse the json into new array
      set_fact:
        message: "{{ message|default([])   [ { 'url': item.url, 'content': item.json.messages }  ] }}"
      loop: "{{ jsondata.msg.results }}"
    - name: display the resulting data structure
      debug:
        var: message
  • Related