Skip to content

Instantly share code, notes, and snippets.

@Timoses
Last active December 17, 2020 17:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Timoses/17c39a100350eeedb10d77ab39b9eceb to your computer and use it in GitHub Desktop.
Save Timoses/17c39a100350eeedb10d77ab39b9eceb to your computer and use it in GitHub Desktop.
Ansible vars_plugin to load r_group_vars recursively from
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
vars: recursive_group_vars
version_added: "?"
short_description: Loads group_vars recursively
description:
- In comparision to host_group_vars plugin, this plugin traverses the `r_group_vars` directory and instead of matching all files and directories within the first matching directory it traverses the directoy tree and recursively matches directories and files during directory traversal to groups
- If a file matching the group is found during traversal of a directory it is applied
- The deepest found matching file is applied last
- If several matching directories are found on the same level they are traversed consecutively (depth-first). This means that on the same level, the existing priorities apply (see [How variables are merged](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#how-variables-are-merged))
- On the same directory level, a matching file will be applied first and then matching directories are traversed
- Only files that match a group are applied. Any other files are ignored.
- The following points are identical to host_group_vars plugin:
- Files are restricted by extension to one of .yaml, .json, .yml or no extension.
- Hidden (starting with '.') and backup (ending with '~') files and directories are ignored.
- Only applies to inventory sources that are existing paths.
options:
_valid_extensions:
default: [".yml", ".yaml", ".json"]
description:
- "Check all of these extensions when looking for 'variable' files which should be YAML or JSON or vaulted versions of these."
- 'This affects vars_files, include_vars, inventory and vars plugins among others.'
env:
- name: ANSIBLE_YAML_FILENAME_EXT
ini:
- section: yaml_valid_extensions
key: defaults
type: list
'''
import os
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.errors import AnsibleParserError
from ansible.plugins.vars import BaseVarsPlugin
from ansible.inventory.group import Group
from ansible.utils.vars import combine_vars
FOUND = {}
class VarsModule(BaseVarsPlugin):
def find_vars_recurse(self, loader, groups, path):
data = {}
found_files = []
for group in groups:
b_opath = os.path.realpath(to_bytes(os.path.join(path, group.name)))
if os.path.exists(b_opath):
try:
found_files = loader.find_vars_files(path, group.name, allow_dir=False)
for found in found_files:
new_data = loader.load_from_file(found, cache=True, unsafe=True)
if new_data:
data = combine_vars(data, new_data)
except Exception as e:
raise AnsibleParserError(to_native(e))
if os.path.isdir(b_opath):
data = combine_vars(data,
self.find_vars_recurse(loader, groups, to_text(b_opath)))
return data
def get_vars(self, loader, path, entities, cache=True):
if not isinstance(entities, list):
entities = [entities]
groups = list(filter(lambda ent : isinstance(ent, Group), entities))
if not groups:
return dict()
super(VarsModule, self).get_vars(loader, path, entities)
b_opath = os.path.realpath(to_bytes(os.path.join(self._basedir, 'r_group_vars')))
data = {}
if os.path.exists(b_opath):
key = '.'.join(list(map(lambda group : group.name, groups)) + [to_text(b_opath)])
if cache and key in FOUND:
data = FOUND[key]
else:
data = self.find_vars_recurse(loader, groups, to_text(b_opath))
FOUND[key] = data
return data
@Shm013
Copy link

Shm013 commented Sep 4, 2019

Hello! I relay want to use yours code. Can you insert copyright header into this code please.

@Timoses
Copy link
Author

Timoses commented Sep 10, 2019

Hi, glad you're interested.

I've created a PR: ansible/ansible#60593 (review)
Would this suffice?

Otherwise let me know and I see what I can do (never dealt with copyright headers before; so a pointer is welcome).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment