{ "info": { "author": "Leapfrog Online", "author_email": "dfuchs@leapfrogonline.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: System :: Systems Administration" ], "description": "# ansible_merge_vars: An action plugin for Ansible\n\n[![Travis](https://img.shields.io/travis/leapfrogonline/ansible-merge-vars.svg)](https://travis-ci.org/leapfrogonline/ansible-merge-vars)\n[![PyPI](https://img.shields.io/pypi/v/ansible_merge_vars.svg)](https://pypi.org/project/ansible_merge_vars/)\n\nAn Ansible plugin to merge all variables in context with a certain suffix (lists\nor dicts only) and create a new variable that contains the result of this merge.\nThis is an Ansible action plugin, which is basically an Ansible module that runs\non the machine running Ansible rather than on the host that Ansible is\nprovisioning.\n\n- [Installation](#installation)\n- [Usage](#usage)\n - [Merging dicts](#merging-dicts)\n - [Merging lists](#merging-lists)\n- [Verbosity](#verbosity)\n- [Example Playbooks](#example-playbooks)\n- [Contributing](#contributing)\n\n## Requirements\n\nThis plugin requires Ansible release >= 2.1.0.0.\n\nAdditionally, there are some releases of Ansible for which this plugin does not work because of bugs in those releases:\n * [Incompatible Ansible Releases](incompatible_ansible_releases.txt)\n\n## Installation\n\n1. Pick a name that you want to use to call this plugin in Ansible playbooks.\n This documentation assumes you're using the name `merge_vars`.\n1. `pip install ansible_merge_vars`\n1. Create an `action_plugins` directory in the directory in which you run Ansible.\n\n By default, Ansible will look for action plugins in an `action_plugins`\n folder adjacent to the running playbook. For more information on this, or to\n change the location where ansible looks for action plugins, see [the Ansible\n docs](https://docs.ansible.com/ansible/dev_guide/developing_plugins.html#distributing-plugins).\n1. Create a file called `merge_vars.py` (or whatever name you picked) in the\n `action_plugins` directory, with one line:\n\n ```\n from ansible_merge_vars import ActionModule\n ```\n1. For Ansible less than 2.4:\n\n 1. Create the `library` directory if it's not created yet:\n \n ```\n mkdir -p library\n ```\n\n 1. Create an empty `merge_vars` (or whatever name you picked) file in your `library` directory:\n\n ```\n touch library/merge_vars\n ```\n\n Ansible action plugins are usually paired with modules (which run on the\n hosts being provisioned), and Ansible will automatically run an action plugin\n when you call of a module of the same name in a task. Prior to Ansible 2.4,\n if you want to call an action plugin by its name (`merge_vars`) in our tasks,\n you need an empty file called `merge_vars` in the place where ansible checks\n for custom modules; by default, this is a `library` directory adjacent to the\n running playbook.\n\n\n## Usage\n\nThe variables that you want to merge must be suffixed with `__to_merge`.\nThey can be defined anywhere in the inventory, or by any other means; as long\nas they're in the context for the running play, they'll be merged.\n\n### Merging dicts\n\nLet's say we've got a group `someenvironment` in `group_vars` with a file\n`users.yml`, with these contents:\n\n```yaml\nusers__someenvironment_users__to_merge:\n user1: bob\n user2: henry\n```\n\nand a group `somedatacenter` in `groups_vars` with a file `users.yml`, with these\ncontents:\n\n```yaml\nusers__somedatacenter_users__to_merge:\n user3: sally\n user4: jane\n```\n\nand we're running a play against hosts that are in both of those groups.\nThen this task:\n\n```yaml\nname: Merge user vars\nmerge_vars:\n suffix_to_merge: users__to_merge\n merged_var_name: merged_users\n expected_type: 'dict'\n```\nwill set a `merged_users` var (fact) available to all subsequent tasks that looks like this (if it were to be declared in raw yaml):\n\n```yaml\nmerged_users:\n user1: bob\n user2: henry\n user3: sally\n user4: jane\n```\n\nNote that the variables get merged in alphabetical order of their names, with\nvalues from later dicts replacing values from earlier dicts. So this setup:\n\n```yaml\nusers__someenvironment_users__to_merge:\n user1: bob\n user2: jekyll\n```\n\n```yaml\nusers__somedatacenter_users__to_merge:\n user2: hyde\n user3: sally\n```\n\n```yaml\nname: Merge user vars\nmerge_vars:\n suffix_to_merge: users__to_merge\n merged_var_name: merged_users\n expected_type: 'dict'\n```\n\nwould set a `merged_users` var that looks like this (if it were to be declared in raw yaml):\n\n```yaml\nmerged_users:\n user1: bob\n user2: jekyll\n user3: sally\n```\n\nWith great power comes great responsibility...\n\n### Merging lists\n\nLet's say we've got a `someenvironment` group with an `open_ports.yml` file\nthat looks like this:\n\n```yaml\nopen_ports__someenvironment_open_ports__to_merge:\n - 1\n - 2\n - 3\n```\nand a `somedatacenter` group with an `open_ports.yml` file that looks like this:\n\n```yaml\nopen_ports__somedatacenter_open_ports__to_merge:\n - 3\n - 4\n - 5\n```\nThen this task:\n\n```yaml\nname: Merge open ports\nmerge_vars:\n suffix_to_merge: open_ports__to_merge\n merged_var_name: merged_ports\n expected_type: 'list'\n```\nwill set a `merged_ports` fact that looks like this (because the variables are merged in alphabetical order):\n\n```yaml\nmerged_ports:\n - 3\n - 4\n - 5\n - 1\n - 2\n```\n\nNotice that `3` only appears once in the merged result. By default, this\n`merge_vars` plugin will de-dupe the resulting merged value. If you don't want\nto de-dupe the merged value, you have to declare the `dedup` argument:\n\n```yaml\nname: Merge open ports\nmerge_vars:\n suffix_to_merge: open_ports__to_merge\n merged_var_name: merged_ports\n dedup: false\n expected_type: 'list'\n```\nwhich will set this fact:\n\n```yaml\nmerged_ports:\n - 3\n - 4\n - 5\n - 1\n - 2\n - 3\n```\n\nA note about `dedup`:\n * It has no effect when the merged vars are dictionaries.\n\n### Recursive merging ###\n\nWhen dealing with complex data structures, you may want to do a deep (recursive) merge.\n\nSuppose you have variables that define lists of users to add and select who should have admin privileges:\n\n```yaml\nusers__someenvironment_users__to_merge:\n users:\n - bob\n - henry\n admins:\n - bob\n```\n\nand\n\n```yaml\nusers__somedatacenter_users__to_merge:\n users:\n - sally\n - jane\n admins:\n - sally\n```\n\nYou can request a recursive merge with:\n\n```yaml\nname: Merge user vars\nmerge_vars:\n suffix_to_merge: users__to_merge\n merged_var_name: merged_users\n expected_type: 'dict'\n recursive_dict_merge: True\n```\n\nand get:\n\n```yaml\nmerged_users:\n users:\n - sally\n - jane\n - bob\n - henry\n admins:\n - sally\n - bob\n```\n\nWhen merging dictionaries and the same key exists in both, the recursive merge checks the type of the value:\n* if the entry value is a list, it merges the values as lists (merge_list)\n* if the entry value is a dict, it merges the values (recursively) as dicts (merge_dict)\n* any other values: just replace (use last)\n\n### Module options ###\n\n| parameter | required | default | choices | comments |\n| --------- | -------- | ------- | ------- | -------- |\n| suffix_to_merge | yes | | | Suffix of variables to merge. Must end with `__to_merge`. |\n| merged_var_name | yes | | | Name of the target variable. |\n| expected_type | yes | | dict, list | Expected type of the merged variable (one of dict or list) |\n| dedup | no | yes | yes / no | Whether to remove duplicates from lists (arrays) after merging. |\n| cacheable | no | no | yes / no | If set to `yes`, the merged variable will be stored in the facts cache |\n| recursive_dict_merge | no | no | yes / no | Whether to do deep (recursive) merging of dictionaries, or just merge only at top level and replace values |\n\n## Verbosity\n\nRunning ansible-playbook with `-v` will cause this plugin to output the order in\nwhich the keys are being merged:\n\n```\nPLAY [Example of merging lists] ************************************************\n\nTASK [Merge port vars] *********************************************************\nMerging vars in this order: [ u'group1_ports__to_merge', u'group2_ports__to_merge', u'group3_ports__to_merge']\nok: [localhost] => {\"ansible_facts\": {\"merged_ports\": [22, 1111, 443, 2222, 80]}, \"changed\": false}\n\nTASK [debug] *******************************************************************\nok: [localhost] => {\n \"merged_ports\": [\n 22,\n 1111,\n 443,\n 2222,\n 80\n ]\n}\n\nPLAY RECAP *********************************************************************\nlocalhost : ok=6 changed=0 unreachable=0 failed=0\n```\n\n## Example Playbooks\n\nThere are some example playbooks in the `examples` directory that show how the\nvarious features work in the context of an actual Ansible playbook. These\nexample playbooks are run as part of the test suite for this plugin; if you\nwould like to run them yourself, please see the [Contributing](#contributing)\nsection for instructions on how to run the test suite.\n\n## Contributing\n\nPlease note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.\n\nThese are the only prerequisites to working on this project locally:\n\n 1. You have [Pipenv](https://docs.pipenv.org) installed.\n 1. You have the Python versions in the [.python-version](.python-version)\n installed and on your path (probably with\n [pyenv](https://github.com/pyenv/pyenv)\n\nA development workflow may look like this:\n\n 1. Clone this repository\n 1. Run `make deps`\n * This will use [Pipenv](https://docs.pipenv.org) to install all of the\n dependencies needed to build a release and run tests.\n 1. Run `make test-all`\n * This will use [tox](https://tox.readthedocs.io/en/latest/) to run the\n tests against different combinations of python versions and ansible\n releases.\n * It will also use [a script](bin/generate_tox_config.py) to query\n [PyPI](https://pypi.python.org) for the latest versions of Ansible, and\n add them to the `tox.ini` file if they're not there.\n\n 1. Updating the `tox.ini` file and running all the tests against all of the\n combinations of Ansible releases and Python versions takes a lot of time.\n To run aginst just one combination, you can list all of the combinations\n available and tell tox to only run the tests for one combination:\n\n ```\n $ pipenv run tox -l\n\n py27-ansible-2.1.0.0\n py27-ansible-2.1.1.0\n py27-ansible-2.1.2.0\n py27-ansible-2.1.3.0\n py27-ansible-2.2.0.0\n py27-ansible-2.2.1.0\n ...\n py35-ansible-2.5.1\n py35-ansible-2.5.2\n py36-ansible-2.5.0\n py36-ansible-2.5.1\n py36-ansible-2.5.2\n ...\n\n $ pipenv run tox -e py36-ansible-2.5.2\n ...\n ```\n\nIf you have any ideas about things to add or improve, or find any bugs to fix, we're all ears! Just a few guidelines:\n\n 1. Please write or update tests (either example-based tests, property-based\n tests, or both) for any code that you add, change, or remove.\n\n 1. Please add an example playbook or update an existing example playbook in\n the `examples` folder. These example playbooks serve as the integration\n tests for this plugin.\n\n 1. Please make sure that `make test-all` exits zero. This runs a code linter,\n all of the tests, and all of the examples against all supported versions\n of Python and Ansible.\n\n 1. If the linting seems too annoying, it probably is! Feel free to do what you\n need to do in the `.pylintrc` at the root of this repository to maintain\n sanity. Add it to your PR, and we'll most likely take it.\n\nHappy merging!", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/leapfrogonline/ansible-merge-vars", "keywords": "ansible plugin", "license": "", "maintainer": "", "maintainer_email": "", "name": "ansible-merge-vars", "package_url": "https://pypi.org/project/ansible-merge-vars/", "platform": "", "project_url": "https://pypi.org/project/ansible-merge-vars/", "project_urls": { "Bug Reports": "https://github.com/leapfrogonline/ansible-merge-vars/issues", "Homepage": "https://github.com/leapfrogonline/ansible-merge-vars", "Source": "https://github.com/leapfrogonline/ansible-merge-vars/" }, "release_url": "https://pypi.org/project/ansible-merge-vars/4.0.0/", "requires_dist": null, "requires_python": "", "summary": "An Ansible action plugin to explicitly merge inventory variables", "version": "4.0.0" }, "last_serial": 4468084, "releases": { "3.0.0": [ { "comment_text": "", "digests": { "md5": "0718b82973c17913b97758bd82a4da1c", "sha256": "b9e000ad757de61449deb1706fc7334dff13d745755af8668554b16f78cde33d" }, "downloads": -1, "filename": "ansible_merge_vars-3.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "0718b82973c17913b97758bd82a4da1c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10190, "upload_time": "2018-05-12T18:57:52", "url": "https://files.pythonhosted.org/packages/10/bc/f96b6b05b7f8ad07174df70aa08be446badb4ca23ed4058f1623d0ce1953/ansible_merge_vars-3.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f1ae9bffd618bd9cfc2603af3d98319a", "sha256": "52820ded2d723c02ebb820b848bd77e44d155944202fd9d4d2df0fe768d324f2" }, "downloads": -1, "filename": "ansible_merge_vars-3.0.0.tar.gz", "has_sig": false, "md5_digest": "f1ae9bffd618bd9cfc2603af3d98319a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20141, "upload_time": "2018-05-12T18:57:54", "url": "https://files.pythonhosted.org/packages/ed/81/047d2f33a3b879e267afe801d8f81c101147c73828d537a13bd1d95423fa/ansible_merge_vars-3.0.0.tar.gz" } ], "4.0.0": [ { "comment_text": "", "digests": { "md5": "d41585a2d07f06324d643fb1ee6c1f4b", "sha256": "ebe2720cecae2e07dd58fd514483d1669c89e05ca10ffcc947c6a083410b8023" }, "downloads": -1, "filename": "ansible_merge_vars-4.0.0.tar.gz", "has_sig": false, "md5_digest": "d41585a2d07f06324d643fb1ee6c1f4b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21230, "upload_time": "2018-11-09T03:30:25", "url": "https://files.pythonhosted.org/packages/58/7a/34c37321876ea08c3623b3f830b1d7e920166f3ddd49f98cf0ce5b0380b7/ansible_merge_vars-4.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d41585a2d07f06324d643fb1ee6c1f4b", "sha256": "ebe2720cecae2e07dd58fd514483d1669c89e05ca10ffcc947c6a083410b8023" }, "downloads": -1, "filename": "ansible_merge_vars-4.0.0.tar.gz", "has_sig": false, "md5_digest": "d41585a2d07f06324d643fb1ee6c1f4b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21230, "upload_time": "2018-11-09T03:30:25", "url": "https://files.pythonhosted.org/packages/58/7a/34c37321876ea08c3623b3f830b1d7e920166f3ddd49f98cf0ce5b0380b7/ansible_merge_vars-4.0.0.tar.gz" } ] }