diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 91dde77434c..022243be3d8 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -167,14 +167,21 @@ class TaskExecutor: if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ - try: - loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._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 + if self._task.loop == '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. + loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=True) + loop_terms = [t for t in loop_terms if not templar._contains_vars(t)] + else: + try: + loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._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 = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop)