Json parse through ansible - json

I have below json
"edge_router_uuid.stdout": {
"buildInfo": {
"buildNumber": "20004",
"buildTimestamp": "1539995399724",
},
"isUp": true,
"pod": "gateway",
"reachable": true,
"region": "dc-1",
"tags": {
........
Actually it is a big json and I am showing above is just a part of it. I need to use the "debug" in ansible to get the variable values for region and reachable values. When I am trying the below
- debug:
var: edge_router_uuid.stdout.region
getting below error.
ok: [10.10.10.10] => {
"edge_router_uuid.stdout.region": "VARIABLE IS NOT DEFINED!"

The JSON syntax is wrong. The problem is "," behind the last value
"buildInfo": {
"buildNumber": "20004",
"buildTimestamp": "1539995399724",
}
Correct syntax is
"buildInfo": {
"buildNumber": "20004",
"buildTimestamp": "1539995399724"
}

Finally I am able to get it as below
- set_fact:
response_dict: "{{ edge_router_uuid.stdout }}"
I ended up with a dictionary named response_dict. Then I am able to get the region value like this:
- debug:
var: response_dict.region

Related

ansible dictionary key value pairs

I am new to Ansible/json and I am trying to parse the following json:
{
"resultCPU": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_facts": {
"CPU": "6",
"VM": "tigger"
},
{
"ansible_facts": {
"CPU": "4",
"VM": "pooh"
},
I need to set the value of the items in this json so that pooh=4 and tigger=6. I will need to refer to both these values later (advice on how to do that would help as well).
I have tried using cpuvm "{{ resultCPU.results |selectattr('VM') |map(attribute='CPU')|list }}" but it complains "'dict object' has no attribute VM".
What am I doing wrong?
Your selectattr ignored the ansible_facts between results: [] and the VM you tried to map. Thankfully, the attribute kwarg understands dot notation
- debug:
msg: >-
VMs are {{ resultCPU.results | map(attribute="ansible_facts.VM") | list }}
CPUs are {{ resultCPU.results | map(attribute="ansible_facts.CPU") | list }}
The together filter may interest you, too
and as for "I will need to refer to both these values later (advice on how to do that would help as well)." that is usually what set_fact: is used for, but without more specifics about what you have tried and what shape you are expecting, it's hard to give a more specific answer

Parsing json output retrieved from an API using Ansbile

I am new to Ansible. I am trying to fetch some API info from a centralized server in the json format, parse the json and set "certificate" to "yes" for each and every server and make a PUT operation back. GET and PUT operations in my code are working fine.
I am not able to find correct syntax to parse listofservers.json.
What is the syntax to display a specific json element??
Can you help me on how to parse the json to change "Certificate" value to Yes for all the servers?
My script
- hosts: serverlist
vars_prompt:
- name: "USER"
prompt: "Enter Admin Username"
private: no
- name: "PASS"
prompt: "Enter Admin Password"
private: yes
tasks:
- name: "Get the current values of all Servers"
delegate_to: localhost
register: listofservers
check_mode: no
uri:
validate_certs: "no"
user: "{{USER}}"
password: "{{PASS}}"
url: "https://console.exmaple.com/adminapi/serverlist"
method: "GET"
body_format: "json"
return_content: "no"
status_code: "200"
- name: Print json dictionary
debug:
var: listofservers.json
Output
TASK [Print json dictionary] *****************************************************************************************
ok: [centalServer.example.com] =>
{
"listofservers.json": {
"serverlist": [
{
"id": 1,
"servername": "redhat.example.com",
"apachestatus": "running",
"certificate": "no"
},
{
"id": 2,
"servername": "solaris.example.com",
"apachestatus": "down",
"certificate": "yes"
} ] } }
Q: "Change "certificate" value to "yes" for all servers."
A: The task below does the job
- set_fact:
listofservers: "{{ {'json':
{'serverlist': serverlist}} }}"
vars:
serverlist: "{{ listofservers.json.serverlist|
map('combine', {'certificate': 'yes'})|
list }}"
- debug:
var: listofservers.json
give
{
"listofservers.json": {
"serverlist": [
{
"apachestatus": "running",
"certificate": "yes",
"id": 1,
"servername": "redhat.example.com"
},
{
"apachestatus": "down",
"certificate": "yes",
"id": 2,
"servername": "solaris.example.com"
}
]
}
}
Q: "What is the syntax to display a specific JSON element?"
A: There are two main options 1) Ansible filters and 2) json_query, and many variations which depend on the structure of the data and requested query
For example, display first servername where id is equal to 1
- debug:
msg: "{{ listofservers.json.serverlist|
selectattr('id', 'eq', 1)|
map(attribute='servername')|
first }}"
gives
"msg": "redhat.example.com"
The same result will give json_query below
- debug:
msg: "{{ listofservers.json.serverlist|
json_query('[?id == `1`].servername')|
first }}"

Ansible fetching Stdout key value

I need some help regarding, how to fetch specific value using Ansible
My task:
- name: 'check Describe Information'
debug:
var: describeresult.stdout
I need IP address value from below stdout, what should I put in debug var to fetch IP address
TASK [check Describe Information] **********************************************
task path: /home/tom/Getipaddress.yml:28
ok: [127.0.0.1] => {
"describeresult.stdout": {
"failures": [],
"tasks": [
{
"attachments": [
{
"details": [
{
"name": "subnetId",
"value": "subnet-xxxxxxxxxxxxxx"
},
{
"name": "networkInterfaceId",
"value": "eni-xxxxxxxxxxxxxxxx"
},
{
"name": "macAddress",
"value": "xxxxxxxxxxxxxxxxxx"
},
{
"name": "privateIPv4Address",
"value": "xxxxxxxxxxxxxxxxxx"
}
Plus I am using AWS ECS command to generate the above output with --output as a JSON not sure how to use --query to filter or fetch above IP address only
Use json_query. For example
- set_fact:
my_privateIPv4Address: "{{ describeresult.stdout.tasks|
json_query(query) }}"
vars:
query: "[].attachments[].details[?name=='privateIPv4Address'].value"
json_query returns by default a list.
You can use something like this for getting private IP address only
"{{describeresult.stdout['tasks'][0]['attachments'][0]['details'][3]['value']}}"
The above might have slight syntax issues but should work.
I have done something like this earlier for ec2_group_info module in ansible
You can start off by generating output in pieces describeresult.stdout['tasks'] should return JSON for the task attribute.
[0] indicates the first element when there is a box bracket for a JSON implying more than one element/list.
Let me know how it goes.

Extract field from JSON response with Ansible

I have a task which performs a GET request to a page. The response's body is a JSON like the following.
{
"ips": [
{
"organization": "1233124121",
"reverse": null,
"id": "1321411312",
"server": {
"id": "1321411",
"name": "name1"
},
"address": "x.x.x.x"
},
{
"organization": "2398479823",
"reverse": null,
"id": "2418209841",
"server": {
"id": "234979823",
"name": "name2"
},
"address": "x.x.x.x"
}
]
}
I want to extract the fields id and address, and tried (for id field):
tasks:
- name: get request
uri:
url: "https://myurl.com/ips"
method: GET
return_content: yes
status_code: 200
headers:
Content-Type: "application/json"
X-Auth-Token: "0010101010"
body_format: json
register: json_response
- name: copy ip_json content into a file
copy: content={{json_response.json.ips.id}} dest="/dest_path/json_response.txt"
but I get this error:
the field 'args' has an invalid value, which appears to include a variable
that is undefined. The error was: 'list object' has no attribute 'id'..
Where is the problem?
The error was: 'list object' has no attribute 'id'
json_response.json.ips is a list.
You either need to choose one element (first?): json_response.json.ips[0].id.
Or process this list for example with map or json_query filters if you need all ids.
Ansible command to copy to file:
copy:
content: "{{ output.stdout[0] }}"
dest: "~/ansible/local/facts/{{ inventory_hostname }}.txt"

Extracting data from json within ansible

I have an ansible playbook that creates some IAM users in AWS.
I'd like the playbook to return the username and access keys details for each account created.
Registering the output from the task is fairly straightforward:
- name: Create IAM users
iam:
iam_type: user
name: "{{ item }}"
state: present
access_key_state: create
with_items:
- "user1"
- "someotheruser"
- "user3"
register: users
I'm finding doing something with that output tricky.
The Json it produces is as follows: (slightly truncated to reduce the length here)
ok: [localhost] => {
"users": {
"changed": true,
"msg": "All items completed",
"results": [
"user_meta": {
"access_keys": [
{
"access_key_id": "key1",
"access_key_selector": "HMAC",
"create_date": "2016-05-19T08:37:11.007Z",
"secret_access_key": "secretkey1",
"status": "Active",
"user_name": "user1"
}
],
}
},
{
"user_meta": {
"access_keys": [
{
"access_key_id": "key2",
"access_key_selector": "HMAC",
"create_date": "2016-05-19T08:37:13.391Z",
"secret_access_key": "secretkey2",
"status": "Active",
"user_name": "someotheruser"
}
],
}
},
{
"user_meta": {
"access_keys": [
{
"access_key_id": "key3",
"access_key_selector": "HMAC",
"create_date": "2016-05-19T08:37:16.243Z",
"secret_access_key": "secretkey3",
"status": "Active",
"user_name": "user3"
}
],
}
}
]
}
}
I've want to display this neatly on completion of the playbook, the closest I've come to getting what I'm after is use debug as follows:
- debug: var="users.results[0].user_meta.access_keys"
- debug: var="users.results[1].user_meta.access_keys"
- debug: var="users.results[2].user_meta.access_keys"
However that feels lame. What if I add user 4 and 5?
I'd like to be able to refer to the entire results array so that it will work no matter how many users I add to the playbook.
Is there a way to achieve this?
As a side note, I've also tried to use from_json, e.g.
- debug: msg="{{ (users.stdout|from_json).results }}"
but I don't know if I'm hitting a bug with ansible 2.0.1.0 or if I'm using it wrong but I could only ever get "type error. expected string or buffer"
Any thoughts gladly received.
You can iterate through the registered variable as well.
Something like this should work:
- name : debug access keys
debug : var="{{ item.user_meta.access_keys }}"
with_items: users.results
In case someone else wants to do the same thing...
I found the best solution for me was to count the number of objects in the array using 'length' and the then set the range that debug should iterate over.
I subtract "1" from the value returned since the first object in the array is referenced by "0".
- name: Record Users Access Keys
debug: var=users.results[{{ item }}].user_meta.access_keys
with_sequence: start=0 end={{users.results|length -1}}
Hope that helps someone looking to do something similar.
Ansiballer's answer worked for me, but if anyone else is looking for something simpler you can use json_query:
- name: show access keys
debug:
var: item
loop: "{{ users | json_query('results[*].user_meta.access_keys') }}"
Ansible docs on json_query
You may have to install jmespath for this to work (apt-get install python-jmespath or similar)