@ -36,9 +36,11 @@ from ansible.cli import CLI
from ansible . errors import AnsibleError , AnsibleParserError , AnsibleUndefinedVariable , AnsibleFileNotFound
from ansible . inventory . host import Host
from ansible . parsing import DataLoader
from ansible . plugins import lookup_loader
from ansible . plugins . cache import FactCache
from ansible . template import Templar
from ansible . utils . debug import debug
from ansible . utils . listify import listify_lookup_plugin_terms
from ansible . utils . vars import combine_vars
from ansible . vars . hostvars import HostVars
from ansible . vars . unsafe_proxy import UnsafeProxy
@ -333,7 +335,38 @@ class VariableManager:
# as we're fetching vars before post_validate has been called on
# the task that has been passed in
templar = Templar ( loader = loader , variables = all_vars )
delegated_host_name = templar . template ( task . delegate_to )
items = [ ]
if task . loop is not None :
if task . loop in lookup_loader :
#TODO: remove convert_bare true and deprecate this in with_
try :
loop_terms = listify_lookup_plugin_terms ( terms = task . loop_args , templar = templar , loader = loader , fail_on_undefined = True , convert_bare = True )
except AnsibleUndefinedVariable as e :
if ' has no attribute ' in str ( e ) :
loop_terms = [ ]
self . _display . deprecated ( " Skipping task due to undefined attribute, in the future this will be a fatal error. " )
else :
raise
items = lookup_loader . get ( task . loop , loader = loader , templar = templar ) . run ( terms = loop_terms , variables = all_vars )
else :
raise AnsibleError ( " Unexpected failure in finding the lookup named ' %s ' in the available lookup plugins " % task . loop )
else :
items = [ None ]
vars_copy = all_vars . copy ( )
delegated_host_vars = dict ( )
for item in items :
# update the variables with the item value for templating, in case we need it
if item is not None :
vars_copy [ ' item ' ] = item
templar . set_available_variables ( vars_copy )
delegated_host_name = templar . template ( task . delegate_to , fail_on_undefined = False )
if delegated_host_name in delegated_host_vars :
# no need to repeat ourselves, as the delegate_to value
# does not appear to be tied to the loop item variable
continue
# a dictionary of variables to use if we have to create a new host below
new_delegated_host_vars = dict (
@ -365,7 +398,15 @@ class VariableManager:
# now we go fetch the vars for the delegated-to host and save them in our
# master dictionary of variables to be used later in the TaskExecutor/PlayContext
all_vars [ ' ansible_delegated_vars ' ] = self . get_vars ( loader = loader , play = play , host = delegated_host , task = task , include_delegate_to = False , include_hostvars = False )
delegated_host_vars [ delegated_host_name ] = self . get_vars (
loader = loader ,
play = play ,
host = delegated_host ,
task = task ,
include_delegate_to = False ,
include_hostvars = False ,
)
all_vars [ ' ansible_delegated_vars ' ] = delegated_host_vars
if self . _inventory is not None :
all_vars [ ' inventory_dir ' ] = self . _inventory . basedir ( )