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.
servermay not always be the 3rd key ofdomainarray.logarray may not alway be a key for allserverarrays and thus should not be printed. For example.servername AdminServer does not have anyloglist 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)) }}"
