Created
October 31, 2017 01:49
-
-
Save willthames/f403ef75e5ba113277331eb85401ae8d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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