I have this JSON output from Juniper switch where I need to get the remote system name associated with lldp_local_parent_interface_name
having the value ae0
.
So, I only know the value ae0
and I need to get the remote system name A_B_C_D
in order to start targeting this host to execute some other tasks.
The data, inside the file juniper-data.json looks like this:
{
"output": {
"lldp_neighbors_information": [{
"lldp_neighbor_information": [{
"lldp_local_parent_interface_name": [{
"data": "ae0"
}],
"lldp_local_port_id": [{
"data": "xe_0/2/0"
}],
"lldp_remote_chassis_id": [{
"data": "00:00:00:00:00:00:00"
}],
"lldp_remote_chassis_id_subtype": [{
"data": "Mac address"
}],
"lldp_remote_port_description": [{
"data": "xe_1/0/1"
}],
"lldp_remote_system_name": [{
"data": "A_B_C_D"
}]
},
{
"lldp_local_parent_interface_name": [{
"data": "_"
}],
"lldp_local_port_id": [{
"data": "ge_0/0/23"
}],
"lldp_remote_chassis_id": [{
"data": "xx:xx:xx:xx:xx:xx"
}],
"lldp_remote_chassis_id_subtype": [{
"data": "Mac address"
}],
"lldp_remote_port_description": [{
"data": "bond0"
}]
}
]
}]
}
}
Here are my tasks:
- name: load data to var
set_fact:
remote_sys_name: "{{ lookup('file', 'juniper-data.json') | from_json }}"
- name: view loaded data
debug:
var: item
loop: "{{ remote_sys_name | community.general.json_query('output.lldp_neighbors_information[0].lldp_neighbor_information[*].[?lldp_local_parent_interface_name[0].data=='ae0'].lldp_remote_system_name[0].data') }}"
Expected results
"item": "A_B_C_D"
What I got is
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected token ',', got 'ae0'. String: {{ remote_sys_name | community.general.json_query('output.lldp_neighbors_information[0].lldp_neighbor_information[*].[?lldp_local_parent_interface_name[0].data=='ae0'].lldp_remote_system_name[0].data') }}"}
If you do not care about the exact hierarchy of nodes and their names beside lldp_neighbor_information
, you can use a cohort of object projections and flatten projection to simplify it:
*.*[][].*[][?
lldp_local_parent_interface_name[0].data == 'ae0'
][].lldp_remote_system_name[].data
As for your current attempt, the issue lies in the fact that your condition is wrongly located in this bit:
lldp_neighbor_information[*].[?lldp_local_parent_interface_name[0].data=='ae0']
The condition should actual replace the star:
lldp_neighbor_information[?lldp_local_parent_interface_name[0].data=='ae0']
Ending up with the query:
output
.lldp_neighbors_information[0]
.lldp_neighbor_information[?
lldp_local_parent_interface_name[0].data=='ae0'
]
.lldp_remote_system_name[0]
.data
Given the task:
- debug:
var: item
loop: >-
{{
lookup('file', 'juniper-data.json')
| from_json
| json_query('
output
.lldp_neighbors_information[0]
.lldp_neighbor_information[?
lldp_local_parent_interface_name[0].data==`ae0`
]
.lldp_remote_system_name[0]
.data
')
}}
This yields:
ok: [localhost] => (item=A_B_C_D) =>
ansible_loop_var: item
item: A_B_C_D
Bonus: If know you before hand that you will only have one element, you can also end your query with | [0]
to stop the projection and only get the first element.
This way, you can get rid of the loop:
- debug:
var: remote_sys_name
vars:
remote_sys_name: >-
{{
lookup('file', 'juniper-data.json')
| from_json
| json_query('
output
.lldp_neighbors_information[0]
.lldp_neighbor_information[?
lldp_local_parent_interface_name[0].data==`ae0`
]
.lldp_remote_system_name[0]
.data | [0]
')
}}
Does yields the name right away:
ok: [localhost] =>
remote_sys_name: A_B_C_D
Bonus bis: if your interface name is in a variable, here would be the task. Mind that it is in a variable local to the task here, but you might define it in any place your requirements call for.
- debug:
var: remote_sys_name
vars:
_interface_name: ae0
remote_sys_name: >-
{{
lookup('file', 'juniper-data.json')
| from_json
| json_query('
output
.lldp_neighbors_information[0]
.lldp_neighbor_information[?
lldp_local_parent_interface_name[0]
.data==`' ~ _interface_name ~ '`
]
.lldp_remote_system_name[0]
.data | [0]
')
}}