@ -10,10 +10,7 @@ import ast
from itertools import islice , chain
from itertools import islice , chain
from types import GeneratorType
from types import GeneratorType
from jinja2 . runtime import StrictUndefined
from ansible . module_utils . _text import to_text
from ansible . module_utils . _text import to_text
from ansible . module_utils . common . collections import is_sequence , Mapping
from ansible . module_utils . six import string_types
from ansible . module_utils . six import string_types
from ansible . parsing . yaml . objects import AnsibleVaultEncryptedUnicode
from ansible . parsing . yaml . objects import AnsibleVaultEncryptedUnicode
from ansible . utils . native_jinja import NativeJinjaText
from ansible . utils . native_jinja import NativeJinjaText
@ -34,29 +31,6 @@ class Json2Python(ast.NodeTransformer):
return ast . Constant ( value = _JSON_MAP [ node . id ] )
return ast . Constant ( value = _JSON_MAP [ node . id ] )
def _fail_on_undefined ( data ) :
""" Recursively find an undefined value in a nested data structure
and properly raise the undefined exception .
"""
if isinstance ( data , Mapping ) :
for value in data . values ( ) :
_fail_on_undefined ( value )
elif is_sequence ( data ) :
for item in data :
_fail_on_undefined ( item )
else :
if isinstance ( data , StrictUndefined ) :
# To actually raise the undefined exception we need to
# access the undefined object otherwise the exception would
# be raised on the next access which might not be properly
# handled.
# See https://github.com/ansible/ansible/issues/52158
# and StrictUndefined implementation in upstream Jinja2.
str ( data )
return data
def ansible_eval_concat ( nodes ) :
def ansible_eval_concat ( nodes ) :
""" Return a string of concatenated compiled nodes. Throw an undefined error
""" Return a string of concatenated compiled nodes. Throw an undefined error
if any of the nodes is undefined .
if any of the nodes is undefined .
@ -73,7 +47,7 @@ def ansible_eval_concat(nodes):
return ' '
return ' '
if len ( head ) == 1 :
if len ( head ) == 1 :
out = _fail_on_undefined( head[ 0 ] )
out = head[ 0 ]
if isinstance ( out , NativeJinjaText ) :
if isinstance ( out , NativeJinjaText ) :
return out
return out
@ -82,7 +56,7 @@ def ansible_eval_concat(nodes):
else :
else :
if isinstance ( nodes , GeneratorType ) :
if isinstance ( nodes , GeneratorType ) :
nodes = chain ( head , nodes )
nodes = chain ( head , nodes )
out = ' ' . join ( [ to_text ( _fail_on_undefined( v) ) for v in nodes ] )
out = ' ' . join ( [ to_text ( v) for v in nodes ] )
# if this looks like a dictionary, list or bool, convert it to such
# if this looks like a dictionary, list or bool, convert it to such
if out . startswith ( ( ' { ' , ' [ ' ) ) or out in ( ' True ' , ' False ' ) :
if out . startswith ( ( ' { ' , ' [ ' ) ) or out in ( ' True ' , ' False ' ) :
@ -111,7 +85,7 @@ def ansible_concat(nodes):
Used in Templar . template ( ) when jinja2_native = False and convert_data = False .
Used in Templar . template ( ) when jinja2_native = False and convert_data = False .
"""
"""
return ' ' . join ( [ to_text ( _fail_on_undefined( v) ) for v in nodes ] )
return ' ' . join ( [ to_text ( v) for v in nodes ] )
def ansible_native_concat ( nodes ) :
def ansible_native_concat ( nodes ) :
@ -129,7 +103,7 @@ def ansible_native_concat(nodes):
return None
return None
if len ( head ) == 1 :
if len ( head ) == 1 :
out = _fail_on_undefined( head[ 0 ] )
out = head[ 0 ]
# TODO send unvaulted data to literal_eval?
# TODO send unvaulted data to literal_eval?
if isinstance ( out , AnsibleVaultEncryptedUnicode ) :
if isinstance ( out , AnsibleVaultEncryptedUnicode ) :
@ -151,7 +125,7 @@ def ansible_native_concat(nodes):
else :
else :
if isinstance ( nodes , GeneratorType ) :
if isinstance ( nodes , GeneratorType ) :
nodes = chain ( head , nodes )
nodes = chain ( head , nodes )
out = ' ' . join ( [ to_text ( _fail_on_undefined( v) ) for v in nodes ] )
out = ' ' . join ( [ to_text ( v) for v in nodes ] )
try :
try :
return ast . literal_eval (
return ast . literal_eval (