Add a combine filter with documentation
This is based on some code from (closed) PR #7872, but reworked based on suggestions by @abadger and the other core team members. Closes #7872 by @darkk (hash_merge/hash_replace filters) Closes #11153 by @telbizov (merged_dicts lookup plugin)
This commit is contained in:
parent
6c9dc78d8c
commit
b328bc023d
3 changed files with 59 additions and 0 deletions
|
@ -334,6 +334,11 @@ official examples repos do not use this setting::
|
|||
|
||||
The valid values are either 'replace' (the default) or 'merge'.
|
||||
|
||||
.. versionadded: '2.0'
|
||||
|
||||
If you want to merge hashes without changing the global settings, use
|
||||
the `combine` filter described in :doc:`playbooks_filters`.
|
||||
|
||||
.. _hostfile:
|
||||
|
||||
hostfile
|
||||
|
|
|
@ -316,6 +316,41 @@ To get a sha256 password hash with a specific salt::
|
|||
Hash types available depend on the master system running ansible,
|
||||
'hash' depends on hashlib password_hash depends on crypt.
|
||||
|
||||
.. _combine_filter:
|
||||
|
||||
Combining hashes/dictionaries
|
||||
-----------------------------
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
The `combine` filter allows hashes to be merged. For example, the
|
||||
following would override keys in one hash:
|
||||
|
||||
{{ {'a':1, 'b':2}|combine({'b':3}) }}
|
||||
|
||||
The resulting hash would be:
|
||||
|
||||
{'a':1, 'b':3}
|
||||
|
||||
The filter also accepts an optional `recursive=True` parameter to not
|
||||
only override keys in the first hash, but also recurse into nested
|
||||
hashes and merge their keys too:
|
||||
|
||||
{{ {'a':{'foo':1, 'bar':2}, 'b':2}|combine({'a':{'bar':3, 'baz':4}}, recursive=True) }}
|
||||
|
||||
This would result in:
|
||||
|
||||
{'a':{'foo':1, 'bar':3, 'baz':4}, 'b':2}
|
||||
|
||||
The filter can also take multiple arguments to merge:
|
||||
|
||||
{{ a|combine(b, c, d) }}
|
||||
|
||||
In this case, keys in `d` would override those in `c`, which would
|
||||
override those in `b`, and so on.
|
||||
|
||||
This behaviour does not depend on the value of the `hash_behaviour`
|
||||
setting in `ansible.cfg`.
|
||||
|
||||
.. _other_useful_filters:
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ from __future__ import absolute_import
|
|||
|
||||
import sys
|
||||
import base64
|
||||
import itertools
|
||||
import json
|
||||
import os.path
|
||||
import ntpath
|
||||
|
@ -42,6 +43,7 @@ from ansible import errors
|
|||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||
from ansible.utils.hashing import md5s, checksum_s
|
||||
from ansible.utils.unicode import unicode_wrap, to_unicode
|
||||
from ansible.utils.vars import merge_hash
|
||||
|
||||
try:
|
||||
import passlib.hash
|
||||
|
@ -231,6 +233,20 @@ def mandatory(a):
|
|||
raise errors.AnsibleFilterError('Mandatory variable not defined.')
|
||||
return a
|
||||
|
||||
def combine(*terms, **kwargs):
|
||||
recursive = kwargs.get('recursive', False)
|
||||
if len(kwargs) > 1 or (len(kwargs) == 1 and 'recursive' not in kwargs):
|
||||
raise errors.AnsibleFilterError("'recursive' is the only valid keyword argument")
|
||||
|
||||
for t in terms:
|
||||
if not isinstance(t, dict):
|
||||
raise errors.AnsibleFilterError("|combine expects dictionaries, got " + repr(t))
|
||||
|
||||
if recursive:
|
||||
return reduce(merge_hash, terms)
|
||||
else:
|
||||
return dict(itertools.chain(*map(dict.iteritems, terms)))
|
||||
|
||||
class FilterModule(object):
|
||||
''' Ansible core jinja2 filters '''
|
||||
|
||||
|
@ -300,4 +316,7 @@ class FilterModule(object):
|
|||
'shuffle': randomize_list,
|
||||
# undefined
|
||||
'mandatory': mandatory,
|
||||
|
||||
# merge dicts
|
||||
'combine': combine,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue