Package: ansible-merge-vars
ansible_merge_vars: An action plugin for AnsibleAn Ansible plugin to merge all variables in context with a certain suffix (lists
or dicts only) and create a new variable that contains the result of this merge.
This is an Ansible action plugin, which is basically an Ansible module that runs
on the machine running Ansible rather than on the host that Ansible is
provisioning.InstallationUsageMerging dictsMerging listsVerbosityExample PlaybooksContributingCompatibilityThis plugin is tested with the latest release of each minor version of Ansible >=2.1. Earlier releases of some minor versions may not be compatible.  This
plugin is not compatible with combinations of older versions of Ansible and
newer versions of Python.  The following combinations are tested:PythonAnsible2.7>= 2.1>= 3.5, < 3.8>= 2.5>= 3.8>= 2.8InstallationPick a name that you want to use to call this plugin in Ansible playbooks.
This documentation assumes you're using the namemerge_vars.pip install ansible_merge_varsCreate anaction_pluginsdirectory in the directory in which you run Ansible.By default, Ansible will look for action plugins in anaction_pluginsfolder adjacent to the running playbook. For more information on this, or to
change the location where ansible looks for action plugins, seethe Ansible
docs.Create a file calledmerge_vars.py(or whatever name you picked) in theaction_pluginsdirectory, with one line:from ansible_merge_vars import ActionModuleFor Ansible less than 2.4:Create thelibrarydirectory if it's not created yet:mkdir -p libraryCreate an emptymerge_vars(or whatever name you picked) file in yourlibrarydirectory:touch library/merge_varsAnsible action plugins are usually paired with modules (which run on the
hosts being provisioned), and Ansible will automatically run an action plugin
when you call of a module of the same name in a task.  Prior to Ansible 2.4,
if you want to call an action plugin by its name (merge_vars) in our tasks,
you need an empty file calledmerge_varsin the place where ansible checks
for custom modules; by default, this is alibrarydirectory adjacent to the
running playbook.UsageThe variables that you want to merge must be suffixed with__to_merge.
They can be defined anywhere in the inventory, or by any other means; as long
as they're in the context for the running play, they'll be merged.Merging dictsLet's say we've got a groupsomeenvironmentingroup_varswith a fileusers.yml, with these contents:users__someenvironment_users__to_merge:user1:bobuser2:henryand a groupsomedatacenteringroups_varswith a fileusers.yml, with these
contents:users__somedatacenter_users__to_merge:user3:sallyuser4:janeand we're running a play against hosts that are in both of those groups.
Then this task:name:Merge user varsmerge_vars:suffix_to_merge:users__to_mergemerged_var_name:merged_usersexpected_type:'dict'will set amerged_usersvar (fact) available to all subsequent tasks that looks like this (if it were to be declared in raw yaml):merged_users:user1:bobuser2:henryuser3:sallyuser4:janeNote that the variables get merged in alphabetical order of their names, with
values from later dicts replacing values from earlier dicts. So this setup:users__someenvironment_users__to_merge:user1:bobuser2:jekyllusers__somedatacenter_users__to_merge:user2:hydeuser3:sallyname:Merge user varsmerge_vars:suffix_to_merge:users__to_mergemerged_var_name:merged_usersexpected_type:'dict'would set amerged_usersvar that looks like this (if it were to be declared in raw yaml):merged_users:user1:bobuser2:jekylluser3:sallyWith great power comes great responsibility...Merging listsLet's say we've got asomeenvironmentgroup with anopen_ports.ymlfile
that looks like this:open_ports__someenvironment_open_ports__to_merge:-1-2-3and asomedatacentergroup with anopen_ports.ymlfile that looks like this:open_ports__somedatacenter_open_ports__to_merge:-3-4-5Then this task:name:Merge open portsmerge_vars:suffix_to_merge:open_ports__to_mergemerged_var_name:merged_portsexpected_type:'list'will set amerged_portsfact that looks like this (because the variables are merged in alphabetical order):merged_ports:-3-4-5-1-2Notice that3only appears once in the merged result. By default, thismerge_varsplugin will de-dupe the resulting merged value. If you don't want
to de-dupe the merged value, you have to declare thededupargument:name:Merge open portsmerge_vars:suffix_to_merge:open_ports__to_mergemerged_var_name:merged_portsdedup:falseexpected_type:'list'which will set this fact:merged_ports:-3-4-5-1-2-3A note aboutdedup:It has no effect when the merged vars are dictionaries.Recursive mergingWhen dealing with complex data structures, you may want to do a deep (recursive) merge.Suppose you have variables that define lists of users to add and select who should have admin privileges:users__someenvironment_users__to_merge:users:-bob-henryadmins:-bobandusers__somedatacenter_users__to_merge:users:-sally-janeadmins:-sallyYou can request a recursive merge with:name:Merge user varsmerge_vars:suffix_to_merge:users__to_mergemerged_var_name:merged_usersexpected_type:'dict'recursive_dict_merge:Trueand get:merged_users:users:-sally-jane-bob-henryadmins:-sally-bobWhen merging dictionaries and the same key exists in both, the recursive merge checks the type of the value:if the entry value is a list, it merges the values as lists (merge_list)if the entry value is a dict, it merges the values (recursively) as dicts (merge_dict)any other values: just replace (use last)Module optionsparameterrequireddefaultchoicescommentssuffix_to_mergeyesSuffix of variables to merge.  Must end with__to_merge.merged_var_nameyesName of the target variable.expected_typeyesdict, listExpected type of the merged variable (one of dict or list)dedupnoyesyes / noWhether to remove duplicates from lists (arrays) after merging.recursive_dict_mergenonoyes / noWhether to do deep (recursive) merging of dictionaries, or just merge only at top level and replace valuesVerbosityRunning ansible-playbook with-vwill cause this plugin to output the order in
which the keys are being merged:PLAY [Example of merging lists] ************************************************

TASK [Merge port vars] *********************************************************
Merging vars in this order: [ u'group1_ports__to_merge', u'group2_ports__to_merge', u'group3_ports__to_merge']
ok: [localhost] => {"ansible_facts": {"merged_ports": [22, 1111, 443, 2222, 80]}, "changed": false}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "merged_ports": [
        22,
        1111,
        443,
        2222,
        80
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=6    changed=0    unreachable=0    failed=0Example PlaybooksThere are some example playbooks in theexamplesdirectory that show how the
various features work in the context of an actual Ansible playbook.  These
example playbooks are run as part of the test suite for this plugin; if you
would like to run them yourself, please see theContributingsection for instructions on how to run the test suite.ContributingPlease note that this project is released with aContributor Code of Conduct. By participating in this project you agree to abide by its terms.There is only one prerequisite to working on this project locally:You have the Python versions in the.python-versioninstalled and on your path (probably withpyenvA development workflow may look like this:Clone this repositoryRunmake dev-depsThis will create a virtualenvvenvin the root of this project and
install all of the dependencies needed to build a release and run tests.Runmake test-allThis will usetoxto run the
tests against different combinations of python versions and ansible
releases.It will also usea scriptto queryPyPIfor the latest versions of Ansible, and
add them to thetox.inifile if they're not there.Updating thetox.inifile and running all the tests against all of the
combinations of Ansible releases and Python versions takes a lot of time.
To run aginst just one combination, you can list all of the combinations
available and tell tox to only run the tests for one combination:$ venv/bin/tox -l

py27-ansible-2.1
py27-ansible-2.2
py27-ansible-2.3
py27-ansible-2.4
py27-ansible-2.5
py27-ansible-2.6
...
py35-ansible-2.5
py35-ansible-2.6
py36-ansible-2.7
py36-ansible-2.8
...

$ venv/bin/tox -e py36-ansible-2.5
...
```If you have any ideas about things to add or improve, or find any bugs to fix, we're all ears!  Just a few guidelines:Please write or update tests (either example-based tests, property-based
tests, or both) for any code that you add, change, or remove.Please add an example playbook or update an existing example playbook in
theexamplesfolder.  These example playbooks serve as the integration
tests for this plugin.Please make sure thatmake test-allexits zero. This runs a code linter,
all of the tests, and all of the examples against all supported versions
of Python and Ansible.If the linting seems too annoying, it probably is! Feel free to do what you
need to do in the.pylintrcat the root of this repository to maintain
sanity. Add it to your PR, and we'll most likely take it.Happy merging!