108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
|
import os
|
||
|
|
||
|
from ansible import constants as C
|
||
|
from ansible.errors import AnsibleParserError
|
||
|
from ansible.module_utils._text import to_native
|
||
|
from ansible.plugins.inventory import BaseInventoryPlugin
|
||
|
|
||
|
|
||
|
DOCUMENTATION = """
|
||
|
name: group_creator
|
||
|
short_description: Uses Jinja2 templates to construct empty groups.
|
||
|
description:
|
||
|
- Uses a YAML configuration file with a valid YAML extension to define
|
||
|
groups. The groups' names as well as the list of parent groups for a
|
||
|
given group may use Jinja2 templates based on the host variables.
|
||
|
options:
|
||
|
plugin:
|
||
|
description:
|
||
|
- Token that ensures this is a source file for the C(group_creator)
|
||
|
plugin.
|
||
|
required: True
|
||
|
choices: ['group_creator']
|
||
|
groups:
|
||
|
description:
|
||
|
- The list of groups to create.
|
||
|
type: list
|
||
|
elements: dict
|
||
|
required: True
|
||
|
suboptions:
|
||
|
name:
|
||
|
description:
|
||
|
- The template to generate a group name from. If an empty
|
||
|
string is returned, the group will not be created.
|
||
|
type: str
|
||
|
required: true
|
||
|
parents:
|
||
|
description:
|
||
|
- A list of templates to generate the names of the group's
|
||
|
parents from. Empty strings will be ignored.
|
||
|
type: list
|
||
|
elements: str
|
||
|
default: []
|
||
|
strict:
|
||
|
description:
|
||
|
- If C(yes) make invalid templates a fatal error, otherwise skip and
|
||
|
continue.
|
||
|
required: False
|
||
|
type: bool
|
||
|
default: no
|
||
|
"""
|
||
|
|
||
|
|
||
|
class InventoryModule(BaseInventoryPlugin):
|
||
|
"""Constructs empty groups based on arbitrary variables."""
|
||
|
|
||
|
NAME = "group_creator"
|
||
|
|
||
|
def __init__(self):
|
||
|
super(InventoryModule, self).__init__()
|
||
|
|
||
|
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 _evaluate(self, template, variables, auto_template):
|
||
|
t = self.templar
|
||
|
if auto_template:
|
||
|
template = "%s%s%s" % (
|
||
|
t.environment.variable_start_string,
|
||
|
template,
|
||
|
t.environment.variable_end_string,
|
||
|
)
|
||
|
t.available_variables = variables
|
||
|
return t.template(template, disable_lookups=True)
|
||
|
|
||
|
def _get_group_name(self, host, name, host_vars, strict):
|
||
|
try:
|
||
|
name = self._evaluate(name, host_vars, False)
|
||
|
return self._sanitize_group_name(name)
|
||
|
except Exception as e:
|
||
|
if strict:
|
||
|
raise AnsibleParserError(
|
||
|
"Could not generate group name for host %s from '%s': (%s) %s"
|
||
|
% (host, name, to_native(repr(type(e))), to_native(e))
|
||
|
)
|
||
|
return ""
|
||
|
|
||
|
def parse(self, inventory, loader, path, cache=False):
|
||
|
super(InventoryModule, self).parse(inventory, loader, path, cache=cache)
|
||
|
self._read_config_data(path)
|
||
|
strict = self.get_option("strict")
|
||
|
for host in inventory.hosts:
|
||
|
host_vars = self.inventory.get_host(host).get_vars()
|
||
|
for group in self.get_option("groups"):
|
||
|
name = self._get_group_name(host, group['name'], host_vars, strict)
|
||
|
if not name:
|
||
|
continue
|
||
|
self.inventory.add_group(name)
|
||
|
for ptmpl in group.get("parents"):
|
||
|
parent = self._get_group_name(host, ptmpl, host_vars, strict)
|
||
|
if parent:
|
||
|
self.inventory.add_group(parent)
|
||
|
self.inventory.add_child(parent, name)
|