summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbhijit Menon-Sen <ams@2ndQuadrant.com>2015-08-25 10:40:58 +0530
committerAbhijit Menon-Sen <ams@2ndQuadrant.com>2015-08-27 23:29:12 +0530
commitb328bc023d1597917383bfe4cbc2923112419c81 (patch)
tree7d3b10011ce18358d9dd57e60b75a8bf92708dc8
parent6c9dc78d8ce2e84eafb94b1ff0f5de0f68cf2558 (diff)
downloadansible-b328bc023d1597917383bfe4cbc2923112419c81.tar.gz
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)
-rw-r--r--docsite/rst/intro_configuration.rst5
-rw-r--r--docsite/rst/playbooks_filters.rst35
-rw-r--r--lib/ansible/plugins/filter/core.py19
3 files changed, 59 insertions, 0 deletions
diff --git a/docsite/rst/intro_configuration.rst b/docsite/rst/intro_configuration.rst
index 2cf03a70d2..e46d2c3f19 100644
--- a/docsite/rst/intro_configuration.rst
+++ b/docsite/rst/intro_configuration.rst
@@ -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
diff --git a/docsite/rst/playbooks_filters.rst b/docsite/rst/playbooks_filters.rst
index 857fc770ba..70cd908d9b 100644
--- a/docsite/rst/playbooks_filters.rst
+++ b/docsite/rst/playbooks_filters.rst
@@ -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:
diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py
index 84e055b61f..aa7464c323 100644
--- a/lib/ansible/plugins/filter/core.py
+++ b/lib/ansible/plugins/filter/core.py
@@ -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,
}