better handling of diff key types in compose

also made separator configurable
fixed some exception types
better error msgs
pull/33550/merge
Brian Coca 7 years ago committed by Brian Coca
parent 38491fe93d
commit c679186f17

@ -24,9 +24,9 @@ import os
import re
import string
from collections import MutableMapping
from collections import Mapping
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.plugins import AnsiblePlugin
from ansible.plugins.cache import InventoryFileCacheModule
from ansible.module_utils._text import to_bytes, to_native
@ -159,7 +159,7 @@ class BaseInventoryPlugin(AnsiblePlugin):
return (os.path.exists(b_path) and os.access(b_path, os.R_OK))
def _populate_host_vars(self, hosts, variables, group=None, port=None):
if not isinstance(variables, MutableMapping):
if not isinstance(variables, Mapping):
raise AnsibleParserError("Invalid data from file, expected dictionary and got:\n\n%s" % to_native(variables))
for host in hosts:
@ -182,7 +182,7 @@ class BaseInventoryPlugin(AnsiblePlugin):
elif config.get('plugin') != self.NAME:
# this is not my config file
raise AnsibleParserError("Incorrect plugin name in file: %s" % config.get('plugin', 'none found'))
elif not isinstance(config, MutableMapping):
elif not isinstance(config, Mapping):
# configs are dictionaries
raise AnsibleParserError('inventory source has invalid structure, it should be a dictionary, got: %s' % type(config))
@ -253,7 +253,7 @@ class Constructable(object):
''' helper method for pluigns to compose variables for Ansible based on jinja2 expression and inventory vars'''
t = self.templar
t.set_available_variables(variables)
return t.do_template('%s%s%s' % (t.environment.variable_start_string, template, t.environment.variable_end_string), disable_lookups=True)
return t.template('%s%s%s' % (t.environment.variable_start_string, template, t.environment.variable_end_string), disable_lookups=True)
def _set_composite_vars(self, compose, variables, host, strict=False):
''' loops over compose entries to create vars for hosts '''
@ -263,7 +263,7 @@ class Constructable(object):
composite = self._compose(compose[varname], variables)
except Exception as e:
if strict:
raise AnsibleOptionsError("Could set %s: %s" % (varname, to_native(e)))
raise AnsibleError("Could not set %s: %s" % (varname, to_native(e)))
continue
self.inventory.set_variable(host, varname, composite)
@ -278,8 +278,9 @@ class Constructable(object):
result = boolean(self.templar.template(conditional))
except Exception as e:
if strict:
raise AnsibleOptionsError("Could not add to group %s: %s" % (group_name, to_native(e)))
raise AnsibleParserError("Could not add host %s to group %s: %s" % (host, group_name, to_native(e)))
continue
if result:
# ensure group exists
self.inventory.add_group(group_name)
@ -289,27 +290,40 @@ class Constructable(object):
def _add_host_to_keyed_groups(self, keys, variables, host, strict=False):
''' helper to create groups for plugins based on variable values and add the corresponding hosts to it'''
if keys and isinstance(keys, list):
groups = []
for keyed in keys:
if keyed and isinstance(keyed, dict):
prefix = keyed.get('prefix', '')
key = keyed.get('key')
if key is not None:
try:
groups = to_safe_group_name('%s_%s' % (prefix, self._compose(key, variables)))
except Exception as e:
if strict:
raise AnsibleOptionsError("Could not generate group on %s: %s" % (key, to_native(e)))
continue
if isinstance(groups, string_types):
groups = [groups]
if isinstance(groups, list):
for group_name in groups:
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
self.inventory.add_child(group_name, host)
try:
key = self._compose(keyed.get('key'), variables)
except Exception as e:
if strict:
raise AnsibleParserError("Could not generate group from %s entry: %s" % (keyed.get('key'), to_native(e)))
continue
if key:
prefix = keyed.get('prefix', '')
sep = keyed.get('separator', '_')
if isinstance(key, string_types):
groups.append('%s%s%s' % (prefix, sep, key))
elif isinstance(key, list):
for name in key:
groups.append('%s%s%s' % (prefix, sep, name))
elif isinstance(key, Mapping):
for (gname, gval) in key.items():
name = '%s%s%s' % (gname, sep, gval)
groups.append('%s%s%s' % (prefix, sep, name))
else:
raise AnsibleOptionsError("Invalid group name format, expected string or list of strings, got: %s" % type(groups))
raise AnsibleParserError("Invalid group name format, expected a string or a list of them or dictionary, got: %s" % type(key))
else:
raise AnsibleOptionsError("No key supplied, invalid entry")
if strict:
raise AnsibleParserError("No key or key resulted empty, invalid entry")
else:
raise AnsibleOptionsError("Invalid keyed group entry, it must be a dictionary: %s " % keyed)
raise AnsibleParserError("Invalid keyed group entry, it must be a dictionary: %s " % keyed)
# now actually add any groups
for group_name in groups:
gname = to_safe_group_name(group_name)
self.inventory.add_group(gname)
self.inventory.add_child(gname, host)

@ -43,7 +43,8 @@ EXAMPLES = '''
multi_group: (group_names|intersection(['alpha', 'beta', 'omega']))|length >= 2
keyed_groups:
# this creates a group per distro (distro_CentOS, distro_Debian) and assigns the hosts that have matching values to it
# this creates a group per distro (distro_CentOS, distro_Debian) and assigns the hosts that have matching values to it,
# using the default separator "_"
- prefix: distro
key: ansible_distribution

Loading…
Cancel
Save