Commit 53fd85e2 by Daniel Hokka Zakrisson

Merge pull request #1903 from leucos/mergeable-hash-vars

Adds user-selectable hash merging support in vars
parents 6e0cb14b 8eb7d740
...@@ -76,6 +76,16 @@ remote_port=22 ...@@ -76,6 +76,16 @@ remote_port=22
sudo_exe=sudo sudo_exe=sudo
# how to handle hash defined in several places
# hash can be merged, or replaced
# if you use replace, and have multiple hashes named 'x', the last defined
# will override the previously defined one
# if you use merge here, hash will cumulate their keys, but keys will still
# override each other
# replace is the default value, and is how ansible always handled hash variables
#
# hash_behaviour=replace
# if set, always use this private key file for authentication, same as if passing # if set, always use this private key file for authentication, same as if passing
# --private-key to ansible or ansible-playbook # --private-key to ansible or ansible-playbook
......
...@@ -92,6 +92,7 @@ DEFAULT_MANAGED_STR = get_config(p, DEFAULTS, 'ansible_managed', None, ...@@ -92,6 +92,7 @@ DEFAULT_MANAGED_STR = get_config(p, DEFAULTS, 'ansible_managed', None,
DEFAULT_SYSLOG_FACILITY = get_config(p, DEFAULTS, 'syslog_facility', 'ANSIBLE_SYSLOG_FACILITY', 'LOG_USER') DEFAULT_SYSLOG_FACILITY = get_config(p, DEFAULTS, 'syslog_facility', 'ANSIBLE_SYSLOG_FACILITY', 'LOG_USER')
DEFAULT_KEEP_REMOTE_FILES = get_config(p, DEFAULTS, 'keep_remote_files', 'ANSIBLE_KEEP_REMOTE_FILES', '0') DEFAULT_KEEP_REMOTE_FILES = get_config(p, DEFAULTS, 'keep_remote_files', 'ANSIBLE_KEEP_REMOTE_FILES', '0')
DEFAULT_SUDO_EXE = get_config(p, DEFAULTS, 'sudo_exe', 'ANSIBLE_SUDO_EXE', 'sudo') DEFAULT_SUDO_EXE = get_config(p, DEFAULTS, 'sudo_exe', 'ANSIBLE_SUDO_EXE', 'sudo')
DEFAULT_HASH_BEHAVIOUR = get_config(p, DEFAULTS, 'hash_behaviour', 'ANSIBLE_HASH_BEHAVIOUR', 'replace')
DEFAULT_ACTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'action_plugins', None, '/usr/share/ansible_plugins/action_plugins')) DEFAULT_ACTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'action_plugins', None, '/usr/share/ansible_plugins/action_plugins'))
DEFAULT_CALLBACK_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'callback_plugins', None, '/usr/share/ansible_plugins/callback_plugins')) DEFAULT_CALLBACK_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'callback_plugins', None, '/usr/share/ansible_plugins/callback_plugins'))
......
...@@ -19,6 +19,7 @@ import os ...@@ -19,6 +19,7 @@ import os
import glob import glob
from ansible import errors from ansible import errors
from ansible import utils from ansible import utils
import ansible.constants as C
class VarsModule(object): class VarsModule(object):
...@@ -48,7 +49,11 @@ class VarsModule(object): ...@@ -48,7 +49,11 @@ class VarsModule(object):
data = utils.parse_yaml_from_file(path) data = utils.parse_yaml_from_file(path)
if type(data) != dict: if type(data) != dict:
raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path)
results.update(data) if C.DEFAULT_HASH_BEHAVIOUR == "merge":
# let data content override results if needed
results = utils.merge_hash(results, data)
else:
results.update(data)
# load vars in playbook_dir/group_vars/name_of_host # load vars in playbook_dir/group_vars/name_of_host
path = os.path.join(basedir, "host_vars/%s" % host.name) path = os.path.join(basedir, "host_vars/%s" % host.name)
...@@ -56,7 +61,10 @@ class VarsModule(object): ...@@ -56,7 +61,10 @@ class VarsModule(object):
data = utils.parse_yaml_from_file(path) data = utils.parse_yaml_from_file(path)
if type(data) != dict: if type(data) != dict:
raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path) raise errors.AnsibleError("%s must be stored as a dictionary/hash" % path)
results.update(data) if C.DEFAULT_HASH_BEHAVIOUR == "merge":
# let data content override results if needed
results = utils.merge_hash(results, data)
else:
results.update(data)
return results return results
...@@ -19,6 +19,7 @@ import sys ...@@ -19,6 +19,7 @@ import sys
import os import os
import shlex import shlex
import yaml import yaml
import copy
import optparse import optparse
import operator import operator
from ansible import errors from ansible import errors
...@@ -273,6 +274,26 @@ def parse_kv(args): ...@@ -273,6 +274,26 @@ def parse_kv(args):
options[k]=v options[k]=v
return options return options
def merge_hash(a, b):
''' merges hash b into a
this means that if b has key k, the resulting has will have a key k
which value comes from b
said differently, all key/value combination from b will override a's '''
# and iterate over b keys
for k, v in b.iteritems():
if k in a and isinstance(a[k], dict):
# if this key is a hash and exists in a
# we recursively call ourselves with
# the key value of b
a[k] = merge_hash(a[k], v)
else:
# k is not in a, no need to merge b, we just deecopy
# or k is not a dictionnary, no need to merge b either, we just deecopy it
a[k] = v
# finally, return the resulting hash when we're done iterating keys
return a
def md5s(data): def md5s(data):
''' Return MD5 hex digest of data. ''' ''' Return MD5 hex digest of data. '''
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment