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