Ansible - How to extract specific keys from a List of Dictionary by iterating through another List [edit] - ansible

I have a list of server names and a List of dicts for all clusters in an environment. The List of dictionaries contains the relevant servers in that cluster. e.g.
"full_cluster_dict": [
{
"key": "cluster_a",
"value": [
"ca_server1",
"ca_server2",
"ca_server3",
"ca_server4",
"ca_server5",
"ca_server6",
"ca_server7",
"ca_server8"
]
},
{
"key": "cluster_b",
"value": [
"cb_server1",
"cb_server2",
"cb_server3"
]
},
{
"key": "cluster_c",
"value": [
"cc_server1",
"cc_server2",
"cc_server3",
"cc_server4"
]
}
and
"server_list": [
"ca_server1",
"cb_server2",
"ca_server6"
]
I would like to create a smaller list of dicts showing only clusters that contain servers from server_list . e.g.
"needed_cluster_dict": [
{
"key: "cluster_a",
"value": [
"ca_server1",
"ca_server2",
"ca_server3",
"ca_server4",
"ca_server5",
"ca_server6",
"ca_server7",
"ca_server8"
]
},
{
"key": "cluster_b",
"value" : [
"cb_server1",
"cb_server2",
"cb_server3"
]
}
]
I tried the following
- name: extract only relevant clusters based on the list of servers
ansible.builtin.set_fact:
needed_cluster_dict: "{{ needed_cluster_dict|d({}) | combine({item: cluster_filter}) }}"
with_items: "{{ server_list }}"
vars:
cluster_filter: "{{ sds_dict|dict2items|json_query(_query) }}"
_query: '[?value.contains(#, `{{ item }}`)].value'`
but this only returns a dictionary where the server names above are the keys and each key contains a list of servers e.g.
needed_cluster_list: {
"ca_server1: [
"ca_server1",
"ca_server2",
"ca_server3",
"ca_server4"
],
"ca_server2: [
"ca_server1",
"ca_server2",
"ca_server3",
"ca_server4"
],
...
...
}
Apologies for the edit from my original question but after asking, i discovered it's easier to loop through a list of Dictionaries than it is to loop through a Dictionary.

Given the list full_cluster_list (erroneously marked as dictionary full_cluster_dict in the question)
full_cluster_list:
- key: cluster_a
value:
- ca_server1
- ca_server2
- ca_server3
- ca_server4
- ca_server5
- ca_server6
- ca_server7
- ca_server8
- key: cluster_b
value:
- cb_server1
- cb_server2
- cb_server3
- key: cluster_c
value:
- cc_server1
- cc_server2
- cc_server3
- cc_server4
Convert the list to a dictionary
full_cluster_dict: "{{ full_cluster_list|items2dict }}"
gives the dictionary used in the answer below
full_cluster_dict:
cluster_a:
- ca_server1
- ca_server2
- ca_server3
- ca_server4
- ca_server5
- ca_server6
- ca_server7
- ca_server8
cluster_b:
- cb_server1
- cb_server2
- cb_server3
cluster_c:
- cc_server1
- cc_server2
- cc_server3
- cc_server4
Q: "Extract specific keys from a list of dictionaries."
A: Create a list of needed clusters. Test the intersection of the lists
needed_cluster_str: |
[{% for k,v in full_cluster_dict.items() %}
{% if v|intersect(server_list)|length > 0 %}
{{ k }},
{% endif %}
{% endfor %}]
needed_cluster: "{{ needed_cluster_str|from_yaml }}"
gives
needed_cluster:
- cluster_a
- cluster_b
Extract the needed lists
needed_cluster_lists: "{{ needed_cluster|map('extract', full_cluster_dict)|list }}"
gives
needed_cluster_lists:
- - ca_server1
- ca_server2
- ca_server3
- ca_server4
- ca_server5
- ca_server6
- ca_server7
- ca_server8
- - cb_server1
- cb_server2
- cb_server3
Create the dictionary
needed_cluster_dict: "{{ dict(needed_cluster|zip(needed_cluster_lists)) }}"
gives
needed_cluster_dict:
cluster_a:
- ca_server1
- ca_server2
- ca_server3
- ca_server4
- ca_server5
- ca_server6
- ca_server7
- ca_server8
cluster_b:
- cb_server1
- cb_server2
- cb_server3
Example of a complete playbook for testing
- hosts: localhost
vars:
server_list: [ca_server1, cb_server2, ca_server6]
full_cluster_dict:
cluster_a:
- ca_server1
- ca_server2
- ca_server3
- ca_server4
- ca_server5
- ca_server6
- ca_server7
- ca_server8
cluster_b:
- cb_server1
- cb_server2
- cb_server3
cluster_c:
- cc_server1
- cc_server2
- cc_server3
- cc_server4
needed_cluster_str: |
[{% for k,v in full_cluster_dict.items() %}
{% if v|intersect(server_list)|length > 0 %}
{{ k }},
{% endif %}
{% endfor %}]
needed_cluster: "{{ needed_cluster_str|from_yaml }}"
needed_cluster_lists: "{{ needed_cluster|map('extract', full_cluster_dict)|list }}"
needed_cluster_dict: "{{ dict(needed_cluster|zip(needed_cluster_lists)) }}"
tasks:
- debug:
var: needed_cluster
- debug:
var: needed_cluster_lists
- debug:
var: needed_cluster_dict

Related

Ansible: Merge 2 lists using common key

I have a use case where I need to merge 2 lists on common key name using Ansible.
List1:
{
"poc-cu2": [
"40:A6:B7:5E:22:11",
"40:A6:B7:5E:22:22"
],
"test2211": [
"40:A6:B7:5E:33:11",
"40:A6:B7:5E:33:22"
],
"test2244": [
"40:A6:B7:5E:22:45",
"40:A6:B7:5E:22:46"
]
}
List2:
{
"poc-cu2": [
"root",
"9WKA3KK3XN39",
"9.3.13.44"
],
"test2211": [
"root2211",
"221122112211",
"9.3.13.82"
]
}
Expected:
List3:
{
"poc-cu2": [
"root",
"9WKA3KK3XN39",
"9.3.13.44",
"40:A6:B7:5E:22:11",
"40:A6:B7:5E:22:22"
],
"test2211": [
"root2211",
"221122112211",
"9.3.13.82",
"40:A6:B7:5E:33:11",
"40:A6:B7:5E:33:22"
]
}
I got how to merge 2 lists using unique key but on my case I need to merge only on common key, please suggest.
You can get most of what you want using the combine filter, like this:
- hosts: localhost
gather_facts: false
tasks:
- set_fact:
dict3: "{{ dict1|combine(dict2, list_merge='append') }}"
- debug:
var: dict3
This will produce:
TASK [debug] *******************************************************************
ok: [localhost] => {
"dict3": {
"poc-cu2": [
"40:A6:B7:5E:22:11",
"40:A6:B7:5E:22:22",
"root",
"9WKA3KK3XN39",
"9.3.13.44"
],
"test2211": [
"40:A6:B7:5E:33:11",
"40:A6:B7:5E:33:22",
"root2211",
"221122112211",
"9.3.13.82"
],
"test2244": [
"40:A6:B7:5E:22:45",
"40:A6:B7:5E:22:46"
]
}
}
If you want the final result to consist of only the keys common to both
dictionaries it gets a little trickier, but this seems to work:
- hosts: localhost
gather_facts: false
tasks:
- set_fact:
dict3: "{{ dict3|combine({item: dict1[item] + dict2[item]}) }}"
when: item in dict2
loop: "{{ dict1.keys() }}"
vars:
dict3: {}
- debug:
var: dict3
Which produces:
TASK [debug] *******************************************************************
ok: [localhost] => {
"dict3": {
"poc-cu2": [
"40:A6:B7:5E:22:11",
"40:A6:B7:5E:22:22",
"root",
"9WKA3KK3XN39",
"9.3.13.44"
],
"test2211": [
"40:A6:B7:5E:33:11",
"40:A6:B7:5E:33:22",
"root2211",
"221122112211",
"9.3.13.82"
]
}
}
The above works by iterating over the keys in dict1, and for each
key from dict1 that also exists in dict2, we synthesize a new
dictionary containing the corresponding values from both dict1 and dict2 and then merge it into our final dictionary using the combine filter.
Given the data
dict1:
poc-cu2:
- 40:A6:B7:5E:22:11
- 40:A6:B7:5E:22:22
test2211:
- 40:A6:B7:5E:33:11
- 40:A6:B7:5E:33:22
test2244:
- 40:A6:B7:5E:22:45
- 40:A6:B7:5E:22:46
dict2:
poc-cu2:
- root
- 9WKA3KK3XN39
- 9.3.13.44
test2211:
- root2211
- '221122112211'
- 9.3.13.82
Iteration is not needed. Put the declarations below as appropriate. The dictionary dict_cmn keeps the merged common attributes of dict1 and dict2
dict_1_2: "{{ dict1|combine(dict2, list_merge='append') }}"
keys_cmn: "{{ dict1.keys()|intersect(dict2.keys()) }}"
vals_cmn: "{{ keys_cmn|map('extract', dict_1_2) }}"
dict_cmn: "{{ dict(keys_cmn|zip(vals_cmn)) }}"
give
dict_1_2:
poc-cu2:
- 40:A6:B7:5E:22:11
- 40:A6:B7:5E:22:22
- root
- 9WKA3KK3XN39
- 9.3.13.44
test2211:
- 40:A6:B7:5E:33:11
- 40:A6:B7:5E:33:22
- root2211
- '221122112211'
- 9.3.13.82
test2244:
- 40:A6:B7:5E:22:45
- 40:A6:B7:5E:22:46
keys_cmn:
- poc-cu2
- test2211
vals_cmn:
- - 40:A6:B7:5E:22:11
- 40:A6:B7:5E:22:22
- root
- 9WKA3KK3XN39
- 9.3.13.44
- - 40:A6:B7:5E:33:11
- 40:A6:B7:5E:33:22
- root2211
- '221122112211'
- 9.3.13.82
dict_cmn:
poc-cu2:
- 40:A6:B7:5E:22:11
- 40:A6:B7:5E:22:22
- root
- 9WKA3KK3XN39
- 9.3.13.44
test2211:
- 40:A6:B7:5E:33:11
- 40:A6:B7:5E:33:22
- root2211
- '221122112211'
- 9.3.13.82

Create dictionary keys from variable and add list of IPs as values

I would like to create a dictionary and populated from variables both the keys and values. The values will be a list of IPs.
If the key is already present in the dictionary, then, I need to add the IP to the existing list.
Here is the input data, which is a list of list.
parse1.json:
[
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_80",
"properties",
"members",
"/Common/10.50.100.25:80",
"session"
],
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_80",
"properties",
"members",
"/Common/10.50.100.39:80",
"session"
],
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_80",
"properties",
"members",
"/Common/10.50.100.49:80",
"session"
],
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_443",
"properties",
"members",
"/Common/10.50.100.18:80",
"session"
],
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_443",
"properties",
"members",
"/Common/10.50.100.28:80",
"session"
],
[
"/RAD33G4099/mobile_app/pl_crad.la-dc.vivo.com_443",
"properties",
"members",
"/Common/10.50.100.48:80",
"session"
]
]
Here is my trial at solving it:
- set_fact:
my_dic: {}
disabled_host: "{{ lookup('file', 'parse1.json') }}"
- name: add new key / value pairs to dict
set_fact:
my_dict_var: "{{ my_dict_var + [ my_dic | combine ( { name + '_' + app_name : host } , recursive=True) ] }}"
loop: "{{ disabled_host }}"
vars:
name: "{{ item[0] | regex_replace('^\/.*\/(.*)$', '\\1') }}"
app_name: "{{ item[0] | regex_replace('^\/.*\/(.*)\/.*$', '\\1') }}"
host: "{{ item[3] | regex_replace('^\/.*\/(.*):.*$', '\\1') }}"
The actual output is
ok: [localhost] => {
"msg": [
{
"pl_crad.la-dc.vivo.com_80_mobile_app": "10.50.100.25"
},
{
"pl_crad.la-dc.vivo.com_80_mobile_app": "10.50.100.39"
},
{
"pl_crad.la-dc.vivo.com_80_mobile_app": "10.50.100.49"
},
{
"pl_crad.la-dc.vivo.com_443_mobile_app": "10.50.100.18"
},
{
"pl_crad.la-dc.vivo.com_443_mobile_app": "10.50.100.28"
},
{
"pl_crad.la-dc.vivo.com_443_mobile_app": "10.50.100.48"
}
]
}
But, I would like to create a list of IPs if the key is same.
My desired output is
{
"pl_crad.la-dc.vivo.com_80_mobile_app": [
"10.50.100.25",
"10.50.100.39",
"10.50.100.49"
],
"pl_crad.la-dc.vivo.com_443_mobile_app": [
"10.50.100.18",
"10.50.100.28",
"10.50.100.48"
]
}
You don't have to go the hard way and use regex, you can just split those strings, and / or, use basename and dirname.
Using dirname and basename:
- set_fact:
disabled_hosts_ips: >-
{{
disabled_hosts_ips | default({})
| combine({
name: (disabled_hosts_ips | default({}))[name] | default([])
+ [ip]
})
}}
loop: "{{ disabled_hosts }}"
vars:
name: "{{ item[0] | basename ~ '_' ~ item[0] | dirname | basename }}"
ip: "{{ (item[3] | basename).split(':')[0] }}"
Using split:
- set_fact:
disabled_hosts_ips: >-
{{
disabled_hosts_ips | default({})
| combine({
name: (disabled_hosts_ips | default({}))[name] | default([])
+ [ip]
})
}}
loop: "{{ disabled_hosts }}"
vars:
name: "{{ item[0].split('/')[-2:] | reverse | join('_') }}"
ip: "{{ item[3].split('/')[-1].split(':')[0] }}"
Those both give:
disabled_hosts_ips:
pl_crad.la-dc.vivo.com_443_mobile_app:
- 10.50.100.18
- 10.50.100.28
- 10.50.100.48
pl_crad.la-dc.vivo.com_80_mobile_app:
- 10.50.100.25
- 10.50.100.39
- 10.50.100.49
For example, using the variable my_dict_var
my_dict_groups: "{{ dict(my_dict_keys|zip(my_dict_vals)) }}"
my_dict_keys: "{{ dh_groups|map('first')|list }}"
my_dict_vals: "{{ dh_groups|map('last')|map('map', attribute='value')|list }}"
dh_groups: "{{ my_dict_var|map('dict2items')|flatten|groupby('key') }}"
gives
my_dict_groups:
pl_crad.la-dc.vivo.com_443_mobile_app:
- 10.50.100.18
- 10.50.100.28
- 10.50.100.48
pl_crad.la-dc.vivo.com_80_mobile_app:
- 10.50.100.25
- 10.50.100.39
- 10.50.100.49
The complete set of the declarations is below
my_dict_groups: "{{ dict(my_dict_keys|zip(my_dict_vals)) }}"
my_dict_keys: "{{ dh_groups|map('first')|list }}"
my_dict_vals: "{{ dh_groups|map('last')|map('map', attribute='value')|list }}"
dh_groups: "{{ dh_keys|zip(dh_vals)|map('combine')|groupby('key') }}"
dh_vals: "{{ disabled_host|
map(attribute=3)|
map('split', '/')|map('last')|
map('split', ':')|map('first')|
map('community.general.dict_kv', 'value')|
list }}"
dh_keys: "{{ disabled_host|
map(attribute=0)|
map('regex_replace', dh_regex, dh_replace)|
map('community.general.dict_kv', 'key')|
list }}"
dh_regex: '^/.*?/(.*?)/(.*)$'
dh_replace: '\2_\1'
disabled_host: "{{ lookup('file', 'parse1.json') }}"
Details
In both cases use the filter groupby and create the list
dh_groups:
- - pl_crad.la-dc.vivo.com_443_mobile_app
- - key: pl_crad.la-dc.vivo.com_443_mobile_app
value: 10.50.100.18
- key: pl_crad.la-dc.vivo.com_443_mobile_app
value: 10.50.100.28
- key: pl_crad.la-dc.vivo.com_443_mobile_app
value: 10.50.100.48
- - pl_crad.la-dc.vivo.com_80_mobile_app
- - key: pl_crad.la-dc.vivo.com_80_mobile_app
value: 10.50.100.25
- key: pl_crad.la-dc.vivo.com_80_mobile_app
value: 10.50.100.39
- key: pl_crad.la-dc.vivo.com_80_mobile_app
value: 10.50.100.49
Create the lists of the keys my_dict_keys and values my_dict_vals, and create the dictionary my_dict_groups
my_dict_keys:
- pl_crad.la-dc.vivo.com_443_mobile_app
- pl_crad.la-dc.vivo.com_80_mobile_app
my_dict_vals:
- - 10.50.100.18
- 10.50.100.28
- 10.50.100.48
- - 10.50.100.25
- 10.50.100.39
- 10.50.100.49
For example, put the declarations into the playbook vars
- hosts: localhost
vars:
my_dict_groups: "{{ dict(my_dict_keys|zip(my_dict_vals)) }}"
my_dict_keys: "{{ dh_groups|map('first')|list }}"
my_dict_vals: "{{ dh_groups|map('last')|map('map', attribute='value')|list }}"
# dh_groups: "{{ my_dict_var|map('dict2items')|flatten|groupby('key') }}"
dh_groups: "{{ dh_keys|zip(dh_vals)|map('combine')|groupby('key') }}"
dh_vals: "{{ disabled_host|
map(attribute=3)|
map('split', '/')|
map('last')|map('split', ':')|map('first')|
map('community.general.dict_kv', 'value')|
list }}"
dh_keys: "{{ disabled_host|
map(attribute=0)|
map('regex_replace', dh_regex, dh_replace)|
map('community.general.dict_kv', 'key')|
list }}"
dh_regex: '^/.*?/(.*?)/(.*)$'
dh_replace: '\2_\1'
disabled_host: "{{ lookup('file', 'parse1.json') }}"
# my_dict_var:
# - pl_crad.la-dc.vivo.com_80_mobile_app: 10.50.100.25
# - pl_crad.la-dc.vivo.com_80_mobile_app: 10.50.100.39
# - pl_crad.la-dc.vivo.com_80_mobile_app: 10.50.100.49
# - pl_crad.la-dc.vivo.com_443_mobile_app: 10.50.100.18
# - pl_crad.la-dc.vivo.com_443_mobile_app: 10.50.100.28
# - pl_crad.la-dc.vivo.com_443_mobile_app: 10.50.100.48
tasks:
- debug:
var: my_dict_groups

Replace the key value in a list with the relevant matching values from another list in Ansible

I am trying to replace the key values in a dict inside a list(here only for the values inside Objectids) with the matching values from another list. Somehow i am only able to replace the 1st value but not iterating the whole list. Here the same key in the input.json will have multiple matching values from the finallist.json and all those values needs to be matched and added to the get the final expected output.
Input.json
[
{
"name": "DNS_One",
"objectIds": [
"DNS_One",
"DNS_One-HO",
"NTP"
]
},
{
"name": "DNS_Two",
"objectIds": [
"NTP"
]
}
]
finallist.json
[
{
"id": "123456",
"net_name": "DNS_One"
},
{
"id": "789101112",
"net_name": "DNS_One"
},
{
"id": "131415161718",
"net_name": "DNS_One-HO"
},
{
"id": "23897845",
"net_name": "NTP"
},
{
"id": "9879879546",
"net_name": "NTP"
}
]
Playbook
- name: Id mapping
vars:
objectid: >-
{{
finallist
| selectattr('net_name', 'in', item.1)
| map(attribute = 'id')
| first
| default([])
}}
set_fact:
obj: >-
{{
obj | default([]) +
[item.0 | combine({'objectIds': [objectid]})]
}}
with_subelements:
- "{{ input }}"
- objectIds
ignore_errors: yes
Expected Output
[
{
"name": "DNS_One",
"objectIds": [
"123456","789101112"
"131415161718",
"23897845","9879879546"
]
},
{
"name": "DNS_Two",
"objectIds": [
"23897845","9879879546"
]
}
]
Read the data and create the variables finallist and input
- set_fact:
finallist: "{{ lookup('file', 'finallist.json')|from_yaml }}"
- set_fact:
input: "{{ lookup('file', 'input.json')|from_yaml }}"
gives
finallist:
- id: '123456'
net_name: DNS_One
- id: '789101112'
net_name: DNS_One
- id: '131415161718'
net_name: DNS_One-HO
- id: '23897845'
net_name: NTP
- id: '9879879546'
net_name: NTP
input:
- name: DNS_One
objectIds:
- DNS_One
- DNS_One-HO
- NTP
- name: DNS_Two
objectIds:
- NTP
In finallist, group the items by net_name and convert the list to a dictionary
- set_fact:
finaldict: "{{ finaldict|d({})|
combine({item.0: item.1|map(attribute='id')}) }}"
loop: "{{ finallist|groupby('net_name') }}"
gives
finaldict:
DNS_One:
- '123456'
- '789101112'
DNS_One-HO:
- '131415161718'
NTP:
- '23897845'
- '9879879546'
Iterate input and substitute the IDs
- set_fact:
new: "{{ new|d([]) + [item|combine({'objectIds': _ids})] }}"
loop: "{{ input }}"
vars:
_ids: "{{ item.objectIds|map('extract', finaldict)|list }}"
gives the expected result
new:
- name: DNS_One
objectIds:
- ['123456', '789101112']
- ['131415161718']
- ['23897845', '9879879546']
- name: DNS_Two
objectIds:
- ['23897845', '9879879546']
You can flatten the lists if you want to
_ids: "{{ item.objectIds|map('extract', finaldict)|flatten }}"
gives
new:
- name: DNS_One
objectIds: ['123456', '789101112', '131415161718', '23897845', '9879879546']
- name: DNS_Two
objectIds: ['23897845', '9879879546']

Convert list to values in dictionary with Ansible

I am trying to use the Ansible gather_facts data from a Linux host as input:
"ansible_fibre_channel_wwn": [
"1000e0071bd4d0ed",
"10009440c90f9d85",
"1000e0071bce95f3",
"1000e0071bce95f2",
"1000e0071bd4d0ec",
"10009440c90f9d84"
],
And would like to create a dictionary using the above list items for dictionary values of a new "wwpn" key:
fc_initiators: [
{wwpn: '10:00:e0:07:1b:d4:d0:ed'},
{wwpn: '10:00:94:40:c9:0f:9d:85'},
{wwpn: '10:00:e0:07:1b:ce:95:f3'},
{wwpn: '10:00:e0:07:1b:ce:95:f2'},
{wwpn: '10:00:e0:07:1b:d4:d0:ec'},
{wwpn: '10:00:94:40:c9:0f:9d:84'}
]
This regex seems sufficient for converting the initial list items into colonized WWPN:
"{{ ansible_fibre_channel_wwn |
map('regex_replace', '^(..)(..)(..)(..)(..)(..)(..)(..)$', '\\1:\\2:\\3:\\4:\\5:\\6:\\7:\\8')|list }}"
I'm not sure where to start with the list->dictionary conversion though.
Any help is much appreciated.
Thanks!
"colonize" the items first, e.g.
- set_fact:
wwn_colonized: "{{ wwn_colonized|default([]) +
[item|map('join')|join(':')] }}"
loop: "{{ ansible_fibre_channel_wwn|map('batch', 2)|map('list')|list }}"
gives
wwn_colonized:
- 10:00:e0:07:1b:d4:d0:ed
- 10:00:94:40:c9:0f:9d:85
- 10:00:e0:07:1b:ce:95:f3
- 10:00:e0:07:1b:ce:95:f2
- 10:00:e0:07:1b:d4:d0:ec
- 10:00:94:40:c9:0f:9d:84
Then the task below creates the list of the dictionaries
- set_fact:
fc_initiators: "{{ wwn_colonized|
map('regex_replace', '^(.*)$', '{wwpn: \\1}')|
map('from_yaml')|
list }}"
gives
fc_initiators:
- wwpn: 10:00:e0:07:1b:d4:d0:ed
- wwpn: 10:00:94:40:c9:0f:9d:85
- wwpn: 10:00:e0:07:1b:ce:95:f3
- wwpn: 10:00:e0:07:1b:ce:95:f2
- wwpn: 10:00:e0:07:1b:d4:d0:ec
- wwpn: 10:00:94:40:c9:0f:9d:84
or, the same data in JSON
fc_initiators|to_nice_json: |-
[
{
"wwpn": "10:00:e0:07:1b:d4:d0:ed"
},
{
"wwpn": "10:00:94:40:c9:0f:9d:85"
},
{
"wwpn": "10:00:e0:07:1b:ce:95:f3"
},
{
"wwpn": "10:00:e0:07:1b:ce:95:f2"
},
{
"wwpn": "10:00:e0:07:1b:d4:d0:ec"
},
{
"wwpn": "10:00:94:40:c9:0f:9d:84"
}
]

How to create a list of dictionary of users and list of folders for each user?

I would like to create a dictionary of users which has list of folders in it.
users:
name: user1
folders:
- user1-1
- user1-2
name: user2
folders:
- user2-1
- user2-2
name: userN
folders:
- userN-1
- userN-2
I am trying to create this user dictionary list dynamically.
- hosts: localhost
gather_facts: no
vars:
userCount: 5
folderCount: 5
tasks:
- set_fact:
user_lists: []
- name: creating list of users
set_fact:
user_lists: "{{ user_lists + [ 'user-' ~ item ] }}"
with_sequence: count="{{userCount|int}}"
- debug:
var: user_lists
- set_fact:
usersObj: []
userDict: {}
- name: add each user to dict
set_fact:
usersObj: "{{ usersObj + [userDict| combine({'name': item})] }}"
with_items: "{{user_lists}}"
- debug: var=usersObj
I have created 5 users in dictionary. Now each user should have folder list created based on folderCount. How to resolve this? Can Jinja2 templates be used to simplify this?
The task below does the job
- set_fact:
user_lists: []
- name: creating dictionary of users with lists of folders
set_fact:
user_lists: "{{ user_lists|combine({key: val}) }}"
with_sequence: start=1 end="{{ userCount }}"
vars:
folder_range: "{{ range(1, folderCount|int + 1)|list }}"
key: "{{ 'user-' ~ item }}"
val: "{{ [key]|
product(folder_range)|
map('join', '-')|
list }}"
- debug:
var: user_lists
gives (abridged)
"user_lists": {
"user-1": [
"user-1-1",
"user-1-2",
"user-1-3",
"user-1-4",
"user-1-5"
],
"user-2": [
"user-2-1",
"user-2-2",
"user-2-3",
"user-2-4",
"user-2-5"
],
"user-3": [
"user-3-1",
"user-3-2",
"user-3-3",
"user-3-4",
"user-3-5"
],
"user-4": [
"user-4-1",
"user-4-2",
"user-4-3",
"user-4-4",
"user-4-5"
],
"user-5": [
"user-5-1",
"user-5-2",
"user-5-3",
"user-5-4",
"user-5-5"
]
}

Resources