Removing a deeply-nested dict item in Ansible

John Mazzitelli
2 min readJun 6, 2019

--

I searched for an answer to this question for at least an hour and surprisingly couldn’t find one!

Suppose you are writing an Ansible playbook, and you have a complex dictionary (with deeply nested dictionaries inside it) and you need to remove an item from one of the nested dictionaries.

Jeff Geerling has a nice blog here that tells you how to add or modify an item in a dictionary that is deeply nested, but it says nothing about how you can remove an item from a dictionary that is deeply nested. This is what I will now explain. I cannot accept credit for this solution — all credit goes to Chris Francy (aka zoredache) who proposed this solution while helping me in the #ansible IRC chat room.

In this example, I want to remove a remove: "me" item from the full_dict.outer_dict.inner_dict dictionary:

full_dict:
outer_key: "outer key value"
outer_dict:
inner_key: "inner key value"
inner_dict:
foo: "bar"
remove: "me"

To do this, I need to first build a dictionary with only the items I want to keep in that inner dictionary. So I have this:

new_inner_dict:
foo: "bar"

In other words, my new_inner_dict is exactly how I want my full_dict.outer_dict.inner_dict to look like — it has all the items I want without all the items I do not want.

At this point, I need to do a little Ansible magic to pop off the original inner_dict so it is completely removed. Now I can use combine() to add a new inner_dict to my full_dict.outer_dict. This is how you do this:

set_fact:
full_dict: |
{% set a=full_dict['outer_dict'].pop('inner_dict') %}
{{ full_dict | combine({'outer_dict': {'inner_dict': new_inner_dict}}, recursive=True) }}

At this point, my full_dict looks exactly how I want it — specifically, the remove: "me" item has now been removed from full_dict.outer_dict.inner_dict:

full_dict:
outer_key: "outer key value"
outer_dict:
inner_key: "inner key value"
inner_dict:
foo: "bar"

Here’s a full Ansible playbook you can run to see it in action — store this file as ansible-test.yml and run ansible-playbook ansible-test.yml.

- hosts: localhost
gather_facts: false
tasks:
- name: "Set the test facts"
set_fact:
new_inner_dict:
foo: "bar"
full_dict:
outer_key: "outer key value"
outer_dict:
inner_key: "inner key value"
inner_dict:
foo: "bar"
remove: "me"
- name: "This is the full dictionary"
debug:
var: full_dict
- name: "Use 'combine' to set inner_dict to a dictionary that does not have 'remove: me' item"
set_fact:
full_dict: "{{ full_dict | combine({'outer_dict': {'inner_dict': new_inner_dict}}, recursive=True) }}"
- name: "You would think the inner_dict had its 'remove: me' element removed, but notice it did not"
debug:
var: full_dict
- name: "Remove the entire inner_dict object and then combine with the new_inner_dict"
set_fact:
full_dict: |
{% set a=full_dict['outer_dict'].pop('inner_dict') %}
{{ full_dict | combine({'outer_dict': {'inner_dict': new_inner_dict}}, recursive=True) }}
- name: "Now notice the 'remove: me' item is gone from the inner_dict"
debug:
var: full_dict

--

--