Below is my sample JSON file.
[
{
"?xml": {
"attributes": {
"encoding": "UTF-8",
"version": "1.0"
}
}
},
{
"domain": [
{
"server": [
{
"name": "myserv1"
},
{
"ssl": {
"name": "myserv1"
}
},
{
"log": [
{
"name": "myserv1"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
]
}
]
},
{
"server": [
{
"name": "myserv2"
},
{
"ssl": {
"name": "myserv2"
}
},
{
"log": [
{
"name": "myserv2"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
]
}
]
}
]
}
]
My requirement is to read the json file and store the value in a file like below:
myserv1_log: "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
myserv2_log: "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
i.e
<server>_log: <file-name>
Here is my Ansible play that uses JMESPath query to read the json data.
- name: Server Names and log details
set_fact:
serverlog: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: '[].domain[].server[*].log[*].[name, "file-name"]'
- name: Print all server names with log details
debug:
msg: "{{ item }}"
with_items:
- "{{ serverlog }}"
As you can see I get several null
values in the output
output:
TASK [Print all server names with log details] *********************************
Wednesday 02 March 2022 03:17:45 -0600 (0:00:00.100) 0:00:04.730 *******
ok: [localhost] => (item=[]) => {
"msg": []
}
ok: [localhost] => (item=[[['myserv1', None], [None, '/web/bea_logs/domains/mydom/myserv1/myserv1.log']]]) => {
"msg": [
[
[
"myserv1",
null
],
[
null,
"/web/bea_logs/domains/mydom/myserv1/myserv1.log"
]
]
]
}
I tied to get rid of the null
using the below but that too does not get me the desired output:
- name: test
set_fact:
list2: "{{list2 [item]}}"
when: item != "null"
with_items:
- "{{serverlog}}"
- name: Neww Print all server names with log details
debug:
msg: "{{ item }}"
with_items:
- "{{ list3 }}"
I also tried the solution proposed on StackOverflow but I get error:
"{{ jsondata | selectattr('domain', 'defined') | map(attribute='domain') | flatten | map(attribute='server') | flatten | selectattr('log', 'defined') | map(attribute='log') | map('combine') }}"
Output error:
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'server'\n\nThe error appears to be in....
Any earlier similar post did not get any working solution is why I decided to post here:
remove null elements from list ansible
Kindly suggest.
CodePudding user response:
the structure of your json is always the same no need to use jmepath:
- hosts: localhost
gather_facts: no
vars:
json: "{{ lookup('file', './file.json') | from_json }}"
tasks:
- name: display
debug:
msg: "name: {{ servername }} --> filename: {{ filename }}"
loop: "{{ json[1].domain }}"
vars:
servername: "{{ item.server.0.name }}_log"
filename: "{{ item['server'][2]['log'][1]['file-name'] }}"
result:
ok: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': {'name': 'myserv1'}}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]}) => {
"msg": "name: myserv1_log --> filename: /web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
ok: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]}) => {
"msg": "name: myserv2_log --> filename: /web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
some explanations:
json is an array with 2 records one with key ?xml
the other with key domain
domain
is an array with key server
server
is an array witk the differents keys name, ssl and log
log
is an array with differents keys name and file-name
json[1].domain
just keeps the part containing domain, json[0] contains the header of json
item.server.0.name (= item['server'][0]['name'])
is the first item of record server which contains the key name
item['server'][2]['log'][1]['file-name']
is the third item for a record server which contains the key log
and the second item of log contains the key file-name