Merging dicts in Ansible

Posted on Wed 27 April 2022 in Sysadmin

Article summary: useRalativeImagePath

I spent way to much time figuring out this simple problem. In Ansible I wanted to have a top-level dict variable in the inventory that could be overridden by a host-level dict.

Example inventory file:

all:
  vars:
    dict1:
      thing1: stuff
      thing2: more stuff
  children:
    some_machines:
      hosts:
        server-a:
        server-b:
          dict1:
            thing1: different stuff

In this example at run-time server-a should have these variables defined:

dict1:
  thing1: stuff
  thing2: more stuff

and server-b, these:

dict1:
  thing1: different stuff
  thing2: more stuff

But server-a's dict1 overwrites that from the top level dict1.

I managed this by alering the inventory like this:

all:
  vars:
    dict1:
      thing1: stuff
      thing2: more stuff
  children:
    some_machines:
      hosts:
        server-a:
        server-b:
          host_dict1:
            thing1: different stuff

and putting the following in the playbook:

- name: merge dicts
  set_fact:
    dict1: "{{ dict1|combine(host_dict1|default({})) }}"

Note the dict1 variable under server-b has been renamed to host_dict1.