How to sort with JMESPath in ansible playbook? - json

I have an array returned by curl from consul during playing ansible playbook:
[
{
"Node": {
"Node": "test-eu-west-2-staging-0"
},
"Node": {
"Node": "test-nyc1-staging-0"
},
"Node": {
"Node": "test-sfo1-staging-0"
}
}
]
I want to have it sorted by "Node": {"Node" : "hostname"} in ansible playbook
- name: Set TEST vars, servers info and number
set_fact:
TEST_SERVERS="{{ test.json | json_query('SOME SORTING QUERY') }}"
TEST_SRV_NUM="{{ test.json | length }}"
I have read JMESPath and ansible docs for whole day but still don't know how to implement it (btw it is easy in jq sort_by(.Node.Node) but this trick is not applicable to ansible)

As #techraf noted, your sample JSON is malformed. I can make a guess that you have a list of objects with Node.Node inside, in this case you can use sort Jinja2 filter:
---
- hosts: localhost
gather_facts: no
vars:
myvar: [
{ "Node": { "Node": "test-c" } },
{ "Node": { "Node": "test-b" } },
{ "Node": { "Node": "test-a" } }
]
tasks:
- debug:
msg: "{{ myvar | sort(attribute='Node.Node') }}"

Related

separate json keys into different file ansible

I have a variable of a large JSON data of students' data of different classes containing their names and numbers respectively. The variable is "data" and here is what the variable contains:
{
"Class001": [
{
"Jesse": 001
},
{
"Adam": 002
}
],
"Class002": [
{
"Jill": 111
},
{
"Ray": 112
}
],
.....
}
Using ansible, I want to separate the keys "Class00X" into some different files. For example, the Class001 file contain:
{
"Jesse": 001
},
{
"Adam": 002
},
.....
etc. How can i do this? thanks
i have created a file.json with:
{
"Class001": [
{
"Jesse": "001"
},
{
"Adam": "002"
}
],
"Class002": [
{
"Jill": "111"
},
{
"Ray": "112"
}
]
}
this playbook does the job:
- hosts: localhost
gather_facts: no
vars:
json: "{{ lookup('file', 'file.json') | from_json }}"
tasks:
- name: loop
copy:
dest: "files/{{ item.key }}.txt"
content: "{{ item.value | to_nice_json }}"
loop: "{{ json | dict2items }}"
here files files/class001.txt and files/class002.txt are created
A dictionary is a better structure to store students' names and numbers. Optionally, store the dictionaries instead of lists
- copy:
dest: "files/{{ item.key }}.yml"
content: "{{ item.value|combine|to_nice_yaml }}"
loop: "{{ json|dict2items }}"
gives
shell> cat files/Class001.yml
Adam: '002'
Jesse: '001'
shell> cat files/Class002.yml
Jill: '111'
Ray: '112

ansible obtain values from changing key

I would like to get value from json, but one of the key can be differet.
here is example json
{
"json": {
"id": "9758b1e5-442e-4545-9364-45f28477edfb",
"results": [{
"code": 200,
"host": "localhost",
"message": "no change",
"runTime": 1233,
"tenant": "http-validate-2.usa-dc.com"
}],
"traces": {
"http-validate-2.usa-dc.comCurrent": {
"/Common/10.10.100.10": {
"command": "ltm node"
},
"http-validate-2.usa-dc.comDiff": [{
"command": "ltm virtual",
"kind": "D",
"lhs": {
"default": "yes"
},
"lhsCommand": "ltm virtual",
"path": [
"/http-validate-2.usa-dc.com/app/vs_http-validate-2.usa-dc.com_80",
"properties",
"persist",
"/Common/cookie"
],
"rhsCommand": "ltm virtual",
"tags": [
"tmsh"
]
}]
}
}
}
}
my ansible playbook
tasks:
- name : deploy json file AS3 to F5
debug:
msg: "{{ lookup('file', 'parse.json') }}"
register: atc_AS3_status
- name: debug
debug:
msg: "{{ atc_AS3_status.msg.json['traces']['.*Diff']}}"
I would like to reach key "path" but the key above "http-validate-2.usa-dc.comDiff" can be different like "http-validate-3.can-dc.comDiff" but always finish with Diff
Use json_query, e.g.
- debug:
msg: "{{ json.traces|json_query('*.*[][].path') }}"
should give the list of the paths (there might be more of them)
msg:
- - /http-validate-2.usa-dc.com/app/vs_http-validate-2.usa-dc.com_80
- properties
- persist
- /Common/cookie
Q: "I need path only in the key which ends Diff."
A: JMESPath is not able to search key wildcards, AFAIK. Instead, use select and create the list of the nested keys that match the regex, e.g.
- debug:
msg: "{{ json.traces|json_query('*.keys(#)')|flatten|
select('match', '^.*Diff$')|list }}"
gives
msg:
- http-validate-2.usa-dc.comDiff
Then iterate this list, select path and concatenate the list paths, e.g.
- set_fact:
paths: "{{ paths|d([]) + json.traces|json_query(query) }}"
loop: "{{ json.traces|json_query('*.keys(#)')|flatten|
select('match', '^.*Diff$')|list }}"
vars:
query: '*."{{ item }}"[].path'
gives the list of paths for the keys that match the regex
paths:
- - /http-validate-2.usa-dc.com/app/vs_http-validate-2.usa-dc.com_80
- properties
- persist
- /Common/cookie

