How to add items to an existing dictionary in Ansible? - list

I have a dictionary which is loaded by the following play:
- name: Get variables from ../main.yml and save them into dict
include_vars:
file: "../main.yml"
name: dict
"dict" contains the following:
"dict": {
"environments": {
"MYENV": {
"key1": "value1",
"key2": "value2"
},
"MYENV2": {
"key1": "value1",
"key2": "value2"
},
"MYENV3": {
"key1": "value1",
"key2": "value2"
}
}}
Question: How can I loop through this dictionary in Ansible and add a 3rd key "key3" with accompanied value to each entry in "environments"?
The desired situation would be a new_dict which contains the following:
"new_dict": {
"environments": {
"MYENV": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"MYENV2": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"MYENV3": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}}
With "value3" being a string built like "MYENV" + "value1" + "value2".

The decomposition of the directory is needed. Then {key3: value3} is added and the directory is combined again. The tasks below
vars:
add_this:
key3: value3
tasks:
- set_fact: # collect dictionary keys
keys: "{{ dict.environments|
dict2items|
json_query('[].key') }}"
- set_fact: # collect dictionary values and add item
values: "{{ dict.environments|
dict2items|
json_query('[].value')|
map('combine', add_this)|list }}"
- set_fact: # create dict environments
environments: "{{ environments|
default({})|
combine({item.0: item.1}) }}"
loop: "{{ keys|zip(values)|list }}"
- set_fact: # create dictionary new_dict
new_dict: "{{ new_dict|
default({})|
combine({'environments': environments}) }}"
- debug:
var: new_dict
give
"new_dict": {
"environments": {
"MYENV": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"MYENV2": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"MYENV3": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
}
Given the fact that all values are different, how can I dynamically create "value3" for each of the environments by e.g. appending the values of "key1" and "key2"?
With a couple of filters
$ cat filter_plugins/filter1.py
def custom_1(h):
return {'key3': h.values()}
def dict_merge(x, y, recursive=False):
if recursive:
z = dict(list(x.items()) + list(y.items()))
else:
z = x.copy()
z.update(y)
return z
def dict_keys(d):
return list(d)
class FilterModule(object):
def filters(self):
return {
'custom_1' : custom_1,
'dict_keys' : dict_keys,
'dict_merge' : dict_merge
}
the tasks below
tasks:
- set_fact:
env: "{{ env|default({})|
combine({item: dict.environments[item]|
dict_merge((dict.environments[item]|custom_1), True)
}) }}"
loop: "{{ dict.environments|dict_keys }}"
- set_fact:
new_dict: "{{ {}|combine({'environments': env}) }}"
- debug:
var: new_dict
give
"new_dict": {
"environments": {
"MYENV": {
"key1": "value1",
"key2": "value2",
"key3": [
"value2",
"value1"
]
},
"MYENV2": {
"key1": "value1",
"key2": "value2",
"key3": [
"value2",
"value1"
]
},
"MYENV3": {
"key1": "value1",
"key2": "value2",
"key3": [
"value2",
"value1"
]
}
}
}
Fit the custom_1 filter to your needs.

Related

how to send my list data at a particular index to another list's particular index in flutter

