Ansible Dictionary value not set - json

I'm trying to fill a value in a dictionary with ansible but apparently is not doing it.
I do like this:
- name: Fill with zeros
set_fact:
item: "{{ item | combine(zero_fill, recursive=true) }}"
vars:
zero_fill: { 'json' : { 'data': { 'result': [{ 'value' : ["0.0","0.0"]}]}}}
when: item.json.data.result == []
with_items:
- "{{ requests.results }}"
One item from this variable is like this:
{
...
"json": {
"data": {
"result": [],
"resultType": "vector"
}
}
...
}
The point is that in the output of this task I do see the value added, but when I print it just right after the task, the value is not there.

For example, create a new list results_zf and update the dictionary json.data with zero_fill when json.data.result is an empty list
- set_fact:
results_zf: "{{ results_zf|default([]) + [_item] }}"
loop: "{{ requests.results }}"
vars:
_item: "{{ (item.json.data.result|length > 0)|
ternary(item,
{'json': {'data': item.json.data|combine(zero_fill)}})
}}"
Limit the dictionary zero_fill to the attribute result
zero_fill:
'result': [{'value': ["0.0","0.0"]}]

Related

Check on a list of JSON objects in Ansible

I have in stdout a list of json objects:
[
{
"key1": "value1",
"status": "connected",
"key2": "value2"
},
{
"key1": "value1",
"status": "disconnected",
"key2": "value2"
},
...
]
I would loop on this list and check the value of key "status".
If it is "connected" for all objects, set a var to true. If there is at least one object with "status" to "disconnected", set the var to false.
use selectattr to check if a value is present:
- name: load json
shell: cat file.json
register: result
- name: save the Json data to a Variable as a Fact
set_fact:
jsondata: "{{ result.stdout | from_json }}"
- name: trap final result
set_fact:
status: "{{ value|int == 0 }}"
vars:
value: "{{ jsondata | selectattr('status', 'match', 'disconnected') |length}}"
- debug:
var: status
jsondata | selectattr('status', 'match', 'disconnected') |length gives the lenght of array containing disconnected so if result is 0, that means all values are connected

How to skip null values in json query?

