mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Make lookup plugin replacements part of the main variable logic
This commit is contained in:
parent
f91fa9f765
commit
d2dce1d63f
2 changed files with 79 additions and 89 deletions
|
@ -33,7 +33,7 @@ import pwd
|
||||||
_LISTRE = re.compile(r"(\w+)\[(\d+)\]")
|
_LISTRE = re.compile(r"(\w+)\[(\d+)\]")
|
||||||
|
|
||||||
|
|
||||||
def _varFindLimitSpace(vars, space, part, depth):
|
def _varFindLimitSpace(basedir, vars, space, part, depth):
|
||||||
''' limits the search space of space to part
|
''' limits the search space of space to part
|
||||||
|
|
||||||
basically does space.get(part, None), but with
|
basically does space.get(part, None), but with
|
||||||
|
@ -47,7 +47,7 @@ def _varFindLimitSpace(vars, space, part, depth):
|
||||||
if part[0] == '{' and part[-1] == '}':
|
if part[0] == '{' and part[-1] == '}':
|
||||||
part = part[1:-1]
|
part = part[1:-1]
|
||||||
# Template part to resolve variables within (${var$var2})
|
# Template part to resolve variables within (${var$var2})
|
||||||
part = varReplace(part, vars, depth=depth + 1)
|
part = varReplace(basedir, part, vars, depth=depth + 1)
|
||||||
|
|
||||||
# Now find it
|
# Now find it
|
||||||
if part in space:
|
if part in space:
|
||||||
|
@ -66,7 +66,7 @@ def _varFindLimitSpace(vars, space, part, depth):
|
||||||
|
|
||||||
return space
|
return space
|
||||||
|
|
||||||
def _varFind(text, vars, depth=0):
|
def _varFind(basedir, text, vars, depth=0):
|
||||||
''' Searches for a variable in text and finds its replacement in vars
|
''' Searches for a variable in text and finds its replacement in vars
|
||||||
|
|
||||||
The variables can have two formats;
|
The variables can have two formats;
|
||||||
|
@ -105,15 +105,28 @@ def _varFind(text, vars, depth=0):
|
||||||
var_start += 1
|
var_start += 1
|
||||||
else:
|
else:
|
||||||
is_complex = False
|
is_complex = False
|
||||||
brace_level = 0
|
brace_level = 1
|
||||||
|
# is_lookup is true for $FILE(...) and friends
|
||||||
|
is_lookup = False
|
||||||
|
lookup_plugin_name = None
|
||||||
end = var_start
|
end = var_start
|
||||||
# part_start is a tuple of where the current part started and its current brace_level
|
# part_start is an index of where the current part started
|
||||||
# brace_level is used to implement .-escaping
|
part_start = var_start
|
||||||
part_start = (var_start, brace_level)
|
|
||||||
space = vars
|
space = vars
|
||||||
while end < len(text) and ((is_complex and brace_level > 0) or not is_complex):
|
while end < len(text) and (((is_lookup or is_complex) and brace_level > 0) or (not is_complex and not is_lookup)):
|
||||||
if text[end].isalnum() or text[end] == '_':
|
if text[end].isalnum() or text[end] == '_':
|
||||||
pass
|
pass
|
||||||
|
elif not is_complex and not is_lookup and text[end] == '(' and text[part_start:end].isupper():
|
||||||
|
is_lookup = True
|
||||||
|
lookup_plugin_name = text[part_start:end]
|
||||||
|
part_start = end + 1
|
||||||
|
elif is_lookup and text[end] == '(':
|
||||||
|
brace_level += 1
|
||||||
|
elif is_lookup and text[end] == ')':
|
||||||
|
brace_level -= 1
|
||||||
|
elif is_lookup:
|
||||||
|
# lookups are allowed arbitrary contents
|
||||||
|
pass
|
||||||
elif is_complex and text[end] == '{':
|
elif is_complex and text[end] == '{':
|
||||||
brace_level += 1
|
brace_level += 1
|
||||||
elif is_complex and text[end] == '}':
|
elif is_complex and text[end] == '}':
|
||||||
|
@ -121,23 +134,44 @@ def _varFind(text, vars, depth=0):
|
||||||
elif is_complex and text[end] in ('$', '[', ']'):
|
elif is_complex and text[end] in ('$', '[', ']'):
|
||||||
pass
|
pass
|
||||||
elif is_complex and text[end] == '.':
|
elif is_complex and text[end] == '.':
|
||||||
if brace_level == part_start[1]:
|
if brace_level == 1:
|
||||||
space = _varFindLimitSpace(vars, space, text[part_start[0]:end], depth)
|
space = _varFindLimitSpace(basedir, vars, space, text[part_start:end], depth)
|
||||||
part_start = (end + 1, brace_level)
|
part_start = end + 1
|
||||||
else:
|
else:
|
||||||
|
# This breaks out of the loop on non-variable name characters
|
||||||
break
|
break
|
||||||
end += 1
|
end += 1
|
||||||
var_end = end
|
var_end = end
|
||||||
|
# Handle "This has $ in it"
|
||||||
|
if var_end == part_start:
|
||||||
|
return {'replacement': None, 'start': start, 'end': end}
|
||||||
|
|
||||||
|
# Handle lookup plugins
|
||||||
|
if is_lookup:
|
||||||
|
# When basedir is None, handle lookup plugins later
|
||||||
|
if basedir is None:
|
||||||
|
return {'replacement': None, 'start': start, 'end': end}
|
||||||
|
var_end -= 1
|
||||||
|
from ansible import utils
|
||||||
|
args = text[part_start:var_end]
|
||||||
|
if lookup_plugin_name == 'LOOKUP':
|
||||||
|
lookup_plugin_name, args = args.split(",", 1)
|
||||||
|
args = args.strip()
|
||||||
|
instance = utils.plugins.lookup_loader.get(lookup_plugin_name.lower(), basedir=basedir)
|
||||||
|
if instance is not None:
|
||||||
|
replacement = instance.run(args, inject=vars)
|
||||||
|
else:
|
||||||
|
replacement = None
|
||||||
|
return {'replacement': replacement, 'start': start, 'end': end}
|
||||||
|
|
||||||
if is_complex:
|
if is_complex:
|
||||||
var_end -= 1
|
var_end -= 1
|
||||||
if text[var_end] != '}' or brace_level != 0:
|
if text[var_end] != '}' or brace_level != 0:
|
||||||
return None
|
return None
|
||||||
if var_end == part_start[0]:
|
space = _varFindLimitSpace(basedir, vars, space, text[part_start:var_end], depth)
|
||||||
return {'replacement': '$', 'start': start, 'end': end}
|
|
||||||
space = _varFindLimitSpace(vars, space, text[part_start[0]:var_end], depth)
|
|
||||||
return {'replacement': space, 'start': start, 'end': end}
|
return {'replacement': space, 'start': start, 'end': end}
|
||||||
|
|
||||||
def varReplace(raw, vars, depth=0, expand_lists=False):
|
def varReplace(basedir, raw, vars, depth=0, expand_lists=False):
|
||||||
''' Perform variable replacement of $variables in string raw using vars dictionary '''
|
''' Perform variable replacement of $variables in string raw using vars dictionary '''
|
||||||
# this code originally from yum
|
# this code originally from yum
|
||||||
|
|
||||||
|
@ -147,7 +181,7 @@ def varReplace(raw, vars, depth=0, expand_lists=False):
|
||||||
done = [] # Completed chunks to return
|
done = [] # Completed chunks to return
|
||||||
|
|
||||||
while raw:
|
while raw:
|
||||||
m = _varFind(raw, vars, depth)
|
m = _varFind(basedir, raw, vars, depth)
|
||||||
if not m:
|
if not m:
|
||||||
done.append(raw)
|
done.append(raw)
|
||||||
break
|
break
|
||||||
|
@ -159,7 +193,7 @@ def varReplace(raw, vars, depth=0, expand_lists=False):
|
||||||
if expand_lists and isinstance(replacement, (list, tuple)):
|
if expand_lists and isinstance(replacement, (list, tuple)):
|
||||||
replacement = ",".join(replacement)
|
replacement = ",".join(replacement)
|
||||||
if isinstance(replacement, (str, unicode)):
|
if isinstance(replacement, (str, unicode)):
|
||||||
replacement = varReplace(replacement, vars, depth=depth+1, expand_lists=expand_lists)
|
replacement = varReplace(basedir, replacement, vars, depth=depth+1, expand_lists=expand_lists)
|
||||||
if replacement is None:
|
if replacement is None:
|
||||||
replacement = raw[m['start']:m['end']]
|
replacement = raw[m['start']:m['end']]
|
||||||
|
|
||||||
|
@ -170,53 +204,11 @@ def varReplace(raw, vars, depth=0, expand_lists=False):
|
||||||
|
|
||||||
return ''.join(done)
|
return ''.join(done)
|
||||||
|
|
||||||
_FILEPIPECRE = re.compile(r"\$(?P<special>[A-Z]+)\(([^\)]*)\)")
|
|
||||||
def _varReplaceLookups(basedir, raw, vars):
|
|
||||||
from ansible import utils
|
|
||||||
done = [] # Completed chunks to return
|
|
||||||
|
|
||||||
while raw:
|
|
||||||
m = _FILEPIPECRE.search(raw)
|
|
||||||
if not m:
|
|
||||||
done.append(raw)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Determine replacement value (if unknown lookup plugin then preserve
|
|
||||||
# original)
|
|
||||||
|
|
||||||
replacement = m.group()
|
|
||||||
if m.group(1) == "FILE":
|
|
||||||
module_name = "file"
|
|
||||||
args = m.group(2)
|
|
||||||
elif m.group(1) == "PIPE":
|
|
||||||
module_name = "pipe"
|
|
||||||
args = m.group(2)
|
|
||||||
elif m.group(1) == "LOOKUP":
|
|
||||||
module_name, args = m.group(2).split(",", 1)
|
|
||||||
args = args.strip()
|
|
||||||
else:
|
|
||||||
module_name = m.group(1).lower()
|
|
||||||
args = m.group(2)
|
|
||||||
instance = utils.plugins.lookup_loader.get(module_name, basedir=basedir)
|
|
||||||
if instance is not None:
|
|
||||||
replacement = instance.run(args, inject=vars)
|
|
||||||
if not isinstance(replacement, basestring):
|
|
||||||
replacement = ",".join(replacement)
|
|
||||||
else:
|
|
||||||
replacement = m.group(0)
|
|
||||||
|
|
||||||
start, end = m.span()
|
|
||||||
done.append(raw[:start]) # Keep stuff leading up to token
|
|
||||||
done.append(replacement.rstrip()) # Append replacement value
|
|
||||||
raw = raw[end:] # Continue with remainder of string
|
|
||||||
|
|
||||||
return ''.join(done)
|
|
||||||
|
|
||||||
def template_ds(basedir, varname, vars):
|
def template_ds(basedir, varname, vars):
|
||||||
''' templates a data structure by traversing it and substituting for other data structures '''
|
''' templates a data structure by traversing it and substituting for other data structures '''
|
||||||
|
|
||||||
if isinstance(varname, basestring):
|
if isinstance(varname, basestring):
|
||||||
m = _varFind(varname, vars)
|
m = _varFind(basedir, varname, vars)
|
||||||
if not m:
|
if not m:
|
||||||
return varname
|
return varname
|
||||||
if m['start'] == 0 and m['end'] == len(varname):
|
if m['start'] == 0 and m['end'] == len(varname):
|
||||||
|
@ -243,9 +235,7 @@ def template(basedir, text, vars, expand_lists=False):
|
||||||
text = text.decode('utf-8')
|
text = text.decode('utf-8')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
pass # already unicode
|
pass # already unicode
|
||||||
text = varReplace(unicode(text), vars, expand_lists=expand_lists)
|
text = varReplace(basedir, unicode(text), vars, expand_lists=expand_lists)
|
||||||
if basedir is not None:
|
|
||||||
text = _varReplaceLookups(basedir, text, vars)
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def template_from_file(basedir, path, vars):
|
def template_from_file(basedir, path, vars):
|
||||||
|
|
|
@ -15,14 +15,14 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
def test_varReplace_trailing_dollar(self):
|
def test_varReplace_trailing_dollar(self):
|
||||||
template = '$what $who $'
|
template = '$what $who $'
|
||||||
vars = dict(what='hello', who='world')
|
vars = dict(what='hello', who='world')
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'hello world $'
|
assert res == 'hello world $'
|
||||||
|
|
||||||
def test_varReplace_multiple(self):
|
def test_varReplace_multiple(self):
|
||||||
|
@ -32,7 +32,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'whoVar': 'world',
|
'whoVar': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
print res
|
print res
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world!'
|
assert res == 'hello world!'
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world}'
|
assert res == 'hello world}'
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == template
|
assert res == template
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': 'world',
|
'who': 'world',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world }'
|
assert res == 'hello world }'
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class TestUtils(unittest.TestCase):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
print res
|
print res
|
||||||
assert res == template
|
assert res == template
|
||||||
|
@ -117,7 +117,7 @@ class TestUtils(unittest.TestCase):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'what': 'hello',
|
'what': 'hello',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello 2'
|
assert res == 'hello 2'
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'who': u'wórld',
|
'who': u'wórld',
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == u'hello wórld'
|
assert res == u'hello wórld'
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'data': [ 'no-one', 'world' ]
|
'data': [ 'no-one', 'world' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'data': [ 'no-one', 'world' ]
|
'data': [ 'no-one', 'world' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == template
|
assert res == template
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'data': [ 'no-one', 'world' ]
|
'data': [ 'no-one', 'world' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == template
|
assert res == template
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'data': { 'no-one': 0, 'world': 1 }
|
'data': { 'no-one': 0, 'world': 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == template
|
assert res == template
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'data': [ 'no-one', {'msg': [ 'world'] } ]
|
'data': [ 'no-one', {'msg': [ 'world'] } ]
|
||||||
}
|
}
|
||||||
|
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
|
|
||||||
assert res == 'hello world'
|
assert res == 'hello world'
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ class TestUtils(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
template = '${foo}${bar}'
|
template = '${foo}${bar}'
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'foobar'
|
assert res == 'foobar'
|
||||||
|
|
||||||
def test_varReplace_escape_dot(self):
|
def test_varReplace_escape_dot(self):
|
||||||
|
@ -214,7 +214,7 @@ class TestUtils(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
template = '${hostvars.{test.example.com}.foo}'
|
template = '${hostvars.{test.example.com}.foo}'
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'bar'
|
assert res == 'bar'
|
||||||
|
|
||||||
def test_varReplace_list_join(self):
|
def test_varReplace_list_join(self):
|
||||||
|
@ -227,7 +227,7 @@ class TestUtils(unittest.TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
template = 'yum pkg=${list} state=installed'
|
template = 'yum pkg=${list} state=installed'
|
||||||
res = ansible.utils.varReplace(template, vars, expand_lists=True)
|
res = ansible.utils.varReplace(None, template, vars, expand_lists=True)
|
||||||
assert res == 'yum pkg=foo,bar,baz state=installed'
|
assert res == 'yum pkg=foo,bar,baz state=installed'
|
||||||
|
|
||||||
def test_varReplace_escaped_var(self):
|
def test_varReplace_escaped_var(self):
|
||||||
|
@ -235,7 +235,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'foo': 'bar',
|
'foo': 'bar',
|
||||||
}
|
}
|
||||||
template = 'action \$foo'
|
template = 'action \$foo'
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'action $foo'
|
assert res == 'action $foo'
|
||||||
|
|
||||||
def test_varReplace_var_part(self):
|
def test_varReplace_var_part(self):
|
||||||
|
@ -246,7 +246,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'key': 'bar',
|
'key': 'bar',
|
||||||
}
|
}
|
||||||
template = 'test ${foo.$key}'
|
template = 'test ${foo.$key}'
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'test result'
|
assert res == 'test result'
|
||||||
|
|
||||||
def test_varReplace_var_partial_part(self):
|
def test_varReplace_var_partial_part(self):
|
||||||
|
@ -257,7 +257,7 @@ class TestUtils(unittest.TestCase):
|
||||||
'key': 'bar',
|
'key': 'bar',
|
||||||
}
|
}
|
||||||
template = 'test ${foo.${key}baz}'
|
template = 'test ${foo.${key}baz}'
|
||||||
res = ansible.utils.varReplace(template, vars)
|
res = ansible.utils.varReplace(None, template, vars)
|
||||||
assert res == 'test result'
|
assert res == 'test result'
|
||||||
|
|
||||||
def test_template_varReplace_iterated(self):
|
def test_template_varReplace_iterated(self):
|
||||||
|
@ -274,14 +274,14 @@ class TestUtils(unittest.TestCase):
|
||||||
def test_varReplace_include(self):
|
def test_varReplace_include(self):
|
||||||
template = 'hello $FILE(world) $LOOKUP(file, world)'
|
template = 'hello $FILE(world) $LOOKUP(file, world)'
|
||||||
|
|
||||||
res = ansible.utils.template("test", template, {})
|
res = ansible.utils.template("test", template, {}, expand_lists=True)
|
||||||
|
|
||||||
assert res == u'hello world world'
|
assert res == u'hello world world'
|
||||||
|
|
||||||
def test_varReplace_include_script(self):
|
def test_varReplace_include_script(self):
|
||||||
template = 'hello $PIPE(echo world) $LOOKUP(pipe, echo world)'
|
template = 'hello $PIPE(echo world) $LOOKUP(pipe, echo world)'
|
||||||
|
|
||||||
res = ansible.utils.template("test", template, {})
|
res = ansible.utils.template("test", template, {}, expand_lists=True)
|
||||||
|
|
||||||
assert res == u'hello world world'
|
assert res == u'hello world world'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue