merging dictionaries in ansible

PythonDictionaryMergeAnsible

Python Problem Overview


I'm currently building a role for installing PHP using ansible, and I'm having some difficulty merging dictionaries. I've tried several ways to do so, but I can't get it to work like I want it to:

# A vars file:
my_default_values:
  key = value

my_values:
  my_key = my_value


# In a playbook, I create a task to attempt merging the
# two dictionaries (which doesn't work):

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values + my_values

# I have also tried:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values|union(my_values)

# I have /some/ success with using j2's update,
# but you can't use j2 syntax in "with_dict", it appears.
# This works:

- debug: msg="{{ my_default_values.update(my_values) }}"

# But this doesn't:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values.update(my_values)

Is there a way to merge two dictionaries, so I can use it with "with_dict"?

Python Solutions


Solution 1 - Python

In Ansible 2.0, there is a Jinja filter, combine, for this:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: "{{ my_default_values | combine(my_values) }}"

Solution 2 - Python

It is now possible to use the anchor and extend features of YAML:

---
- hosts: localhost
  vars:
    my_default_values: &def
      key: value
    my_values:
      <<: *def
      my_key: my_value
  tasks:
    - debug: var=my_default_values
    - debug: var=my_values

Result:

TASK [debug]
ok: [localhost] => {
    "my_default_values": {
        "key": "value"
    }
}

TASK [debug] 
ok: [localhost] => {
    "my_values": {
        "key": "value", 
        "my_key": "my_value"
    }
}

I have no idea why this was not mentioned before.

Solution 3 - Python

If you want hash merging I would turn the hash merging feature on in ansible. In your ansible config file turn hash merging on.

With hash_behaviour=merge you can have two var files with the same variable name:

defaults.yml:

values:
  key: value

overrides.yml:

values:
  my_key: my_value

In order for the two vars to be merged you will need to include both var files:

ansible-playbook some-play.yml ... -e@defaults.yml  -e@overrides.yml

And you will end up with this:

TASK: [debug var=values] ********************************************************
ok: [localhost] => {
    "values": {
        "key": value,
        "my_key": my_value
    }
}

Calling update on a variable can be done in Jinja but in general it will be messy, I wouldn't do it outside of your templates and even then try to avoid it altogether.

Solution 4 - Python

If you need the merged dictionary a few times, you can set it to a new "variable":

- set_fact: _my_values="{{ my_default_values|combine(my_values) }}"

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: _my_values

Solution 5 - Python

Try this role from Ansible Galaxy.

I did it some time ago for same reason. It can deep merge dictionaries from several vars files and set custom precedence of merging.

This role can work under Ansible 2.0+

Solution 6 - Python

>>> key = 'default key'
>>> value = 'default value'
>>> my_key = 'my key'
>>> my_value = 'my value'
>>>
>>> my_default_values = {key: value}
>>> print my_default_values
{'default key': 'default value'}
>>>
>>> my_values = {my_key: my_value}
>>> print my_values
{'my key': 'my value'}
>>>
>>> with_dict = my_default_value.copy()
>>> print with_dict
{'default key': 'default value'}
>>> with_dict.update(my_values)
>>> print with_dict
{'default key': 'default value', 'my key': 'my value'}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBerry LangerakView Question on Stackoverflow
Solution 1 - PythonaugurarView Answer on Stackoverflow
Solution 2 - PythonleiivView Answer on Stackoverflow
Solution 3 - PythonjarvView Answer on Stackoverflow
Solution 4 - PythonNatView Answer on Stackoverflow
Solution 5 - Pythoneugene0707View Answer on Stackoverflow
Solution 6 - PythonQuentin THEURETView Answer on Stackoverflow