Merging multiple (more than 2) dicts, the correct way

So I know that we’re doing this incorrectly. The question is, how can I do this the correct way?

I have a windows.yml group variable file that contains a dict that lists the basic software that machines will need:

default_baseline_includes:
  7zip: true
  bigfix: true
  checkmk: true
  chrome: true
  d4voip: false
  firefox: true
  git: true

Then I have other group var files, such as windows_admin.yml windows_32bit.yml windows_itps.yml etc, that might have changes:

override_baseline_includes:
  bigfix: false
  checkmk: false

Then I put them together like this:

baseline_includes: "{{ default_baseline_includes|combine(override_baseline_includes) }}"

I’m under the impression that this definition is evaluated at run-time – that is, not at the moment it’s defined, but whenever the baseline_incluces variable is actually called/referenced, it uses whatever happens to be in override_baseline_includes at that time. (Maybe I’m wrong?)

The problem is that, if a machine is in several groups, it might have several options to define (and thus replace) the override_baseline_includes dict. If this were perl, I could just say

  $baseline{bigfix} = false;

and it wouldn’t affect the rest of the dict. But in ansible (as far as I can tell), creating override_baseline_includes will completely remove and replace a pre-existing override_baseline_includes

So the question is …

How can I, correctly, have several different dicts similar to my override_baseline_includes , that will all be merged together with my default_baseline_includes

(bonus question) merged in the correct order? (I’m not sure what the correct order is yet, other than “host-based should override group-based, and group-based should override the default”

I hope this makes sense. Thanks in advance.

So I don’t know if it’s acceptable to answer your own question.

My boss referred me to this web page

specifically, the final example.

The plan is that each individual group’s override_baseline_includes will be renamed override_baseline_includes_## and assigned a number from 00 to 98, and each individual host’s override_baseline_includes will become override_baseline_includes_99

Then we will set

override_baseline_includes: "{{ q('vars', *q('varnames', '^override_baseline_includes_')) | flatten }}"

baseline_includes: "{{ default_baseline_includes|combine(override_baseline_includes) }}"

The first line should grab all of the various override_baseline_includes_## files in lexical (numerical) order into a single override_baseline_includes , which will then be merged into the default_baseline_includes .

I suppose we could have saved a few steps by giving the default_baseline_includes a name like override_baseline_includes_00, but so far, our testing has worked correctly, and using the word “override” seemed wrong for the defaults.

Anyway, I think this has solved our problem.