Merge List of Dictionary using ansible - json

I am trying to merge two list of dictionaries.
"my_name":
[ {
"name": "xyz",
"number": "123" },
{
"name": "abc",
"number": "456"
}
]
"my_address":
[ {
"name": "abc",
"address": "smith street" },
{
"name": "xyz",
"number": "ray street"
}
]
Required Output:
merged:
[ {
"name": "abc",
"address": "smith street",
"number": "456" },
{
"name": "xyz",
"address": "ray street",
"number": "123"
}
]
I tried using combine but it would just combine the last item.
set_fact:
merged: "{{ my_name | combine(my_address) }}"
"merged":
[
{
"name": "xyz",
"number": "ray street",
"number": "123"
}
]
i used the debug module. debug: msg: "{{ my_name| list_mergeby(my_address,'name')}}" The error was: template error while templating string: no filter named 'lists_mergby,

For example, given the fixed my_address
- hosts: localhost
vars:
my_name:
- name: xyz
number: '123'
- name: abc
number: '456'
my_address:
- name: abc
address: smith street
- name: xyz
address: ray street
merged: "{{ [my_name, my_address]|community.general.lists_mergeby('name') }}"
tasks:
- debug:
var: merged
gives (abridged)
merged:
- address: smith street
name: abc
number: '456'
- address: ray street
name: xyz
number: '123'
See: the filter community.general.lists_mergeby

Related

Insert data type JSON in lighthouse php

