Skip to content

Instantly share code, notes, and snippets.

@cthiemann
Created June 10, 2015 22:12
Show Gist options
  • Save cthiemann/220c128e298614a869f2 to your computer and use it in GitHub Desktop.
Save cthiemann/220c128e298614a869f2 to your computer and use it in GitHub Desktop.
Ansible plugins for adding !platform YAML tag
from ansible.errors import AnsibleFilterError
def selectby(value, keys, default=None, loop_over_seq=True, filter_seq=None):
if not isinstance(keys, list):
keys = [keys] # make sure we have a list of keys
keys.append(':') # append the 'default' key
if isinstance(value, list) and loop_over_seq:
# apply selectby to each value in the list and filter the results
return filter(filter_seq, [ selectby(v, keys, loop_over_seq=False) for v in value ])
if not isinstance(value, dict):
# return value unmodified
return value
# if the value contains only a single key ending with a colon,
# that key (with the colon stripped) is used as the default value,
# and the value of that key is used as the lookup dictionary
# (i.e., 'value' can provide an override for 'default')
if len(value) == 1:
k = value.keys()[0]
if k[-1] == ':':
default = k[:-1]
value = value.values()[0]
if not isinstance(value, dict):
raise AnsibleFilterError('value of default override must be a dict')
# search for keys in dict value and return first match
for k in keys:
if k in value:
return value[k]
# none of the keys is in dict value
return default
class FilterModule(object):
def filters(self):
return dict(selectby=selectby)
import re
import yaml
from ansible.inventory.vars_plugins import noop
def repr_jinja(x):
if isinstance(x, list):
x = [ repr_jinja(e) for e in x ]
return '[' + ', '.join(x) + ']'
if isinstance(x, dict):
x = [ repr_jinja(k) + ': ' + repr_jinja(v) for (k, v) in x.iteritems() ]
return '{' + ', '.join(x) + '}'
if isinstance(x, str):
# FIXME: recognize escaped brackets
m = re.match('^(.*?){{(.*?)}}(.*)$', x)
if m:
x = '(' + m.group(2).strip() + ')'
if m.group(1):
x = repr_jinja(m.group(1)) + ' + ' + x
if m.group(3):
x = x + ' + ' + repr_jinja(m.group(3))
return x
else:
return repr(x)
return repr(x)
def selectby_platform_constructor(loader, node):
if isinstance(node, yaml.ScalarNode):
return node.value # simple values don't need to be run through |selectby
elif isinstance(node, yaml.SequenceNode):
value = loader.construct_sequence(node, deep=True)
elif isinstance(node, yaml.MappingNode):
value = loader.construct_mapping(node, deep=True)
else:
raise yaml.ConstructorError('unknown node type: ' + type(node))
return '{{ ' + repr_jinja(value) + '|selectby(ansible_platform) }}'
for loader in ['Loader', 'SafeLoader', 'CLoader', 'CSafeLoader']:
if hasattr(yaml, loader):
getattr(yaml, loader).add_constructor('!platform', selectby_platform_constructor)
class VarsModule(noop.VarsModule):
def get_host_vars(self, host, vault_password=None):
# inject the ansible_platform variable used by the !platform tag
platform = [
'{{ ansible_distribution }}_{{ ansible_distribution_version }}',
'{{ ansible_distribution }}{{ ansible_distribution_major_version }}',
'd{{ ansible_distribution }}', # allow explicit matching if distro == family
'{{ ansible_distribution }}',
'f{{ ansible_os_family }}', # allow explicit matching if distro == family
'{{ ansible_os_family }}',
'default',
]
return dict(ansible_platform=platform)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment