Ansible: Appending to the dictionaries skips duplicated key names - dictionary

I'm trying to populate dictionary from register output result.containers which happens to override the item.Image with same value.
Here is my output.
"result.containers": [
{
"Image": "lna-docker/webproxy:2.4.0",
"Names": [
"/se-webproxyui-dev-01"
],
},
{
"Image": "lna-docker-dev-local/webproxy:1.8.1",
"Names": [
"/se-webproxy-dev-01"
],
},
{
"Image": "docker-release/consul:1.0.1",
"Names": [
"/consul-client"
],
},
{
"Image": "docker.dev/webproxy:0.6.1",
"Names": [
"/webproxy-dev-01"
],
},
]
}
Here is my code.
- name: Populate dictonary for containerup
set_fact:
containeruplist: "{{ containeruplist|default({}) | combine({item.Image.split('/')[-1].split(':')[0]:item.Names[0][1:]} ) }}"
loop: "{{ result.containers }}"
here is my output
ok: [VM3node.lite.com] => {
"containeruplist": {
"consul": "consul-client",
"webproxy": "webproxy-dev-01"
}
}
I'm trying to populate dictionary from register output result.containers which happens to override the item.Image with same value. Any help would be greatly appreciated.
Ideally I should be getting below output. It's overriding the first two item.Image with value "webroxy" . Could someone help me achieve the below.
containeruplist": {
"webproxy":"se-webproxyui-dev-01"
"webproxy":"se-webproxy-dev-01"
"consul": "consul-client",
"webproxy": "webproxy-dev-01"
}

Related

JQ: Delete duplicate entry inplace

I am trying to delete a key whose value is duplicated elsewhere. That is I would like to delete all occurences(duplicates) after the first occurence. Here is a sample json file I am working with
{
"clouds":{
"finfolk-vmaas":{
"auth-types":[
"oauth1"
],
"endpoint":"http://10.125.0.10:5240/MAAS/",
"type":"maas"
},
"vsphere":{
"auth-types":[
"userpass"
],
"endpoint":"10.247.0.3",
"regions":{
"QA":{
"endpoint":"10.247.0.3"
}
},
"type":"vsphere"
}
}
}
I would like to get this after the deletion:
{
"clouds":{
"finfolk-vmaas":{
"auth-types":[
"oauth1"
],
"endpoint":"http://10.125.0.10:5240/MAAS/",
"type":"maas"
},
"vsphere":{
"auth-types":[
"userpass"
],
"endpoint":"10.247.0.3",
"regions":{
"QA":{}
},
"type":"vsphere"
}
}
}
Essentially I want to remove this duplicate key:pair "endpoint":"10.247.0.3" and leave the enclosing parentheses {}
Here is a simple jq query that I am trying to play with:
jq -cs 'unique_by(.endpoint)' clouds.json
For each object in .clouds[], this saves the object reduced to its enpoint as $endpoint, then recursively traverses to all child objects, from which, if it contains the previously stored endpoint, (only) the endpoint field will be deleted.
.clouds[] |= ({endpoint} as $endpoint | .[] |= walk(
(objects | select(contains($endpoint))) |= del(.endpoint)
))
{
"clouds": {
"finfolk-vmaas": {
"auth-types": [
"oauth1"
],
"endpoint": "http://10.125.0.10:5240/MAAS/",
"type": "maas"
},
"vsphere": {
"auth-types": [
"userpass"
],
"endpoint": "10.247.0.3",
"regions": {
"QA": {}
},
"type": "vsphere"
}
}
}
Demo

Combine multiple json to single json using jq

I am new to jq and stuck with this problem for a while. Any help is appreciable.
I have two json files,
In file1.json:
{
"version": 4,
"group1": [
{
"name":"olditem1",
"content": "old content"
}
],
"group2": [
{
"name":"olditem2"
}
]
}
And in file2.json:
{
"group1": [
{
"name" : "newitem1"
},
{
"name":"olditem1",
"content": "new content"
}
],
"group2": [
{
"name" : "newitem2"
}
]
}
Expected result is:
{
"version": 4,
"group1": [
{
"name":"olditem1",
"content": "old content"
},
{
"name" : "newitem1"
}
],
"group2": [
{
"name":"olditem2"
},
{
"name" : "newitem2"
}
]
}
Criterial for merge:
Has to merge only group1 and group2
Match only by name
I have tried
jq -S '.group1+=.group1|.group1|unique_by(.name)' file1.json file2.json
but this is filtering group1 and all other info are lost.
This approach uses INDEX to create a dictionary of unique elements based on their .name field, reduce to iterate over the group fields to be considered, and an initial state created by combining the slurped (-s) input files using add after removing the group fileds to be processed separately using del.
jq -s '
[ "group1", "group2" ] as $gs | . as $in | reduce $gs[] as $g (
map(del(.[$gs[]])) | add; .[$g] = [INDEX($in[][$g][]; .name)[]]
)
' file1.json file2.json
{
"version": 4,
"group1": [
{
"name": "olditem1",
"content": "new content"
},
{
"name": "newitem1"
}
],
"group2": [
{
"name": "olditem2"
},
{
"name": "newitem2"
}
]
}
Demo

jq: avoid empty arrays mapped field

Here my jq script:
def pick_nationality:
select(.NACIONALITAT) |
{nation: {country: .NACIONALITAT, code: "some code"} };
def pick_surname:
select(.SURNAME) |
{name: {surname: .SURNAME, code: "some code"} };
def pick_extension:
{ use: "official", extension: [pick_nationality, pick_surname] };
map(pick_extension)
Input json is like:
{
"SURNAME": "surname1"
}
{
"NACIONALITAT": "nacionalitat1"
}
However, sometimes any input objects don't contain any look up field:
{
"field1": "value1"
}
{
"field2": "value2"
}
Above script returns:
[
{
"use": "official",
"extension": []
},
{
"use": "official",
"extension": []
}
]
I'd like extension doesn't appear:
[
{
"use": "official"
},
{
"use": "official"
}
]
Any ideas?
You can simply add
| del(..|select(. == []))
as a trailing to your script in order to remove all such empty arrays
Demo
extend your function pick_extension for the desired output:
def pick_extension:
[pick_nationality, pick_surname] as $extension
| { use: "official" }
| if $extension | length > 0 then . + {extension: $extension} else . end;
If no extension could be picked, the empty array will no longer be added to the json object this way.

Map to an array within an object within an array

I am still having trouble understanding how to use the map function. In this case my payload is a JSON object that contains an array of "orders" with each "order" being an object... How do I create a map that would let me get to the array of "ContactEmailAddresses"?
{
"orders": [
{
"OrderGroupNumber": 1,
"Requester": {
"Name": "Mickey Mouse"
},
"ContactEmailAddresses": [
"user1#abc.com",
"user2#abc.com"
],
"CreatedByEmailAddress": "user1#abc.com"
},
{
"OrderGroupNumber": 2,
"Requester": {
"Name": "Donald Duck"
},
"ContactEmailAddresses": [
"user3#abc.com",
"user4#abc.com"
],
"CreatedByEmailAddress": "user3#abc.com"
},
{
"OrderGroupNumber": 3,
"Requester": {
"Name": "Goofy"
},
"ContactEmailAddresses": [
"user5#abc.com",
"user6#abc.com"
]
}
]
}
My current attempt that doesn't work is:
payload.*orders map (order, index) ->
{
order.contactEmailAddresses
}
%dw 2.0
output application/json
---
payload.orders flatMap $.ContactEmailAddresses
Output:
[
"user1#abc.com",
"user2#abc.com",
"user3#abc.com",
"user4#abc.com",
"user5#abc.com",
"user6#abc.com"
]

Ansible build a list of dictionaries and append to list within dictionary

Taking this cut down example set of inventory hostvars:
{
"_meta": {
"hostvars": {
"host-a.foo.com": {
"host_domain": "foo.com",
"subnet_address": "192.168.1.0",
"subnet_mask": "255.255.254.0"
},
"host-b.foo.com": {
"host_domain": "foo.com",
"subnet_address": "192.168.2.0",
"subnet_mask": "255.255.254.0"
},
"host-c.bar.com": {
"host_domain": "bar.com",
"subnet_address": "192.168.2.0",
"subnet_mask": "255.255.254.0"
}
}
}
}
I'm trying to produce something representing the following in ansible:
[
{
"192.168.1.0": {
"mask": "255.255.254.0",
"domains": [
"foo.com"
]
},
"192.168.2.0": {
"mask": "255.255.254.0",
"domains": [
"foo.com",
"bar.com"
]
}
}
]
So far I have this, but I'm unsure how to append to the domains list for each dictionary item (instead of overwriting it):
- name: inventory subnets
set_fact:
inventory_subnets: "{{ inventory_subnets | default({}) | combine({
hostvars[item].subnet_address: {
'mask': hostvars[item]['subnet_mask'],
'domains': [
# How to build this list?
]
}
}) }}"
loop: "{{ query('inventory_hostnames', 'all') }}"
Is it possible to perform another combine within a dictionary definition somehow?
The tasks below
- set_fact:
hostvars_list: "{{ hostvars_list|default([]) +
[{'host': item.key}|combine(item.value)] }}"
loop: "{{ hostvars|dict2items }}"
- set_fact:
subnets: "{{ subnets|default([]) +
[{item.0: {'mask': item.1|json_query('[].subnet_mask')|first,
'domains': item.1|json_query('[].host_domain')}}] }}"
loop: "{{ hostvars_list|groupby('subnet_address') }}"
- debug:
var: subnets
give
"subnets": [
{
"192.168.1.0": {
"domains": [
"foo.com"
],
"mask": "255.255.254.0"
}
},
{
"192.168.2.0": {
"domains": [
"foo.com",
"bar.com"
],
"mask": "255.255.254.0"
}
}
]

Resources