How to make a specific dict in Ansible from json output - json

I have an Ansible job that run on 2 or more urls. Each url returns the same variables with different values. Here is the JSON data registry of the job:
{
"msg": {
"results": [
{
"url": "http://0.0.0.1:xxx1",
"othervar": "othervar",
"othervar2": "othervar2",
"json": {
"messages": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
]
}
},
{
"url": "http://0.0.0.2:xxx2",
"othervar": "othervar",
"othervar2": "othervar2",
"json": {
"messages": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
]
}
}
]
}
}
I want to make a specific dict containing only the url variable and also message and message2 variables. I have 2 options for my expected results:
option 1:
"message": [
{
"url": "http://0.0.0.1:xxx1",
"content": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
]
},
{
"url": "http://0.0.0.2:xxx2",
"content": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
]
}
option 2:
"message": [
{
"url": "http://0.0.0.0:xxx1",
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"url": "http://0.0.0.0:xxx1",
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"url": "http://0.0.0.0:xxx1",
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"url": "http://0.0.0.0:xxx2",
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"url": "http://0.0.0.0:xxx2",
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"url": "http://0.0.0.0:xxx2",
"message": "This is message number 2",
"message2": "This is message2 number 2"
}
]
I am able to get each variable (url only, message only, message2 only) but how can i merge them into a dict like option 1 or option 2?

The easiest way is to start with option 1 which is the closest to your original data. You can for example declare it as var in your play:
my_results: "{{ results | json_query('[].{\"url\": url, \"content\": json.messages}') }}"
Note that json_query requires the community.general collection (usually available if you installed the ansible meta package) and pip install jmespath
This gives (debuging the above variable):
TASK [debug] *******************************************************************
ok: [localhost] => {
"my_results": [
{
"content": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
],
"url": "http://0.0.0.1:xxx1"
},
{
"content": [
{
"message": "This is message number 1",
"message2": "This is message2 number 1"
},
{
"message": "This is message number 2",
"message2": "This is message2 number 2"
},
{
"message": "This is message number 3",
"message2": "This is message2 number 3"
}
],
"url": "http://0.0.0.2:xxx2"
}
]
}
From there, If you need to loop on structure which looks like your option 2, it's very easy to acheive using the subelements lookup:
- name: loop on a structure looking like option 2
debug:
msg:
- "url is {{ item.0.url }}"
- "message one is {{ item.1.message }}"
- "message two is {{ item.1.message2 }}"
loop: "{{ q('subelements', my_results, 'content') }}"
loop_control:
label: "{{ item.0.url }}"
which gives:
TASK [loop on a structure looking like option 2] *******************************
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.1:xxx1",
"message one is This is message number 1",
"message two is This is message2 number 1"
]
}
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.1:xxx1",
"message one is This is message number 2",
"message two is This is message2 number 2"
]
}
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.1:xxx1",
"message one is This is message number 3",
"message two is This is message2 number 3"
]
}
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.2:xxx2",
"message one is This is message number 1",
"message two is This is message2 number 1"
]
}
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.2:xxx2",
"message one is This is message number 2",
"message two is This is message2 number 2"
]
}
ok: [localhost] => (item=item.0.url) => {
"msg": [
"url is http://0.0.0.2:xxx2",
"message one is This is message number 3",
"message two is This is message2 number 3"
]
}
Here is a playbook for a full test:
---
- hosts: localhost
gather_facts: false
vars:
# Your orig data minified
results: [{"url":"http://0.0.0.1:xxx1","othervar":"othervar","othervar2":"othervar2","json":{"messages":[{"message":"This is message number 1","message2":"This is message2 number 1"},{"message":"This is message number 2","message2":"This is message2 number 2"},{"message":"This is message number 3","message2":"This is message2 number 3"}]}},{"url":"http://0.0.0.2:xxx2","othervar":"othervar","othervar2":"othervar2","json":{"messages":[{"message":"This is message number 1","message2":"This is message2 number 1"},{"message":"This is message number 2","message2":"This is message2 number 2"},{"message":"This is message number 3","message2":"This is message2 number 3"}]}}]
my_results: "{{ results | json_query('[].{\"url\": url, \"content\": json.messages}') }}"
tasks:
- name: debug my_results var to check
debug:
var: my_results
- name: loop on a structure looking like option 2
debug:
msg:
- "url is {{ item.0.url }}"
- "message one is {{ item.1.message }}"
- "message two is {{ item.1.message2 }}"
loop: "{{ q('subelements', my_results, 'content') }}"
loop_control:
label: item.0.url

The following code loads your input json, then creates a new array with the structure you ask in option 1, by creating new items while iterating on your messages list:
---
- name: Playbook for infinispan Hosts
hosts: localhost
tasks:
- name: load json from file
shell: cat test.json
register: result
- name: save the input json data to a variable
set_fact:
jsondata: "{{ result.stdout | from_json }}"
- name: display the input dict
debug:
var: jsondata
- name: parse the json into new array
set_fact:
message: "{{ message|default([]) + [ { 'url': item.url, 'content': item.json.messages } ] }}"
loop: "{{ jsondata.msg.results }}"
- name: display the resulting data structure
debug:
var: message