suppose my list 1 data is like this
[
{
key1: value1,
key2: value2,
key3: value3,
},
{
key1: value4,
key2: value5,
key3: value6,
},
.....
]
what if i want to send
{
key1: value4,
key2: value5,
key3: value6,
},
to updatedList at index 1
my code is:
updatedList[0]= List.from(widget.allDataList[1]);
void main() {
var list = [];
list =
[
{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
{
"key1": "value4",
"key2": "value5",
"key3": "value6",
},
];
List<Map<String, String>> updatedList=[];
updatedList.insert(0, list[0]);
print(updatedList);
}

type 'List<dynamic>' is not a subtype of type 'Map<dynamic, dynamic>' need to conver list of map as map

the result I got as List
[{name: john, voted: [{5fhh54522b5: 8}, {2cg128gsc4541: 822}]}, {name: Donald, voted: [{8br55rj25ns3j: 822}, {jfej4v85552: 1}]}, {name: Abraham, voted: []}, {name: Colly, voted: []}]
need to convert this data as below map as.....Map<dynamic,dynamic>
{name: john, voted: [{5fhh54522b5: 8}, {2cg128gsc4541: 822}]}, {name: Donald, voted: [{8br55rj25ns3j: 822}, {jfej4v85552: 1}]}, {name: Abraham, voted: []}, {name: Colly, voted: []}
From your gist, I modified the code as follows
void main() {
var dataList = jsonString;
Map<dynamic, dynamic> data = Map<dynamic, dynamic>();
dataList.forEach((item) {
if(item["voted"] != null) {
(item["voted"] as List).forEach((voteItem) {
if(voteItem != null) {
(voteItem as Map).forEach((key, val){
data[key] = val;
});
}
});
}
});
print(data);
//this what I need as reult
// {
// 60e6956078fb6f42da: 1,
// 60e6956020d8bf42db: 5,
// 120d8bf42dffsww66: 1,
// jd58466daa4dw2: 20,
// gg4c577x6ad8ds6a: 6
// }
}
const jsonString = [
{
"voted": [
{
"60e6956078fb6f42da": "1"
},
{
"60e6956020d8bf42db": "5"
}
],
"_id": "60e698fe78fb6120d8bf42dd",
"name": "donald"
},
{
"voted": [
{
"120d8bf42dffsww66": "1"
}
],
"_id": "60e698fe78fb6120d8bf42de",
"name": "barrack"
},
{
"voted": [
{
"jd58466daa4dw2": "20"
}
],
"_id": "60e698fe78fb6120d8bf42df",
"name": "malan"
},
{
"voted": [
{
"gg4c577x6ad8ds6a": "6"
}
],
"_id": "60e698fe78fb6120d8bf42e0",
"name": "kuma"
}
];
i don't think this is map
{name: john, voted: [{5fhh54522b5: 8}, {2cg128gsc4541: 822}]}, {name: Donald, voted: [{8br55rj25ns3j: 822}, {jfej4v85552: 1}]}, {name: Abraham, voted: []}, {name: Colly, voted: []}
they are multiple maps, not single map.
you can use list.asMap() function to convert list of any to map,
HI, i tried in dart pad, i can see that it is not valid json,
you have to convert it like this, after that it you will be able to parse the json string easily
voted :[ { id : '5fhh54522b5', count : '8'}, ]

How to take map values (key - value pairs), inside a list

I am stuck with this, I want to write 2 maps within the list. How do I do that? I tried this, but this doesn't work. Even instead of interface{}, I put string, it doesn't work.
var b := []interface{}{
{
"type" : "value1",
"target" : "value2",
},
{
"type" : "value3",
"target" : "value4",
}
}
var b = []interface{}{
map[string]string{
"type": "value1",
"target": "value2",
},
map[string]string{
"type": "value3",
"target": "value4",
},
}
or, if b can be of type []map[string]string
var b = []map[string]string{{
"type": "value1",
"target": "value2",
}, {
"type": "value3",
"target": "value4",
}}

How to modify an existing dictionary in ansible?

I'm trying to add an existing list to an existing dict in Ansible.
I have a dict "jbossvars" containing the following (ansible debug)
"jbossvars": {
"environments": {
"TEST_ENV": {
"key1": "value1",
"key2": "value2"
},
"TEST_ENV2": {
"key1": "value1",
"key2": "value2"
}
}
}
and a list "env_homes" containing the following (ansible debug)
"env_homes": [
"/opt/redhat/jboss-7.2.0/TEST_ENV",
"/opt/redhat/jboss-7.2.0/TEST_ENV2"
]
which I want to combine to a new dictionary "new_dict"
"jbossvars": {
"environments": {
"TEST_ENV": {
"key1": "value1",
"key2": "value2",
"key3": "/opt/redhat/jboss-7.2.0/TEST_ENV"
},
"TEST_ENV2": {
"key1": "value1",
"key2": "value2",
"key3": "/opt/redhat/jboss-7.2.0/TEST_ENV2"
}
}
}
The following play does not give me the desired situation:
- name: Create dict to append
set_fact:
env_homes: "{{ {'TEST_ENV': [ jbossvars.environments.TEST_ENV ] + env_homes} }}"
- name: Insert created dict into existing dict and save it into a new variable newdict
set_fact:
newdict: "{{ jbossvars.environments|combine(env_homes) }}"
- debug: var: newdict
To get the result
TEST_ENV: { "a": 1, "b": [ 2, "x1", "x2" ] }
The play below
vars:
TEST_ENV:
a: 1
b: 2
add_this:
c: [ x1, x2 ]
tasks:
- set_fact:
add_this: "{{ {'b': [ TEST_ENV.b ] + add_this.c} }}"
- set_fact:
TEST_ENV: "{{ TEST_ENV|combine(add_this) }}"
- debug:
var: TEST_ENV
gives
"TEST_ENV": {
"a": 1,
"b": [
2,
"x1",
"x2"
]
}

Ansible - check if item in a list of dictionaries is present in other list of dictionaries

How to check if an object of a list of dictionaries is present in another list of dictionaries (with Ansible?)
You could try jinja filters selectattr - I had an issue with using it, so I did revert to a simplified but ugly solution - build a filtered list and compare filtered attributes only (list-to-list).
I do not like it, but it works.
Let me know if you know other way.
playbook:
- name: find existing system_crontabs #would generate a list of dict
find:
path: /var/spool/cron/crontabs/
register: system_side_crontabs
become: True
- name: create lists of system_cron_names and repo_cron_names
set_fact:
system_cron_names: "[]"
repo_cron_names: "[]"
- name: build list of system_cron_names
set_fact:
system_cron_names: "{{ system_cron_names }} + [ '{{ item.path |basename }}' ]"
with_items: "{{ system_side_crontabs.files }}"
- name: build lists of repo_cron_names
set_fact:
repo_cron_names: "{{ repo_cron_names }} + [ '{{ item.user }}' ]"
with_items: "{{ crontabs }}"
- name: assert check if an object of system_crontab is defined in repo_crontab
assert:
that: "{{ [item] |intersect(repo_cron_names) | length }} == 1"
with_items: "{{ system_cron_names }}"
hosts_vars/prd-inner-mgmt202 #a list of dictionaries
crontabs:
- user: root
crontab_rules: |
11 1 * * * find /home/ansible/.ansible/tmp/ -atime +10 -delete
a result of find
ok: [prd-inner-mgmt202] => {
"changed": false,
"examined": 1,
"files": [ ### List of dictionary
{
"path": "/var/spool/cron/crontabs/root",
},
{
"path": "/var/spool/cron/crontabs/another_file",
}
],
"invocation": {
"module_args": {
"age": null,
"age_stamp": "mtime",
"contains": null,
"file_type": "file",
"follow": false,
"get_checksum": false,
"hidden": false,
"path": "/var/spool/cron/crontabs/",
"paths": [
"/var/spool/cron/crontabs/"
],
"patterns": [
"*"
],
"recurse": false,
"size": null,
"use_regex": false
},
"module_name": "find"
},
"matched": 1,
"msg": ""
}
generate a list of strings that are easy to compare
TASK [mid_crontab : build list of system_cron_names] **************************
"ansible_facts": {
"system_cron_names": [
"root",
]
},
"changed": false,
"invocation": {
"module_args": {
"system_cron_names": [
"root"
]
},
"module_name": "set_fact"
},
generate another list of strings
TASK [mid_crontab : build list of repo_cron_names] *****************************
ok: [prd-inner-mgmt202] => (item={u'crontab_rules': u'11 1 * * * find /home/ansible/.ansible/tmp/ -atime +10 -delete\n', u'user': u'root'}) => {
"ansible_facts": {
"repo_cron_names": [
"root"
]
},
"changed": false,
"invocation": {
"module_args": {
"repo_cron_names": [
"root",
"other"
]
},
"module_name": "set_fact"
},
"item": {
"crontab_rules": "11 1 * * * find /home/ansible/.ansible/tmp/ -atime +10 -delete\n",
"user": "root"
}
}
Assert the required check, use intersect jinja filter. In my case a system defined object (cron record) should exist in my repository - so the list should have 1 element.
TASK [mid_crontab : assert check if system_crontab is defined in repo_crontab] *
ok: [prd-inner-mgmt202] => (item=root) => {
"changed": false,
"invocation": {
"module_args": {
"that": "1 == 1"
},
"module_name": "assert"
},
"item": "root",
"msg": "All assertions passed"
}
Seems you want to reduce original dict to list of strings (names) and compare the difference:
---
- hosts: localhost
gather_facts: no
vars:
crontabs:
- user: root
crontab_rules: xxx
tasks:
- find:
path: /tmp/test
register: myfiles
- assert:
that: sys_crons_violation | count == 0
msg: "This crons are not defined in repo : {{ sys_crons_violation | join(', ') }}"
vars:
sys_crons: "{{ myfiles.files | map(attribute='path') | map('basename') | list }}"
repo_crons: "{{ crontabs | map(attribute='user') | list }}"
sys_crons_violation: "{{ sys_crons | difference(repo_crons) }}"
result:
TASK [find] ************************
TASK [assert] **********************
fatal: [localhost]: FAILED! => {
"assertion": "sys_crons_violation | count == 0",
"changed": false,
"evaluated_to": false,
"msg": "This crons are not defined in repo : another_file"
}