I´m working in back graphql API with Laravel and Lighthouse.
I have a table with a column named "config" that stores json data.
I´m trying to create a new register to that table.
I have a mutation:
createOrderTemplate(name: String!, config: JSON!): OrderTemplate #create
The schema is:
type OrderTemplate {
id: ID!
name: String!
config: JSON!
}
I´ve tried the mutation in graphql-playground
mutation{
createOrderTemplate(
name:"SomeName",
config:
[{
"w_name": "Name1",
"w_code": "001",
"place": "Place1",
"job": "job1",
"data": [
{
"name": "name1",
"quantity": 2
},
{
"name": "name2",
"quantity": 2
},
{
"name": "name3",
"quantity": 1
},
{
"name": "name4",
"quantity": 2
}
]
},
{
"w_name": "Name2",
"w_code": "002",
"place": "Place2",
"job": "job2",
"data": [
{
"name": "name1",
"quantity": 2
},
{
"name": "name2",
"quantity": 2
},
{
"name": "name3"
"quantity": 1
},
{
"name": "name4",
"quantity": 2
}
]
}]
){
id
name
config
}
When I typed this I get an error, all is colored red and it does not execute anything.
What am I doing wrong?
Firstly, try to run that query in Insomnia, so you could see the exception that is thrown.
Moreover, I don't think that config gets a valid JSON value. Try first with a simple JSON like {key: 'value'}

Get specific list of dict from json content using Ansible

I spend a lot of times to finally didn't get what I need, my request is so complicated then I prefer share with you my concern::
I have this json.content to pars it:
"json": {
"content": [
{
"name": "machine1",
"hasChildren": false,
"resourceData": {
"entries": [
{
"value": {
"type": "string",
"value": "Red Hat Enterprise Linux 7 (64-bit)"
},
"key": "MachineGuestOperatingSystem"
},
{
"value": {
"type": "string",
"value": "Folder1"
},
"key": "VMware.VirtualCenter.Folder"
},
{
"value": {
"type": "boolean",
"value": true
},
"key": "Destroy"
}
]
}
},
{
"name": "machine2",
"hasChildren": false,
"resourceData": {
"entries": [
{
"value": {
"type": "string",
"value": "Red Hat Enterprise Linux 7 (64-bit)"
},
"key": "MachineGuestOperatingSystem"
},
{
"value": {
"type": "string",
"value": "Folder2"
},
"key": "VMware.VirtualCenter.Folder"
},
{
"value": {
"type": "boolean",
"value": false
},
"key": "Destroy"
}
]
}
},
{
"name": "machine3",
"hasChildren": false,
"resourceData": {
"entries": [
{
"value": {
"type": "string",
"value": "Windows Server 2016 or later (64-bit)"
},
"key": "MachineGuestOperatingSystem"
},
{
"value": {
"type": "string",
"value": "Folder3"
},
"key": "VMware.VirtualCenter.Folder"
},
{
"value": {
"type": "boolean",
"value": true
},
"key": "Destroy"
}
]
}
}
]
}
and I'd like to have as output Something like:
[{"name":"machine1", "OsName": "Red Hat Enterprise Linux 7 (64-bit)", "Folder": "Folder1"}, {"name":"machine2", "OsName": "Red Hat Enterprise Linux 7 (64-bit)", "Folder": "Folder2"},
{"name":"machine3", "OsName": "Windows Server 2016 or later (64-bit)", "Folder": "Folder3"}]
I tried all the solutions but no way, all result not what I want to expect. someone can help me to find a solution to get this attended result
The task below does the job
- set_fact:
_list: "{{ json.content|json_query(query) }}"
vars:
query: "[].{name: name,
OsName: resourceData.entries[0].value.value,
Folder: resourceData.entries[1].value.value}"
gives
_list:
- Folder: Folder1
OsName: Red Hat Enterprise Linux 7 (64-bit)
name: machine1
- Folder: Folder2
OsName: Red Hat Enterprise Linux 7 (64-bit)
name: machine2
- Folder: Folder3
OsName: Windows Server 2016 or later (64-bit)
name: machine
Q: "It changes the order of (key, value), so referencing by [0] or [1] will be not the same."
A: Select the items by the keys. You'll have to pipe the results and select the first items of the selected lists, e.g. the task below gives the same results
- set_fact:
_list: "{{ json.content|json_query(query) }}"
vars:
query: "[].{name: name,
OsName: resourceData.entries[?key==`MachineGuestOperatingSystem`].value.value|[0],
Folder: resourceData.entries[?key==`VMware.VirtualCenter.Folder`].value.value|[0]}"
Q: "Filter 'Red Hat ...' Get output"
- Folder: Folder1
OsName: Red Hat Enterprise Linux 7 (64-bit)
name: machine1
- Folder: Folder2
OsName: Red Hat Enterprise Linux 7 (64-bit)
name: machine2
A: Use selectattr, e.g. the task below does the job
- debug:
msg: "{{ _list|
selectattr('OsName', 'eq', 'Red Hat Enterprise Linux 7 (64-bit)')|
list }}"
Q: "Where I can learn this kind of search?"
A: There are examples in JMESPath Specification. As a hint, see the code below on how to translate these examples into Ansible json_query
Example1
- name: 'search(foo, {"foo": "value"}) -> "value"'
debug:
msg: "{{ _dict|json_query(_query) }}"
vars:
_dict: {"foo": "value"}
_query: "foo"
Example2
- name: 'search(foo[?bar==`10`], {"foo": [{"bar": 1}, {"bar": 10}]}) -> [{"bar": 10}]'
debug:
msg: "{{ _dict|json_query(_query) }}"
vars:
_dict: {"foo": [{"bar": 1}, {"bar": 10}]}
_query: "foo[?bar==`10`]"
Example3
- name: 'search(foo | bar, {"foo": {"bar": "baz"}}) -> "baz"'
debug:
msg: "{{ _dict|json_query(_query) }}"
vars:
_dict: {"foo": {"bar": "baz"}}
_query: "foo | bar"

jq filtering - Cannot index array with string "Score"

I am trying to find person name who has a subject and it score.
But i am getting index array.
This problem is different then other questions asked on Stackoverflow because it throws error for the parameter which is not in [] but in {}
jq -r '.[] | select(.result."*value*".Score.English) | {Name: .result."*value*".name, Subject: .result."*value*".Score.English} | #text' test.txt | sed 's/^{\|}$//g; s/,/\n/'
INPUT JSON FILE
[{
"host": "testserver",
"hostclass": "Unknown",
"result": {
"*value*": [
{
"sessionId": "000001",
"name": "ABC",
"Age": "21",
"Score": {
"English": "A+",
"Mathematics": "B-",
"String Theory": "C+"
}
},
{
"sessionId": "000001",
"name": "CDE",
"Age": "21",
"Score": {
"English": "A-",
"German": "B-",
"French": "C+"
}
},
{
"sessionId": "000001",
"name": "EFG",
"Age": "21",
"Score": {
}
},
{
"sessionId": "000001",
"name": "XYZ",
"Age": "21"
}]
}
}]
OUTPUT :
Name: ABC
Subject : A+
Name: CDE
Subject : A-
ERROR :
jq: error (at test.txt:39): Cannot index array with string "Score"
how can i fix this error?
You need to expand arrays to access elements in them,
You don't need sed at all.
$ jq -r '.[].result."*value*"[] | select(.Score.English) | "Name: \(.name)", "Subject: \(.Score.English)"' file
Name: ABC
Subject: A+
Name: CDE
Subject: A-
EFG Score is of length 0 that probably doesn't help :
"sessionId": "000001",
"name": "EFG",
"Age": "21",
"Score": {}
So it chokes when trying to evaluate :
Subject: .result."*value*".Score.English

JSON query for finding the newest snapshot for host and device?

I am trying to find the newest snapshot for a device and host in AWS with the aws ec2 command. I am getting the following output from aws ec2 describe-snapshots.
As you can see I can have several snapshots for the same host (see Tags with Keys hostname and devicename) and device. The start time differs.
{
"Snapshots": [
{
"Description": "My desc.",
"Encrypted": false,
"VolumeId": "vol-aaa",
"State": "completed",
"VolumeSize": 8,
"StartTime": "2018-02-02T19:27:56.000Z",
"Progress": "100%",
"OwnerId": "5674567",
"SnapshotId": "snap-xxx"
},
{
"Description": "host1.domain.com - sdc",
"Tags": [
{
"Value": "SNAP1",
"Key": "Name"
},
{
"Value": "sdc",
"Key": "devicename"
},
{
"Value": "host1.domain.com",
"Key": "hostname"
}
],
"Encrypted": false,
"VolumeId": "vol-xxx",
"State": "completed",
"VolumeSize": 140,
"StartTime": "2018-09-21T08:39:58.000Z",
"Progress": "100%",
"OwnerId": "345634563456",
"SnapshotId": "snap-xxx"
},
{
"Description": "host1.domain.com - sdc",
"Tags": [
{
"Value": "SNAP2",
"Key": "Name"
},
{
"Value": "sdc",
"Key": "devicename"
},
{
"Value": "host1.domain.com",
"Key": "hostname"
}
],
"Encrypted": false,
"VolumeId": "vol-xxx",
"State": "completed",
"VolumeSize": 140,
"StartTime": "2018-09-22T08:39:58.000Z",
"Progress": "100%",
"OwnerId": "345634563456",
"SnapshotId": "snap-xxx"
}
}
How would I query this JSON in Ansible to get the newest snapshot for the hostname and device? I don't do this often so struggle with the query syntax.
Until now I have the following.
- shell: "aws ec2 describe-snapshots"
register: snap
delegate_to: localhost
- debug:
msg: "{{ snap.stdout | from_json | json_query(query) }}"
vars:
query: "Snapshots[].Tags[?Key=='hostname'].Value"
But how do I select all snapshot elements where Tags.Value is equal to a certain value where Key is "hostname"? And how do I then select the newest from the list I get?
According to the fine manual, JMESPath supports nested bracket specifier expressions:
vars:
snap: |
{
"Snapshots": [
{"Id": "aaa", "Tags": [{"Key": "hostname", "Value": "alpha"}]},
{"Id": "bbb", "Tags": [{"Key": "hostname", "Value": "beta"}]}
]
}
jq: "Snapshots[? Tags[? Key=='hostname' && Value=='alpha']].Id"
tasks:
- debug:
msg: "{{ snap | from_json | json_query(jq) }}"
As for the "for a certain host" part, that vars: query: is subject to jinja2 interpolation just like every other ansible string, thus:
vars:
query: ... [? Value=='{{ the_hostname }}' ] ...
Just be careful to ensure the value is correctly escaped -- which likely won't be a problem with a hostname, but I mean in general.
Then, as for the "newest from the list" part, ISO8601 has the very pleasing side benefit of sorting lexigraphically, so:
vars:
jq: "Snapshots[? Tags[? Key=='hostname' && Value=='alpha']]"
tasks:
- debug:
msg: "{{ snap | from_json | json_query(jq) | sort(attribute='StartTime', reverse=True) }}"

How to filter JSON data in Ansible?

I'm querying an API with Ansible command's command. The API returns a JSON object with network information.
I'd like to get a server's private ip based on its public ip. I know this is possible with JSON query filter but I can't figure out how.
The code:
- name: Get RPN topology
command: 'curl -X GET -H "Authorization: Bearer {{ onlineApiToken }}" "https://api.online.net/api/v1/rpn/group"'
register: RPN
delegate_to: 127.0.0.1
This is what RPN.stdout output looks like:
TASK [debug] ****************************************************************************************
ok: [ps1] => {
"changed": false,
"msg": [
{
"id": 7406,
"members": [
{
"id": 0000,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
},
{
"id": 1111,
"ip": "y.y.y.y",
"owner": "buzut",
"private_ip": "10.91.120.148",
"speed": 100,
"status": "active"
},
{
"id": 2222,
"ip": "z.z.z.z",
"owner": "buzut",
"private_ip": "10.91.165.215",
"speed": 1000,
"status": "active"
}
],
"name": "MySQL",
"owner": "buzut",
"shared": false,
"status": "updating"
}
]
}
The question: how do I get a server's private ip, based on its public one?
You probably want to take some time to read through the JMESPath Examples to familiarize yourself with the syntax supported by the json_query filter. The following gives you the result you want:
- hosts: localhost
gather_facts: false
vars:
RPN:
stdout: >-
[
{
"id": 7406,
"members": [
{
"id": 0,
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
},
{
"id": 1111,
"ip": "y.y.y.y",
"owner": "buzut",
"private_ip": "10.91.120.148",
"speed": 100,
"status": "active"
},
{
"id": 2222,
"ip": "z.z.z.z",
"owner": "buzut",
"private_ip": "10.91.165.215",
"speed": 1000,
"status": "active"
}
],
"name": "MySQL",
"owner": "buzut",
"shared": false,
"status": "updating"
}
]
tasks:
- name: lookup server based on public ip
debug:
var: item
with_items: "{{RPN.stdout|from_json|json_query(public_to_private_ip)}}"
vars:
public_to_private_ip: >-
[].members[?ip=='{{ public_ip }}'].private_ip
If I call this like:
ansible-playbook playbook.yml -e public_ip=y.y.y.y
I get:
TASK [lookup server based on public ip] ****************************************
ok: [localhost] => (item=10.91.120.148) => {
"item": "10.91.120.148"
}
And if I call it as:
ansible-playbook playbook.yml -e public_ip=z.z.z.z
I get:
TASK [lookup server based on public ip] ****************************************
ok: [localhost] => (item=10.91.165.215) => {
"item": "10.91.165.215"
}
---
- name: play1
hosts: localhost
gather_facts: false
vars:
public_ip: "x.x.x.x"
tasks:
- name: Print data
debug: var=RPN
- name: Lookup value in json var
debug: var=item
with_items: "{{RPN|json_query(public_to_private_ip)}}"
vars:
public_to_private_ip: "members[?ip=='{{ public_ip }}'].private_ip"
Gives you:
PLAY [play1] *******************************************************************
TASK [Print data] **************************************************************
ok: [localhost] => {
"RPN": {
"id": 7406,
"members": [
{
"id": "0000",
"ip": "x.x.x.x",
"owner": "buzut",
"private_ip": "10.91.154.39",
"speed": 100,
"status": "active"
},
{
"id": 1111,
"ip": "y.y.y.y",
"owner": "buzut",
"private_ip": "10.91.120.148",
"speed": 100,
"status": "active"
},
{
"id": 2222,
"ip": "z.z.z.z",
"owner": "buzut",
"private_ip": "10.91.165.215",
"speed": 1000,
"status": "active"
}
],
"name": "MySQL",
"owner": "buzut",
"shared": false,
"status": "updating"
}
}
TASK [Lookup value in json var] ************************************************
ok: [localhost] => (item=10.91.154.39) => {
"item": "10.91.154.39"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
Where members[?ip=='{{ public_ip }}'].private_ip does the magic.