Last Updated: May 24, 2017
·
18.94K
· alisaifee

iterating a hash in an ansible task

This is no longer needed as the with_dict iterator is available in ansible core since version 1.5.

I'd been stuck on the problem of iterating over a hash in a task.

Vars:

var:
  item1:
    name: one
    value: 1
  item2: 
    name: two
    value: 2

Taks:

name: my loop
action: shell echo ${item.name}
with_items: $var

The above sample will generate an error

with_items expects a list

Now the obvious solution to this might be to rewrite the vars as

var: 
  - name: one
     value: 1
  - name: two
     value: 2

However, there is one main use case I've encountered that can't be satisfied by a list of hashes. This is when I want the same var to be added to by different roles.

By default ansible uses the replace strategy when combining variable definitions. However, if the ansible variable hash_behaviour is set to merge the final variable state is created by recursively merging all hashes.

Getting back to the topic at hand, iterating over the hash can be achieved by creating a custom jinja2 filter.

First create a structure similar to

custom
└── filter_plugins
    ├── __init__.py
    └── hash.py  

in your ansible repository.

Add the following snippet to hash.py

def hash_to_tuples(h):
    return h.items()

def hash_keys(h):
    return h.keys()

def hash_values(h):
    return h.values()

class FilterModule(object):
    ''' utility filters for operating on hashes '''

    def filters(self):
        return {
            'hash_to_tuples' : hash_to_tuples
            ,'hash_keys'     : hash_keys
            ,'hash_values'   : hash_values
        }

Then, add filter_plugins=./custom/filter_plugins to your ansible.cfg file.

Finally, update your task to look like

name: my loop
action: shell echo ${item[1].name}
with_items: "{{var|hash_to_tuples}}"

5 Responses
Add your response

Hi,
Nice, I am looking for the same thing.
However, I am not familiar with the ansible.cfg file and when I look at the doc, it does not help a lot.
When I just insert this line "filterplugins=./custom/filterplugins" into my ansible.cfg, it does not work. I have an error about no headers...
What does your all ansible.cfg file contain?

Thanks

over 1 year ago ·

Hi,
Refer to the sample config file in the ansible repository. The filterplugins property goes under the [defaults] section.

over 1 year ago ·

This "solution" is NOT needed anymore since with_dict was introduced in ansible version 1.5 ( Feb 2014 ).

With the variable from your example ...

name: my loop
 action: shell echo ${item.name}
 with_dict: var

... will work perfectly.

See the documentation chapter Looping over Hashes

over 1 year ago ·

@nifr: thanks! good to see that it's in the built-ins now!

over 1 year ago ·

withdict is useful to iterate through keys, values but what if I want to store in a variable only the list of the values?
my
dict:
ka: "a"
kb: "b"

And I would like to create a "my_values" variable that will be a list of the values only: ["a", "b"]

over 1 year ago ·