move from with_<lookup>: to loop:

- old functionality is still available direct lookup use, the following are equivalent

  with_nested: [[1,2,3], ['a','b','c']]

  loop: "{{lookup('nested', [1,2,3], ['a','b','c'])}}"

- avoid squashing with 'loop:'
- fixed test to use new intenal attributes
- removed most of 'lookup docs' as these now reside in the plugins
This commit is contained in:
Brian Coca
2017-09-16 23:32:34 -04:00
committed by Brian Coca
parent bd17edd5ed
commit d84df2405d
24 changed files with 157 additions and 1211 deletions

View File

@@ -189,20 +189,20 @@ class TaskExecutor:
templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
items = None
if self._task.loop:
if self._task.loop in self._shared_loader_obj.lookup_loader:
if self._task.loop_with:
if self._task.loop_with in self._shared_loader_obj.lookup_loader:
fail = True
if self._task.loop == 'first_found':
if self._task.loop_with == 'first_found':
# first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing.
fail = False
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=fail,
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, loader=self._loader, fail_on_undefined=fail,
convert_bare=False)
if not fail:
loop_terms = [t for t in loop_terms if not templar._contains_vars(t)]
# get lookup
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar)
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar)
# give lookup task 'context' for subdir (mostly needed for first_found)
for subdir in ['template', 'var', 'file']: # TODO: move this to constants?
@@ -213,7 +213,12 @@ class TaskExecutor:
# run lookup
items = mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True)
else:
raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop)
raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop_with)
elif self._task.loop:
items = templar.template(self._task.loop)
if not isinstance(items, list):
raise AnsibleError("Invalid data passed to 'loop' it requires a list, got this instead: %s" % items)
# now we restore any old job variables that may have been modified,
# and delete them if they were in the play context vars but not in
@@ -264,7 +269,10 @@ class TaskExecutor:
u" to something else to avoid variable collisions and unexpected behavior." % loop_var)
ran_once = False
items = self._squash_items(items, loop_var, task_vars)
if self._task.loop_with:
# Only squash with 'with_:' not with the 'loop:', 'magic' squashing can be removed once with_ loops are
items = self._squash_items(items, loop_var, task_vars)
for item in items:
task_vars[loop_var] = item

View File

@@ -75,8 +75,7 @@ class Task(Base, Conditional, Taggable, Become):
_delegate_to = FieldAttribute(isa='string')
_delegate_facts = FieldAttribute(isa='bool', default=False)
_failed_when = FieldAttribute(isa='list', default=[])
_loop = FieldAttribute(isa='string', private=True, inherit=False)
_loop_args = FieldAttribute(isa='list', private=True, inherit=False)
_loop = FieldAttribute()
_loop_control = FieldAttribute(isa='class', class_type=LoopControl, inherit=False)
_name = FieldAttribute(isa='string', default='')
_notify = FieldAttribute(isa='list')
@@ -85,6 +84,9 @@ class Task(Base, Conditional, Taggable, Become):
_retries = FieldAttribute(isa='int', default=3)
_until = FieldAttribute(isa='list', default=[])
# deprecated, used to be loop and loop_args but loop has been repurposed
_loop_with = FieldAttribute(isa='string', private=True, inherit=False)
def __init__(self, block=None, role=None, task_include=None):
''' constructors a task, without the Task.load classmethod, it will be pretty blank '''
@@ -145,16 +147,17 @@ class Task(Base, Conditional, Taggable, Become):
else:
return "TASK: %s" % self.get_name()
def _preprocess_loop(self, ds, new_ds, k, v):
def _preprocess_with_loop(self, ds, new_ds, k, v):
''' take a lookup plugin name and store it correctly '''
loop_name = k.replace("with_", "")
if new_ds.get('loop') is not None:
if new_ds.get('loop') is not None or new_ds.get('loop_with') is not None:
raise AnsibleError("duplicate loop in task: %s" % loop_name, obj=ds)
if v is None:
raise AnsibleError("you must specify a value when using %s" % k, obj=ds)
new_ds['loop'] = loop_name
new_ds['loop_args'] = v
new_ds['loop_with'] = loop_name
new_ds['loop'] = v
display.deprecated("with_ type loops are being phased out, use the 'loop' keyword instead", version="2.9")
def preprocess_data(self, ds):
'''
@@ -210,7 +213,7 @@ class Task(Base, Conditional, Taggable, Become):
continue
elif k.replace("with_", "") in lookup_loader:
# transform into loop property
self._preprocess_loop(ds, new_ds, k, v)
self._preprocess_with_loop(ds, new_ds, k, v)
else:
# pre-2.0 syntax allowed variables for include statements at the top level of the task,
# so we move those into the 'vars' dictionary here, and show a deprecation message
@@ -248,9 +251,9 @@ class Task(Base, Conditional, Taggable, Become):
super(Task, self).post_validate(templar)
def _post_validate_loop_args(self, attr, value, templar):
def _post_validate_loop(self, attr, value, templar):
'''
Override post validation for the loop args field, which is templated
Override post validation for the loop field, which is templated
specially in the TaskExecutor class when evaluating loops.
'''
return value

View File

@@ -522,7 +522,7 @@ class VariableManager:
if task.loop is not None:
if task.loop in lookup_loader:
try:
loop_terms = listify_lookup_plugin_terms(terms=task.loop_args, templar=templar,
loop_terms = listify_lookup_plugin_terms(terms=task.loop, templar=templar,
loader=self._loader, fail_on_undefined=True, convert_bare=False)
items = lookup_loader.get(task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy)
except AnsibleUndefinedVariable: