Below is my JSON file:
[
{
"?xml": {
"attributes": {
"encoding": "UTF-8",
"version": "1.0"
}
}
},
{
"domain": [
{
"name": "mydom"
},
{
"domain-version": "12.2.1.3.0"
},
{
"server": [
{
"name": "AdminServer"
},
{
"ssl": {
"name": "AdminServer"
}
},
{
"listen-port": "12400"
},
{
"listen-address": "mydom.host1.bank.com"
}
]
},
{
"server": [
{
"name": "myserv1"
},
{
"ssl": [
{
"name": "myserv1"
},
{
"login-timeout-millis": "25000"
}
]
},
{
"log": [
{
"name": "myserv1"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
]
}
]
},
{
"server": [
{
"name": "myserv2"
},
{
"ssl": {
"name": "myserv2"
}
},
{
"reverse-dns-allowed": "false"
},
{
"log": [
{
"name": "myserv2"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
]
}
]
}
]
}
]
I need to get log list's name
and file-name
like below using ansible code.
myserv1_log: "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
myserv2_log: "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
There are two challenges that i m facing.
server
may not always be the 3rd key ofdomain
array.log
array may not alway be a key for allserver
arrays and thus should not be printed. For example.server
name AdminServer does not have anylog
list while myserv1 & myserv2 do have.
I need an ansible code to print the desired for the dynamically changing json.
Note: server
will always be a key in the domain
array
I'm posting with reference to my similar query here: unable to ideally parse a json file in ansible
Kindly suggest.
CodePudding user response:
you just test if both keys exist:
- 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'] }}"
when: item.server is defined and item.server.2.log is defined
result:
TASK [display]
skipping: [localhost] => (item={'name': 'USWL1212MRSHM01'})
skipping: [localhost] => (item={'domain-version': '12.2.1.3.0'})
skipping: [localhost] => (item={'server': [{'name': 'AdminServer'}, {'ssl': {'name': 'AdminServer'}}, {'listen-port': '12400'}, {'listen-address': 'myhost1'}]})
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"
}
As you can see, when the condition is not true, the action is skipped...
you could simplify by testing only key log
, because in your case, keylog
is always linked to key server
when: item.server.2.log is defined
CodePudding user response:
Given the data
mydata:
- ?xml:
attributes:
encoding: UTF-8
version: '1.0'
- domain:
- name: USWL1212MRSHM01
- domain-version: 12.2.1.3.0
- server:
- name: AdminServer
- ssl:
name: AdminServer
- listen-port: '12400'
- listen-address: myhost1
- 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
Use json_query to select the attributes log
_logs: "{{ mydata|json_query(_query) }}"
_query: '[].domain[][].server[].log'
gives
_logs:
- - name: myserv1
- file-name: /web/bea_logs/domains/mydom/myserv1/myserv1.log
- - name: myserv2
- file-name: /web/bea_logs/domains/mydom/myserv2/myserv2.log
Next, combine the items and use items2dict to create the dictionary
logs_dict: "{{ _logs|map('combine')|list|
items2dict(key_name='name', value_name='file-name') }}"
gives the expected result
logs_dict:
myserv1: /web/bea_logs/domains/mydom/myserv1/myserv1.log
myserv2: /web/bea_logs/domains/mydom/myserv2/myserv2.log
Put the variables as appropriate, e.g.
- hosts: localhost
vars:
mydata: "{{ lookup('file', 'test-658-data.yml')|from_yaml }}"
_logs: "{{ mydata|json_query(_query) }}"
_query: '[].domain[][].server[].log'
logs_dict: "{{ _logs|map('combine')|list|
items2dict(key_name='name', value_name='file-name') }}"
tasks:
- debug:
var: logs_dict
Q: The name is not the name of the log but the name of the server
A: Generally, select keys and values, and combine the dictionary. The expressions below give the same result
mydata: "{{ lookup('file', 'test-658-data.yml')|from_yaml }}"
_logs: "{{ mydata|json_query(_query) }}"
_query: '[].domain[][].server'
_arr: "{{ _logs|map('combine')|
selectattr('name', 'defined')|
selectattr('log', 'defined') }}"
_names: "{{ _arr|map(attribute='name')|list }}"
_files: "{{ _arr|map(attribute='log.1.file-name')|list }}"
logs_dict: "{{ dict(_names|zip(_files)) }}"