Reputation: 43
How i can iterate with Ansible on a dict with contain another dict ?
mydict
can contain X "foo" and fooX (like foo1) can contain (at least) one or more params "bar".
I can't really change the vars type, which is currently :
mydict: dict
mydict.foo1: dict
mydict.foo1.params: dict
Ansible playbook : localvars.yml
---
- hosts: localhost
connection: local
gather_facts: false
vars:
mydict:
foo1:
dest: /tmp/foo1.txt
content: "foo1"
params:
bar1:
alias: foo1foo
bar2:
alias: foo1foo
foo2:
dest: /tmp/foo2.txt
content: "foo2"
params:
bar1:
alias: foo1foo
tasks:
- name: Print records
debug:
msg: |-
Item {{ item.key }} dest {{ item.value.dest }} content {{ item.value.content }} params {{ item.value.params }}"
loop: "{{ mydict | dict2items }}"
Ansible command : ansible-playbook -vv -i localhost, localvars.yml
Expected results :
Getting mydict.fooX.params.barX.alias dynamically for each "barX" params in "fooX"
Getting mydict.fooX.dest dynamically for each "fooX"
Thank you for your help
I tried this :
- name: Using dict2items
ansible.builtin.debug:
msg: |-
"item.key = {{ item.key }}
item.value = {{ item.value }}"
loop: "{{ mydict | dict2items }}"
Which is working fine to get all values in mydict
like mydict.foo1.dest, but i'm struggling to get all params values
Thanks for your help
Upvotes: 1
Views: 418
Reputation: 68404
The simplest option is an iteration of the attribute params in an included file, e.g. create a file
shell> cat iterate-params.yml
- debug:
msg: |-
item: {{ outer_item.key }}
dest: {{ outer_item.value.dest }}
content: {{ outer_item.value.content }}
param: {{ item }}
loop: "{{ outer_item.value.params|dict2items }}"
loop_control:
label: "{{ outer_item.key }}: {{ item.key }}"
and include it in the loop
- include_tasks: iterate-params.yml
loop: "{{ mydict|dict2items }}"
loop_control:
loop_var: outer_item
label: "{{ outer_item.key }}"
gives
TASK [debug] *******************************************************
included: /export/scratch/tmp8/iterate-params.yml for localhost => (item=foo1)
included: /export/scratch/tmp8/iterate-params.yml for localhost => (item=foo2)
TASK [debug] *******************************************************
ok: [localhost] => (item=foo1: bar1) =>
msg: |-
item: foo1
dest: /tmp/foo1.txt
content: foo1
param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=foo1: bar2) =>
msg: |-
item: foo1
dest: /tmp/foo1.txt
content: foo1
param: {'key': 'bar2', 'value': {'alias': 'foo1foo'}}
TASK [debug] *******************************************************
ok: [localhost] => (item=foo2: bar1) =>
msg: |-
item: foo2
dest: /tmp/foo2.txt
content: foo2
param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
The next option, if you can use the latest filter community.general.dict_kv, is the conversion of the attribute params to a list and iteration with_subelements
- debug:
msg: |-
dest: {{ item.0.dest }}
content: {{ item.0.content }}
param: {{ item.1 }}
with_subelements:
- "{{ _values|zip(_params)|map('combine') }}"
- params
loop_control:
label: "{{ item.0.dest }}"
vars:
_list: "{{ mydict|dict2items }}"
_values: "{{ _list|map(attribute='value') }}"
_params: "{{ _list|map(attribute='value.params')|
map('dict2items')|
map('community.general.dict_kv', 'params') }}"
gives
TASK [debug] ***********************************************************
ok: [localhost] => (item=/tmp/foo1.txt) =>
msg: |-
dest: /tmp/foo1.txt
content: foo1
param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=/tmp/foo1.txt) =>
msg: |-
dest: /tmp/foo1.txt
content: foo1
param: {'key': 'bar2', 'value': {'alias': 'foo1foo'}}
ok: [localhost] => (item=/tmp/foo2.txt) =>
msg: |-
dest: /tmp/foo2.txt
content: foo2
param: {'key': 'bar1', 'value': {'alias': 'foo1foo'}}
Upvotes: 1
Reputation: 44818
This is a bit ugly but I believe it meets your requirement:
- name: Print records
vars:
_records_to_items: "{{ mydict | dict2items }}"
_params_to_items: "{{ _records_to_items | map(attribute='value.params') | map('dict2items') }}"
_consolidate: "{{ _records_to_items | zip(_params_to_items) }}"
my_msg: |-
Item: {{ item.0.0.key }}
dest: {{ item.0.0.value.dest }}
content {{ item.0.0.value.content }}
curent param
name: {{ item.1.key }}
value: {{ item.1.value }}
debug:
msg: "{{ my_msg | split('\n') }}"
loop: "{{ _consolidate | subelements([1]) }}"
loop_control:
label: "Processing params for {{ item.0.0.key }}"
Which gives (running against your above data):
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [Print records] **********************************************************************************************************************************************************************************************
ok: [localhost] => (item=Processing params for foo1) => {
"msg": [
"Item: foo1",
"dest: /tmp/foo1.txt",
"content foo1",
"curent param",
" name: bar1",
" value: {'alias': 'foo1foo'}"
]
}
ok: [localhost] => (item=Processing params for foo1) => {
"msg": [
"Item: foo1",
"dest: /tmp/foo1.txt",
"content foo1",
"curent param",
" name: bar2",
" value: {'alias': 'foo1foo'}"
]
}
ok: [localhost] => (item=Processing params for foo2) => {
"msg": [
"Item: foo2",
"dest: /tmp/foo2.txt",
"content foo2",
"curent param",
" name: bar1",
" value: {'alias': 'foo1foo'}"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Upvotes: 1