How to iterate over this dictionary in Ansible?

Say I have this dictionary

war_files: server1: - file1.war - file2.war server2: - file1.war - file2.war - file3.war 

and for now I just want to iterate over each element (key), and then for each element in the key (value). I did it

 - name: Loop over the dictionary debug: msg="Key={{ item.key }} value={{ item.value }}" with_dict: "{{ war_files }}" 

And I understand that. This, of course, is correct, but NOT what I want.

 ok: [localhost] => (item={'value': [u'file1.war', u'file2.war'], 'key': u'server1'}) => { "item": { "key": "server1", "value": [ "file1.war", "file2.war" ] }, "msg": "Server=server1, WAR=[u'file1.war', u'file2.war']" } ok: [localhost] => (item={'value': [u'file1.war', u'file2.war', u'file3.war'], 'key': u'server2'}) => { "item": { "key": "server2", "value": [ "file1.war", "file2.war", "file3.war" ] }, "msg": "Server=server2, WAR=[u'file1.war', u'file2.war', u'file3.war']" } 

I want to get a conclusion that says

 "msg": "Server=server1, WAR=file1.war" "msg": "Server=server1, WAR=file2.war" "msg": "Server=server2, WAR=file1.war" "msg": "Server=server2, WAR=file2.war" "msg": "Server=server2, WAR=file3.war" 

IOW, how can I write a task for iterating through a dictionary so that it goes through each key and then the elements inside each key? Essentially, I have a nested array and you want to iterate over it?

+8
source share
5 answers

Well, I could not find a very simple way to do this, however, with a little jinja2, we can achieve something similar:

 /tmp ❯❯❯ cat example.yml --- - hosts: 127.0.0.1 vars: war_files: server1: - file1.war - file2.war server2: - file1.war - file2.war - file3.war tasks: - set_fact: war_files_list_of_dicts: | {% set res = [] -%} {% for key in war_files.keys() -%} {% for value in war_files[key] -%} {% set ignored = res.extend([{'Server': key, 'WAR':value}]) -%} {%- endfor %} {%- endfor %} {{ res }} - name: let debug the crap out of this debug: var=war_files_list_of_dicts - name: Servers and their WARs!!! debug: msg: "Server={{ item.Server }}, WAR={{ item.WAR }}" with_items: "{{ war_files_list_of_dicts }}" 

And, when the player starts:

 /tmp ❯❯❯ ansible-playbook example.yml [WARNING]: provided hosts list is empty, only localhost is available PLAY [127.0.0.1] *************************************************************** TASK [setup] ******************************************************************* ok: [127.0.0.1] TASK [set_fact] **************************************************************** ok: [127.0.0.1] TASK [let debug the crap out of this] **************************************** ok: [127.0.0.1] => { "war_files_list_of_dicts": [ { "Server": "server1", "WAR": "file1.war" }, { "Server": "server1", "WAR": "file2.war" }, { "Server": "server2", "WAR": "file1.war" }, { "Server": "server2", "WAR": "file2.war" }, { "Server": "server2", "WAR": "file3.war" } ] } TASK [Servers and their WARs!!!] *********************************************** ok: [127.0.0.1] => (item={'WAR': u'file1.war', 'Server': u'server1'}) => { "item": { "Server": "server1", "WAR": "file1.war" }, "msg": "Server=server1, WAR=file1.war" } ok: [127.0.0.1] => (item={'WAR': u'file2.war', 'Server': u'server1'}) => { "item": { "Server": "server1", "WAR": "file2.war" }, "msg": "Server=server1, WAR=file2.war" } ok: [127.0.0.1] => (item={'WAR': u'file1.war', 'Server': u'server2'}) => { "item": { "Server": "server2", "WAR": "file1.war" }, "msg": "Server=server2, WAR=file1.war" } ok: [127.0.0.1] => (item={'WAR': u'file2.war', 'Server': u'server2'}) => { "item": { "Server": "server2", "WAR": "file2.war" }, "msg": "Server=server2, WAR=file2.war" } ok: [127.0.0.1] => (item={'WAR': u'file3.war', 'Server': u'server2'}) => { "item": { "Server": "server2", "WAR": "file3.war" }, "msg": "Server=server2, WAR=file3.war" } PLAY RECAP ********************************************************************* 127.0.0.1 : ok=4 changed=0 unreachable=0 failed=0 
+6
source

Like this

 - hosts: localhost vars: war_files: server1: - file1.war - file2.war server2: - file1.war - file2.war - file3.war tasks: - name: Loop over subelements of the dictionary debug: msg: "Key={{ item.0.key }} value={{ item.1 }}" loop: "{{ war_files | dict2items | subelements('value') }}" 

dict2items , subelements filters will appear in Ansible 2.6.

For your information, if the filter for your purpose does not exist, you can write your own in python without resorting to the jinja2 hack. Ansible is easy to expand; Filters in filter_plugins/*.py are searched by default next to your games / roles and are automatically turned on - for details, see the Developing plugins section.

+7
source

Now ansible lets it

 - name: add several users user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" with_items: - { name: 'testuser1', groups: 'wheel' } - { name: 'testuser2', groups: 'root' } 
+5
source

Here is my preferred way to iterate over dictionaries:

input_data.yml contains the following:

 ---- input_data: item_1: id: 1 info: "Info field number 1" item_2: id: 2 info: "Info field number 2" 

Then I use a data structure like the one above in the game using the keys () function, and iterate over the data using with_items:

 --- - hosts: localhost gather_facts: false connection: local tasks: - name: Include dictionary data include_vars: file: data.yml - name: Show info field from data.yml debug: msg: "Id: {{ input_data[item]['id'] }} - info: {{ input_data[item]['info'] }}" with_items: "{{ input_data.keys() }}" 

The above playbook produces the following output:

 PLAY [localhost] *********************************************************** TASK [Include dictionary data] ********************************************* ok: [localhost] TASK [Show info field from data.yml] *************************************** ok: [localhost] => (item=item_2) => { "msg": "Id: 2 - info: Info field item 2" } ok: [localhost] => (item=item_3) => { "msg": "Id: 3 - info: Info field item 3" } ok: [localhost] => (item=item_1) => { "msg": "Id: 1 - info: Info field item 1" } PLAY RECAP ***************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 
0
source

dict2items

I found that I want to iterate through a heterogeneous set of keys and their associated values ​​and use a key-value pair in the task. The dict2items filter is the least painful way I've found. You can find dict2items in Ansible 2.6

Dict example

 systemsetup: remotelogin: "On" timezone: "Europe/Oslo" usingnetworktime: "On" sleep: 0 computersleep: 0 displaysleep: 0 harddisksleep: 0 allowpowerbuttontosleepcomputer: "Off" wakeonnetworkaccess: "On" restartfreeze: "On" restartpowerfailure: "On" 

Task example

 --- - debug: msg: "KEY: {{ item.key }}, VALUE: {{ item.value }}" loop: "{{ systemsetup | dict2items }}" 
0
source

Source: https://habr.com/ru/post/1014883/


All Articles