Im trying to pull values from a json file but I do not want values that are null? How can I easily skip null values?
I am just trying to find the easiest and simplest solution to parsing JSON into YALM and not have formatting errors in YAML. Maybe I am over complicating it.
JSON:
{
"configuration": {
"protocols" : {
"bgp" : {
"group" : [
{
"name" : "IBGP",
"neighbor" : [
{
"name" : "192.168.1.2",
"description" : "router-2"
}
]
},
{
"name" : "EBGP",
"neighbor" : [
{
"name" : "192.168.2.2",
"description" : "router-3",
"local-address" : "192.168.2.1",
"peer-as" : "65555"
}
]
}
]
}
}
}
}
Play:
- name: parse bgp
set_fact:
bgp: "{{ read | to_json | from_json | json_query(bgp_var) }}"
vars:
bgp_var: 'configuration.protocols.bgp.group[].{group_name:name,neighbors:[{peer_ip:neighbor[].name | [0], peer_description:neighbor[].description | [0], peer_as:neighbor[]."peer-as" | [0] }]}'
- copy:
content: >-
routing_protocols:
bgp:
{{ bgp | to_nice_yaml(indent=2, width=1337, sort_keys=False) | indent(4) }}
dest: "{{ inventory_hostname }}_routing_protocols.yaml"
Returns:
routing_protocols:
bgp:
- group_name: IBGP
neighbors:
- peer_as: null # < Is there a way to skip this anytime a value is null?
peer_description: router-2
peer_ip: 192.168.1.2
- group_name: EBGP
neighbors:
- peer_as: '65555'
peer_description: router-3
peer_ip: 192.168.2.2
you could use this playbook with the parameter omit:
tasks:
- name: set var
set_fact:
bgp: >-
{{ bgp | d([]) +
[ {'group_name': _gpname,
'neighbors': [{'peer_description': _desc, 'peer_ip': _peerip, 'peer_as': _peeras}]
}
] }}
loop: "{{ configuration.protocols.bgp.group }}"
vars:
_gpname: "{{ item.name }}"
_desc: "{{ item.neighbor.0.description }}"
_peeras: "{{ item.neighbor[0]['peer-as'] | d(omit)}}"
_peerip: "{{ item.neighbor.0.name }}"
- name: displ
debug:
msg: "{{ bgp }}"
result:
ok: [localhost] => {
"msg": [
{
"group_name": "IBGP",
"neighbors": [
{
"peer_description": "router-2",
"peer_ip": "192.168.1.2"
}
]
},
{
"group_name": "EBGP",
"neighbors": [
{
"peer_as": "65555",
"peer_description": "router-3",
"peer_ip": "192.168.2.2"
}
]
}
]
}
You can make it in one go in JMESPath, but that would require a double query on the property neighbour, as JMESPath cannot omit a property as Ansible can (for that, see #Frenchy's answer).
So, you would have to have list of list, into which, the first sub list would consist of the neighbour that would contain the key peer-as, and the second sub list, the one that would not contain it. Then you will have to flatten this list of list.
So, here is the copy task:
- copy:
content: >-
{{
read
| to_json
| from_json
| json_query(query)
| to_nice_yaml(indent=2)
}}
dest: "{{ inventory_hostname }}_routing_protocols.yaml"
vars:
query: >-
{
routing_protocols: {
bgp: configuration.protocols.bgp.group[].{
group_name: name,
neighbors: [
neighbor[?"peer-as"].{
peer_description: description,
peer_ip: name,
peer_as: "peer-as"
},
neighbor[?"peer-as" == null].{
peer_description: description,
peer_ip: name
}
]|[]
}
}
}
After this task, you will end with a YAML file containing your expected:
routing_protocols:
bgp:
- group_name: IBGP
neighbors:
- peer_description: router-2
peer_ip: 192.168.1.2
- group_name: EBGP
neighbors:
- peer_as: '65555'
peer_description: router-3
peer_ip: 192.168.2.2

ansible json_query to extract value dependant on other field

Looking to extract href value for each flavor from below json when rel==self and I just can't work it out
{
"flavors": [
{
"id": "1",
"links": [
{
"href": "http://127.0.0.1:8764/v2.1/flavors/1",
"rel": "self"
},
{
"href": "http://127.0.0.1:8764/flavors/1",
"rel": "bookmark"
}
],
"name": "m1.tiny"
},
{
"id": "2",
"links": [
{
"href": "http://127.0.0.1:8764/v2.1/flavors/2",
"rel": "self"
},
{
"href": "http://127.0.0.1:8764/flavors/2",
"rel": "bookmark"
}
],
"name": "m1.small"
},
{
"id": "3",
"links": [
{
"href": "http://127.0.0.1:8764/v2.1/flavors/3",
"rel": "self"
},
{
"href": "http://127.0.0.1:8764/flavors/3",
"rel": "bookmark"
}
],
"name": "m1.medium"
}
]
}
I have tried below but just cant get the jmesquery: 'flavors.links[?contains(rel, self)]' query to work?
- name:
uri:
url: 'http://192.168.1.182:8774/v2.1/flavors'
method: GET
body_format: json
headers:
X-Auth-Token: "{{ ansible_facts.auth_token }}"
Content-Type: "application/json; charset=UTF-8"
return_content: yes
register: this
- debug:
msg: "{{ this }}"
- name: save the Json data to a Variable as a Fact
set_fact:
jsondata: "{{ this }}"
- debug:
msg: "{{ jsondata }}"
- name: save the Json data to a Variable as a Fact
set_fact:
flavors: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'json.flavors'
- debug:
msg: "{{ flavors }}"
- name: LINKS
set_fact:
links: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'flavors.links[?contains(rel, `self`)]'
- debug:
msg: "{{ links }}"
I can print the values for all href using below...
- name: save the Json data to a Variable as a Fact
set_fact:
href: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'json.flavors[*].links[].href'
- debug:
msg: "{{ href }}"
Any help appreciated?
Actually, I have eventually worked it out...
- name: save the Json data to a Variable as a Fact
set_fact:
href: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: json.flavors[].links[?rel==`self`].href
- debug:
msg: "{{ href }}"

Ansible - nested loop over object without knowing object/key name

I'm working on an ansible playbook, I need to get a value from a JSON API result.
I want to get the value of the key "1h" without knowing the previous object (sd#eureka...), and i need to loops over all my results, and all my buckets.
{
"etat_ms_rep": {
"results": [
{
"buckets": {
"sd#eureka#pixidanalyticsbackend#c3fb422bb36882d9f502092fd75fcb34": {
"1h": -1,
"1m": -1
},
"sd#eureka#pixidanalyticsbackend#348fdab155904e22ca0c744d0c052cf8": {
"1h": 100,
"1m": 100
}
}
},
{
"buckets": {
"sd#eureka#pixidorchestratorbackend#8fa3441c6c5caa2d5f0e3264a00be91b": {
"1h": 100,
"1m": 100
},
"sd#eureka#pixidorchestratorbackend#6dc48be83cb86ae1a73b344e9421ed8e": {
"1h": 100,
"1m": 100
}
}
}
]
}
}
I tried that but without success, it doesnt show the value of "1h" key...
- name: Display all bucket info
set_fact:
test: "{{ etat_ms_rep.results | json_query(jmesquery) }}"
vars:
jmesquery: " [*].['1h'] "
For example
- name: Get the value of the key 1h
debug:
msg: "{{ etat_ms_rep.results | json_query(jmesquery) }}"
vars:
jmesquery: '[].*.*.["1h"]'
gives
msg:
- - - - -1
- - 100
- - - - 100
- - 100
Flatten the list if you want to
- name: Get the value of the key 1h
debug:
msg: "{{ etat_ms_rep.results | json_query(jmesquery) | flatten }}"
vars:
jmesquery: '[].*.*.["1h"]'
gives
msg:
- -1
- 100
- 100
- 100

Using item in Ansible json_query

I'm trying to loop through a list of keys to grab associated names from some json:
- name: show names
debug:
msg: "{{ data.json | json_query(query) }}"
vars:
query: "[? key==item].name"
with_items: "{{ keys.split() }}"
But it never displays properly when I try to run it. The keys are correct, but no data is returned:
TASK [get_help_on_SO: show]
ok: [localhost] => (item=Key1) => {
"msg": []
}
ok: [localhost] => (item=Key2) => {
"msg": []
}
Manually putting in the code works just fine so my query syntax seems to be right:
query: "[? key==`Key1`].name"
TASK [get_help_on_SO : show]
ok: [localhost] => (item=Key1) => {
"msg": [
"FooBar 1"
]
}
ok: [localhost] => (item=Key2) => {
"msg": [
"FooBar 1"
]
}
How can I properly pass the item into the json_query?
You didn't surround the item variable with any Jinja delimiters, so it is not interpreted.
You end testing if the key is equal to the string 'item' and not to the string stored in the variable item.
- name: show names
debug:
msg: "{{ data.json | json_query(query) }}"
vars:
query: "[?key==`{{ item }}`].name"
with_items: "{{ keys.split() }}"
Given the data
keys: 'key1 key3'
data:
json: [{
"key": "key1",
"name": "name1"
},
{
"key": "key2",
"name": "name2"
},
{
"key": "key3",
"name": "name3"
}
]
the expected result is
- name1
- name3
It's possible to avoid both the loop and json_query and simplify the solution. The task below
- name: show names
debug:
msg: "{{ data.json|
selectattr('key', 'in', my_keys)|
map(attribute='name')|
list }}"
vars:
my_keys: "{{ keys.split() }}"
gives
msg:
- name1
- name3