Ansible pretty print json

when I'm running my playbook I get the debug output in the correct json format I would want it
"ansible_facts": {
"routes": [
{
"subnet": "10.0.0.0/24"
},
{
"subnet": "10.0.1.0/24"
}
]
},
but when I export it to a file using the local_action directive it displays like this
[{"subnet": "10.0.0.0/24"}, {"subnet": "10.0.1.0/24"}
Is there any working pretty print module or in Ansible which would export my file in the same way as I see it in the debug messages?
Thanks!
Not exactly the output you get on screen, but you could use a template task to print the variable, after passing it through a to_nice_json filter. Example:
---
- hosts: localhost
gather_facts: false
vars:
my_ansible_facts:
routes:
- subnet: 10.0.0.0/24
- subnet: 10.0.1.0/24
tasks:
- template: src=nice_yaml_filter.j2 dest=/tmp/nice_yaml_filter.out
Please note that i am not using the same variable as you are, just a my_ansible_facts variable that i populated.
And the template file's contents, nice_yaml_filter.j2:
{{ my_ansible_facts | to_nice_json }}
Result:
[http_offline#greenhat-32 ANSIBLE_TESTS]$ cat /tmp/nice_yaml_filter.out
{
"routes": [
{
"subnet": "10.0.0.0/24"
},
{
"subnet": "10.0.1.0/24"
}
]
}[http_offline#greenhat-32 ANSIBLE_TESTS]$
cheers

How to get values from registered json output conditionally in ansible

I am trying to parse the json output of yum module, to conditionally get data.
My playbook looks like below:
---
- hosts: all
become: true
tasks:
- name: list ggk rpms
yum:
list: "{{ item }}"
register: ggk_njk_info
ignore_errors: yes
with_items:
- ggk_base
- njk_tt_client
- debug: msg="{{ item.results }}"
with_items: "{{ ggk_njk_info.results }}"
when: item.results
The output for the debug task looks like below:
A part of the debug looks like below:
"msg": [
{
"arch": "noarch",
"envra": "0:njk_tt_client-2.36.11-1.noarch",
"epoch": "0",
"name": "njk_tt_client",
"release": "1",
"repo": "ggk_Software",
"version": "2.36.11",
"yumstate": "available"
},
{
"arch": "noarch",
"envra": "0:njk_tt_client-2.36.11-1.noarch",
"epoch": "0",
"name": "njk_tt_client",
"release": "1",
"repo": "installed",
"version": "2.36.11",
"yumstate": "installed"
},
{
"arch": "noarch",
"envra": "0:njk_tt_client-2.36.3-1.noarch",
"epoch": "0",
"name": "njk_tt_client",
"release": "1",
"repo": "ggk_Software",
"version": "2.36.3",
"yumstate": "available"
}
]
}
I would like to find the rpm "version" ONLY when its corresponding "yumstate" is "installed"
In this case i would like to be able to get the version for below:
"repo": "installed",
"version": "2.36.11",
json_query does the job. For example the task below
- debug:
msg: "{{ ggk_njk_info.results|
json_query('[?yumstate==`installed`].{repo: repo,
version: version}') }}"
gives
"msg": [
{
"repo": "installed",
"version": "2.36.11"
}
]

Parsing json using Ansible

I have a json as below :
"instances": {
"biometricsManagerInstance": {
"appId": "biometrics-manager",
"spawnType": "uniqueSiteWide"
},
"videoSensorInstance": {
"appId": "video-sensor",
"spawnType": "reuse"
},
"faceDetectionInstance":{
"appId": "face-detection",
"spawnType": "reuse"
},
"faceMatchingInstance":{
"appId": "face-matching",
"spawnType": "new"
},
"faceAnnotatorInstance":{
"appId": "face-annotator",
"spawnType": "new"
}
}
I have a variable where the json is stored. Lets say : my_json_contents
I want to create a dictionary from this data which has values like :
{"biometrics-manager":"biometricsManagerInstance","video-sensor":"videoSensorInstance","face-detection":"faceDetectionInstance",..}
I want to achieve it using ansible. Help is appreciated.TIA.
Here you are:
- set_fact:
instances_modified: "{{ instances_modified | default({}) | combine({item.1.appId: item.0}) }}"
loop: "{{ instances | dictsort }}"