114 lines
3.8 KiB
Python
114 lines
3.8 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
'''
|
||
|
Forked version of lookup.py by Georg Pfuetzenreuter <georg+salt@lysergic.dev>.
|
||
|
Notable changes:
|
||
|
- Python 3 support
|
||
|
- nested pillar lookups
|
||
|
Original: https://github.com/vmware-archive/salt-contrib/blob/master/pillars/lookup.py
|
||
|
|
||
|
Look up data from other pillar values or by executing a module function.
|
||
|
|
||
|
Usage:
|
||
|
|
||
|
Generally, this module should be configured as the final ext_pillar, if other
|
||
|
ext_pillars are used.
|
||
|
|
||
|
A pillar value matching the pattern ${...} will trigger this module to perform
|
||
|
a lookup. A lookup may be a pillar value (e.g., ${other_value}) or a call to
|
||
|
an execution module (${cmd.run('echo "foo"')}). Note that module functions are
|
||
|
executed on the master. Nested functions are supported, as is the passing of
|
||
|
a pillar value to a function. E.g.: ${cmd.run(command)}
|
||
|
|
||
|
'''
|
||
|
|
||
|
# O Import python libs
|
||
|
import inspect
|
||
|
import logging
|
||
|
import ast
|
||
|
import re
|
||
|
|
||
|
# Import salt libs
|
||
|
import salt.utils
|
||
|
|
||
|
# debug
|
||
|
import json
|
||
|
|
||
|
__virtualname__ = 'lookup'
|
||
|
|
||
|
|
||
|
def __virtual__():
|
||
|
return __virtualname__
|
||
|
|
||
|
|
||
|
# Set up logging
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
def ext_pillar(minion_id, pillar, *args, **kwargs):
|
||
|
def process(o):
|
||
|
log.debug('lookup.py: Processing')
|
||
|
if isinstance(o, ast.Call):
|
||
|
log.debug('lookup.py: is astCall')
|
||
|
f = '{0}.{1}'.format(o.func.value.id, o.func.attr)
|
||
|
args = [process(a) for a in o.args]
|
||
|
kwargs = dict((k.arg, process(k.value))
|
||
|
for k in o.keywords)
|
||
|
func = __salt__[f]
|
||
|
spec = inspect.getargspec(func)
|
||
|
if ('pillar' in spec.args or
|
||
|
spec.keywords is not None):
|
||
|
kwargs['pillar'] = pillar
|
||
|
if ('minion_id' in spec.args or
|
||
|
spec.keywords is not None):
|
||
|
kwargs['minion_id'] = minion_id
|
||
|
return func(*args, **kwargs)
|
||
|
elif isinstance(o, ast.Name):
|
||
|
log.debug('lookup.py: is astName')
|
||
|
myret = salt.utils.data.traverse_dict_and_list(pillar, o.id, 'x', ':')
|
||
|
log.debug('lookup.py: returning ' + json.dumps(myret))
|
||
|
return myret
|
||
|
elif isinstance(o, ast.Expr):
|
||
|
log.debug('lookup.py: is astExpr')
|
||
|
return process(o.value)
|
||
|
elif isinstance(o, ast.Str) and ':' in ast.literal_eval(o):
|
||
|
log.debug('lookup.py: is astStr with colon')
|
||
|
saltret = salt.utils.data.traverse_dict_and_list(pillar, ast.literal_eval(o), 'x', ':')
|
||
|
log.debug('lookup.py: returning ' + json.dumps(saltret))
|
||
|
return(saltret)
|
||
|
else:
|
||
|
log.debug('lookup.py: is useless')
|
||
|
log.debug(ast.dump(ast.parse(o)))
|
||
|
return ast.literal_eval(o)
|
||
|
|
||
|
|
||
|
def walk(data):
|
||
|
log.debug('lookup.py: Walking')
|
||
|
def process_val(k, v):
|
||
|
if isinstance(v, dict) or isinstance(v, list):
|
||
|
log.debug('lookup.py: Skipping ' + json.dumps(v))
|
||
|
walk(v)
|
||
|
elif isinstance(v, bytes) or isinstance(v, str):
|
||
|
log.debug('lookup.py: Examining ' + v)
|
||
|
m = re.search('^\$\{(.*)\}$', v)
|
||
|
if m:
|
||
|
log.debug('lookup.py: Match!')
|
||
|
s = m.groups()[0]
|
||
|
log.debug('lookup.py: sending ' + s + ' for processing')
|
||
|
#if ':' in s:
|
||
|
# log.debug('lookup.py: processing as string')
|
||
|
# process(s)
|
||
|
#else:
|
||
|
#log.debug('lookup.py: processing with AST')
|
||
|
data[k] = process(ast.parse(s).body[0].value)
|
||
|
|
||
|
if isinstance(data, dict):
|
||
|
for k, v in data.items():
|
||
|
process_val(k, v)
|
||
|
elif isinstance(data, list):
|
||
|
i = 0
|
||
|
for v in data:
|
||
|
process_val(i, v)
|
||
|
i = i+1
|
||
|
|
||
|
walk(pillar)
|