Skip to content

Instantly share code, notes, and snippets.

@willthames
Created October 31, 2017 01:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save willthames/f403ef75e5ba113277331eb85401ae8d to your computer and use it in GitHub Desktop.
Save willthames/f403ef75e5ba113277331eb85401ae8d to your computer and use it in GitHub Desktop.
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
name: generator
plugin_type: inventory
version_added: "2.5"
short_description: Uses Jinja2 to construct hosts and groups from patterns
description:
- Uses a YAML configuration file with a valid YAML or ``.config`` extension to define var expressions and group conditionals
- Create a pattern that describes all hosts, and use the elements of the pattern to define group membership
- Only variables already available from previous inventories or the fact cache can be used for templating.
- When ``strict`` is False, failed expressions will be ignored (assumes vars were missing).
'''
EXAMPLES = '''
# inventory.config file in YAML format
plugin: generator
strict: False
hosts:
name: "{{ operation }}-{{ application }}-{{ environment }}-runner"
parents:
- name: "{{ operation }}-{{ application }}-{{ environment }}"
parents:
- name: "{{ operation }}-{{ application }}"
parents:
- "{{ operation }}"
- "{{ application }}"
- name: "{{ application }}-{{ environment }}"
parents:
- "{{ application }}"
- "{{ environment }}"
- name: runner
layers:
operation:
- build
- launch
environment:
- dev
- test
- prod
application:
- web
- api
'''
import os
from collections import MutableMapping
from ansible import constants as C
from ansible.errors import AnsibleParserError
from ansible.plugins.cache import FactCache
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.module_utils._text import to_native
from itertools import product
class InventoryModule(BaseInventoryPlugin):
""" constructs groups and vars using Jinaj2 template expressions """
NAME = 'generator'
def __init__(self):
super(InventoryModule, self).__init__()
self._cache = FactCache()
def verify_file(self, path):
valid = False
if super(InventoryModule, self).verify_file(path):
file_name, ext = os.path.splitext(path)
if not ext or ext in ['.config'] + C.YAML_FILENAME_EXTENSIONS:
valid = True
return valid
def template(self, pattern, variables):
t = self.templar
t.set_available_variables(variables)
return t.do_template(pattern)
def add_parents(self, inventory, child, parents, template_vars):
for parent in parents:
group = self.template(parent['name'], template_vars)
if group not in inventory.groups:
inventory.add_group(group)
inventory.add_child(group, child)
self.add_parents(inventory, group, parent.get('parents', []), template_vars)
def parse(self, inventory, loader, path, cache=False):
''' parses the inventory file '''
super(InventoryModule, self).parse(inventory, loader, path, cache=cache)
try:
data = self.loader.load_from_file(path)
except Exception as e:
raise AnsibleParserError("Unable to parse %s: %s" % (to_native(path), to_native(e)))
if not data:
raise AnsibleParserError("%s is empty" % (to_native(path)))
elif not isinstance(data, MutableMapping):
raise AnsibleParserError('inventory source has invalid structure, it should be a dictionary, got: %s' % type(data))
elif data.get('plugin') != self.NAME:
raise AnsibleParserError("%s is not a generator groups config file, plugin entry must be 'generator'" % (to_native(path)))
template_inputs = product(*data.get('layers').values())
for item in template_inputs:
template_vars = dict()
for i, key in enumerate(data['layers'].keys()):
template_vars[key] = item[i]
host = self.template(data['hosts']['name'], template_vars)
inventory.add_host(host)
self.add_parents(inventory, host, data['hosts'].get('parents', []), template_vars)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment