# dict merge - with\_dict expects a dict

**URL:** <https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710>\
**Category:** Ansible Project\
**Created:** [March 10, 2015, 1:23pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710 "2015-03-10T13:23:49Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![John\_McNulty](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@John\_McNulty](https://forum.ansible.com/u/John_McNulty)\
**Post date:** [March 10, 2015, 1:23pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/1 "2015-03-10T13:23:49Z")

</div>

Hi,

So here’s the scenario - I’m given a data structure that when converted to yaml looks like this (names & numbers invented).

`  
host\_routes:  
route-oob:  
device: bond.123  
routes:  
10.118.0.0/16: ‘10.118.255.254’  
route-int:  
device: bond.456  
routes:  
172.168.0.0/23: ‘172.168.1.254’

`

I can use that with a template to create the network-script route files needed, that’s easy enough. But in real life there can be up to several OOB routes that this host will need depending on which datacentre / hall / security zone it resides in. e.g.

`standard_routes: route-oob: device: bond.123 routes: 10.198.0.0/24: '10.118.255.254'`

I’d like to add these additional routes to the appropriate group\_var file and then merge them together when creating the route files. I can’t get this to work though. I’ve tried all the following:

`  
with\_dict: host\_routes|union(standard\_routes)

with\_dict: union(host\_routes, standard\_routes)

with\_dict: host\_routes + standard\_routes

`

and get the same error every time …

`fatal: [localhost] => with_dict expects a dict`

Is there another filter or some other way of doing this? I don’t want to change the default hash\_behaviour to merge just for this one use case as that has much wider implications.

Thanks, John

---

<div class="post-metadata">

**Author:** ![John\_McNulty](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@John\_McNulty](https://forum.ansible.com/u/John_McNulty)\
**Post date:** [March 10, 2015, 4:19pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/2 "2015-03-10T16:19:46Z")

</div>

So the reason why I tried using union was this github issue ( [https://github.com/ansible/ansible/issues/7495](https://github.com/ansible/ansible/issues/7495) ) which implied it should work (assuming the PR got actioned).

But looking at the code ( lib/ansible/runner/filter\_plugins/mathstuff.py ) it doesn’t look like that’s the case as union() doesn’t match what this article ([http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single-expression](http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single-expression)) describes as the ‘pythonic way’.

z = x.copy()  
z.update(y)

So I tried to emulate that with …

`with_dict: "{% set r = host_routes.copy() %}{% r.update(standard_routes) %}{{ r }}"`

resulting in …

`  
fatal: [localhost] =\> template error while templating string: unknown tag ‘r’

`

I’ve also scanned all the Jinja2 filters ( [http://jinja.pocoo.org/docs/dev/templates](http://jinja.pocoo.org/docs/dev/templates) ) looking for a potential candidate and can’t see anything that looks suitable.

I really am an Ansible & jinja2 pseudo-novice, so I’m kind of stumbling around a bit here 🙂

---

<div class="post-metadata">

**Author:** ![Jonathan\_Davila](https://avatars.discourse-cdn.com/v4/letter/j/e0b2c6/32.png) [@Jonathan\_Davila](https://forum.ansible.com/u/Jonathan_Davila)\
**Post date:** [March 11, 2015, 3:23pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/3 "2015-03-11T15:23:43Z")

</div>

Would you mind sharing the full body of the task that pertains to this as well as the template file?

---

<div class="post-metadata">

**Author:** ![Jonathan\_Davila](https://avatars.discourse-cdn.com/v4/letter/j/e0b2c6/32.png) [@Jonathan\_Davila](https://forum.ansible.com/u/Jonathan_Davila)\
**Post date:** [March 11, 2015, 4:01pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/4 "2015-03-11T16:01:25Z")

</div>

so I’ve got a working sample for you. This is the exact test I did.

`

---

<div class="post-metadata">

**Author:** ![John\_McNulty](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@John\_McNulty](https://forum.ansible.com/u/John_McNulty)\
**Post date:** [March 11, 2015, 5:07pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/5 "2015-03-11T17:07:52Z")

</div>

Hi,

For just processing host\_routes I had.

`

- name: Write network routes  
template: \>  
src=route.j2  
dest={{ net\_path}}/route-{{ item.value.device }}  
mode=0644 owner=root group=root  
with\_dict: host\_routes  
when: item.value.routes is defined  
tags: netdev

`

And the template was …

`  
{% for network,gateway in item.value.routes.iteritems() %}  
{{ network }} via {{ gateway }} dev {{ item.value.device }}  
{% endfor %}

`

I needed the ‘when’ conditional because the dict sometimes contains something like this instead to ensure that old/retired/changed network-script route files must be removed:

`routes-ext: device: 'eth6.111' absent: true routes-other: device: 'eth6.222' absent: true`

And I cater for that with …

`

- name: Remove ‘absent’ route files  
file: path={{ net\_path}}/route-{{ item.value.device }} state=absent  
with\_dict: host\_routes  
when: item.value.absent is defined  
tags: netdev

`

---

<div class="post-metadata">

**Author:** ![Jonathan\_Davila](https://avatars.discourse-cdn.com/v4/letter/j/e0b2c6/32.png) [@Jonathan\_Davila](https://forum.ansible.com/u/Jonathan_Davila)\
**Post date:** [March 11, 2015, 5:15pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/6 "2015-03-11T17:15:58Z")

</div>

Does my example above help you as far as the templating piece?

Personally I would abstract out the desired state for the route-file status into it’s own dict to smth like this:

`  
route\_file\_state:  
routes-other: present  
routes-ext: absent

`

would prevent that extra attribute from interfering with my jinja example and needing to add more logic.

---

<div class="post-metadata">

**Author:** ![John\_McNulty](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@John\_McNulty](https://forum.ansible.com/u/John_McNulty)\
**Post date:** [March 11, 2015, 5:20pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/7 "2015-03-11T17:20:07Z")

</div>

Hi again. Thanks … I got so hung up on using with\_dict I didn’t consider taking another tack.

I’m reconsidering the decision to not to use hash\_behaviour=merge as that solves my problem + would also come in handy elsewhere, like combining default sysctl parameter changes with additional application & environment requirements. If I don’t then it would be an interesting exercise for me to write a custom module to merge dictionaries, or even add a new ansible filter.

Cheers, J

---

<div class="post-metadata">

**Author:** ![John\_McNulty](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@John\_McNulty](https://forum.ansible.com/u/John_McNulty)\
**Post date:** [March 11, 2015, 5:22pm UTC](https://forum.ansible.com/t/dict-merge-with-dict-expects-a-dict/17710/8 "2015-03-11T17:22:56Z")

</div>

Yes, I can work with that.

Thanks for your help.