Related

How to remove duplicate dict in Ansible?

So I have a dict data that look like this
{
"json_response": [
{
"message": "The Value is 1505",
"Value": "1505"
},
{
"message": "The Value is 1534",
"Value": "1534"
},
{
"message": "The Value is 1505",
"Value": "1505"
},
{
"message": "The Value is 1534",
"Value": "1534"
}
],
}
What I'm trying to achieve is something like this:
{
"json_response": [
{
"message": "The Value is 1505",
"Value": "1505"
},
{
"message": "The Value is 1534",
"Value": "1534"
}
],
}
I have tried:
remove_duplicate: "{{ json_response('\n') | unique | join('\n') }}"
and also:
remove_duplicate: "{{ json_response('\n') | unique | list }}"
But it returned error like this:
{
"msg": "Unexpected templating type error occurred on ({{ json_response('\n') | unique | join('\n') }}): 'list' object is not callable",
"_ansible_no_log": false
}
How can I achieve unique dict from my data?

How to remove brackets from JSON?

I have a groovy script that I want to return userDefinedErrorText. The issue I am having is that when parse my JSON I am having my failedForm variable equal [Failed] instead of "Failed".
If I remove the first pair of [] from my JSON input, I get the correct "Failed".
Is there a way to remove [] from the input JSON?
My Groovy
def json = new JsonSlurper().parseText( aInputJson )
failedForm = json?.userDefinedErrorText
if( failedForm == "Failed" ) {
resultMessage = "false"
}
JSON
[
{
"step": "abcd",
"message": {
"ServiceRequest: abc": {
"App Stack Form Exception": {
"Expecting Form": "P",
"Resulting Form": "P"
},
"JAS Response": {
"fs_P": {
"title": "I",
"data": {},
"errors": [
{
"CODE": "799L",
"TITLE": "Error: Invalid Long Address Number",
"ERRORCONTROL": "15",
"DESC": "CAUSE . . . . The long address number entered is not found in the Address Book\\u000a Master file (F0101).\\u000aRESOLUTION. . Enter a valid long address number.",
"MOBILE": "The long address number entered is not found in the Address Book\\u000a Master file (F0101)."
}
],
"warnings": []
},
"stackId": 12,
"stateId": 5,
"rid": "8f4",
"currentApp": "P",
"timeStamp": "2022-04-22:11.25.03",
"sysErrors": []
}
}
},
"timeStamp": "2022-04-22T11:25:03.235-0400",
"userDefinedErrorText": "Failed"
}
]
The issue I am having is that when parse my JSON I am having my
failedForm variable equal [Failed] instead of "Failed".
The following should work:
String jsonString = '''
[
{
"step": "abcd",
"message": {
"ServiceRequest: abc": {
"App Stack Form Exception": {
"Expecting Form": "P",
"Resulting Form": "P"
},
"JAS Response": {
"fs_P": {
"title": "I",
"data": {},
"errors": [
{
"CODE": "799L",
"TITLE": "Error: Invalid Long Address Number",
"ERRORCONTROL": "15",
"DESC": "CAUSE . . . . The long address number entered is not found in the Address Book\\\\u000a Master file (F0101).\\\\u000aRESOLUTION. . Enter a valid long address number.",
"MOBILE": "The long address number entered is not found in the Address Book\\\\u000a Master file (F0101)."
}
],
"warnings": []
},
"stackId": 12,
"stateId": 5,
"rid": "8f4",
"currentApp": "P",
"timeStamp": "2022-04-22:11.25.03",
"sysErrors": []
}
}
},
"timeStamp": "2022-04-22T11:25:03.235-0400",
"userDefinedErrorText": "Failed"
}
]'''
def json = new JsonSlurper().parseText(jsonString)
String value = json[0].userDefinedErrorText
assert value == 'Failed'

How to using testrail-api to add result for step

The testrail-api have 4 method to update result.
add_result
add_result_for_case
add_results
add_results_for_cases
add_result >> How should I do let me can add result to step?
The TestRail documentation includes an example of how to add steps when using the add_result endpoint. You need to use the custom_step_results field as shown below:
{
"status_id": 5,
"comment": "This test failed",
"elapsed": "15s",
"defects": "TR-7",
"version": "1.0 RC1 build 3724",
"custom_step_results": [
{
"content": "Step 1",
"expected": "Expected Result 1",
"actual": "Actual Result 1",
"status_id": 1
},
{
"content": "Step 2",
"expected": "Expected Result 2",
"actual": "Actual Result 2",
"status_id": 2
}
]
}

Using JQ to specific csv format

I have a json that looks like this:
[
{
"auth": 1,
"status": "Active",
"userCustomAttributes": [
{
"customAttributeName": "Attribute 1",
"customAttributeValue": "Value 1"
},
{
"customAttributeName": "Attribute 2",
"customAttributeValue": "Value 2"
},
{
"customAttributeName": "Attribute 3",
"customAttributeValue": "Value 3"
}
],
},
{
"auth": 1,
"status": "Active",
"userCustomAttributes": [
{
"customAttributeName": "Attribute 1",
"customAttributeValue": "Value 1"
},
{
"customAttributeName": "Attribute 2",
"customAttributeValue": "Value 2"
},
{
"customAttributeName": "Attribute 3",
"customAttributeValue": "Value 3"
},
{
"customAttributeName": "Attribute 4",
"customAttributeValue": "Value 4"
}
],
}
]
I would like to parse this and have a css output that looks something like this:
authType, status, attribute 1, attribute 2, attribute 3, attribute 4
"1", "active", "value1", "value2", "value3",""
"1", "active", "value1", "value2", "value3","value 4"
The json has over 180k records in the array so it would need to loop through all of them. Some records don't have all the attributes. Some have all 4 yet some only have 1. I am hoping to show a null value in the csv for the records that don't have the attribute.
With your sample input, the following program, which does not depend on the ordering of the "attribute" keys:
jq -r '
["Attribute 1", "Attribute 2", "Attribute 3", "Attribute 4"] as $attributes
# Header row
| ["authType", "status"]
+ ($attributes | map( (.[:1] | ascii_upcase) + .[1:])),
# Data rows:
(.[]
| (INDEX(.userCustomAttributes[]; .customAttributeName)
| map_values(.customAttributeValue)) as $dict
| [.auth, .status] + [ $dict[ $attributes[] ] ]
)
| #csv
'
produces the following CSV:
"authType","status","Attribute 1","Attribute 2","Attribute 3","Attribute 4"
1,"Active","Value 1","Value 2","Value 3",
1,"Active","Value 1","Value 2","Value 3","Value 4"
You can easily modify this to emit a literal string of your choice in place of a JSON null value.
Explanation
$dict[ $a[] ] produces the stream of values:
$dict[ $a[0] ]
$dict[ $a[1] ]
...
This is used to ensure the columns are produced in the correct order, independently of the ordering or even presence of the keys.

How to create nested object in MongoDB schema, nested object and array MEAN stack

I'm trying to design a nested MongoDB schema.
Currently, I have this schema and it's working:
var CompanySchema = new mongoose.Schema({
name: String,
rate: number
date: Date
})
But I wanna expend it to get:
var CompanySchema = new mongoose.Schema({
name: String,
currency: {
mxn: Number,
php: Number,
},
source: [String],
deliveryMethod: [String],
date: Date
})
For source, I want to get an array of inputs ex. ["bank", "debit card", "agent"]
and almost samething for deliverymethod.
But either my input is wrong or my schema, because the value for source saves as one long string, not a separated value.
Also, I think the way I designed the currency to have more currency rate is correct but I don't know how my input json should suppose to be.
I tried it in postman:
{
"name": "google",
"currency": {
"mxn": 20,
"php": 30
}
}
and this is the result i got:
{
"status": 201,
"data": {
"__v": 0,
"name": "google",
"date": "2017-12-06T22:38:45.896Z",
"_id": "5a2871752e3b7343dc388549",
"deliveryMethod": [
null
],
"source": [
null
]
},
"message": "Succesfully Created Company"
}
1- if my currency nested schema is correct how should be my post json file be?
2- how can I get source and deliveryMethod as an array of string?
The JSON in the request body should look like this:
{
"name": "google",
"currency": {
"mxn": 20,
"php": 30
},
"source": ["source1", "source 2", "source 3"],
"deliveryMethod": ["delMetd 1", "delMetd 2", "delMetd 3"],
"date": "2015-11-27T23:00:00Z"
}
I copy/pasted your code and tried with Postman. The response I got back was:
{
"__v": 0,
"name": "google",
"date": "2015-11-27T23:00:00.000Z",
"_id": "5a2915295c5f714f7cb25d90",
"deliveryMethod": [
"delMetd 1",
"delMetd 2",
"delMetd 3"
],
"source": [
"source1",
"source 2",
"source 3"
],
"currency": {
"mxn": 20,
"php": 30
}
}
If I connect to the database with the mongo shell and run db.companies.find().pretty() I get this result:
{
"_id" : ObjectId("5a2915295c5f714f7cb25d90"),
"name" : "google",
"date" : ISODate("2015-11-27T23:00:00Z"),
"deliveryMethod" : [
"delMetd 1",
"delMetd 2",
"delMetd 3"
],
"source" : [
"source1",
"source 2",
"source 3"
],
"currency" : {
"mxn" : 20,
"php" : 30
},
"__v" : 0
}
Your schema is fine. You can try dropping the collection (db.companies.drop()) if you can't get it to work. Start with a fresh one if you don't have any important data in it.