summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--changelogs/fragments/first_found_template_fix.yml2
-rw-r--r--lib/ansible/executor/task_executor.py9
-rw-r--r--lib/ansible/plugins/lookup/first_found.py2
-rw-r--r--test/integration/targets/lookup_first_found/tasks/main.yml45
-rw-r--r--test/integration/targets/lookup_first_found/vars/ishouldnotbefound.yml1
-rw-r--r--test/integration/targets/lookup_first_found/vars/itworks.yml1
6 files changed, 54 insertions, 6 deletions
diff --git a/changelogs/fragments/first_found_template_fix.yml b/changelogs/fragments/first_found_template_fix.yml
new file mode 100644
index 0000000000..70fe6b5862
--- /dev/null
+++ b/changelogs/fragments/first_found_template_fix.yml
@@ -0,0 +1,2 @@
+bugfixes:
+ - first_found lookup now gets 'untemplated' loop entries and handles templating itself as task_executor was removing even 'templatable' entries and breaking functionality. https://github.com/ansible/ansible/issues/70772
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index bc08c6791a..784f80a5a1 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -224,14 +224,11 @@ class TaskExecutor:
items = None
if self._task.loop_with:
if self._task.loop_with in self._shared_loader_obj.lookup_loader:
- fail = True
- 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
+ # TODO: hardcoded so it fails for non first_found lookups, but thhis shoudl be generalized for those that don't do their own templating
+ # lookup prop/attribute?
+ fail = bool(self._task.loop_with != 'first_found')
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, fail_on_undefined=fail, convert_bare=False)
- if not fail:
- loop_terms = [t for t in loop_terms if not templar.is_template(t)]
# get lookup
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar)
diff --git a/lib/ansible/plugins/lookup/first_found.py b/lib/ansible/plugins/lookup/first_found.py
index 24b3b70441..d92e935467 100644
--- a/lib/ansible/plugins/lookup/first_found.py
+++ b/lib/ansible/plugins/lookup/first_found.py
@@ -226,6 +226,8 @@ class LookupModule(LookupBase):
try:
fn = self._templar.template(fn)
except (AnsibleUndefinedVariable, UndefinedError):
+ # NOTE: backwards compat ff behaviour is to ignore errors when vars are undefined.
+ # moved here from task_executor.
continue
# get subdir if set by task executor, default to files otherwise
diff --git a/test/integration/targets/lookup_first_found/tasks/main.yml b/test/integration/targets/lookup_first_found/tasks/main.yml
index d0ca91eaf5..7aa9742708 100644
--- a/test/integration/targets/lookup_first_found/tasks/main.yml
+++ b/test/integration/targets/lookup_first_found/tasks/main.yml
@@ -102,3 +102,48 @@
- assert:
that: "no_terms|first == '/etc/hosts'"
+
+- name: handle templatable dictionary entries
+ block:
+
+ - name: Load variables specific for OS family
+ assert:
+ that:
+ - "{{item|quote}} is file"
+ - "{{item|basename == 'itworks.yml'}}"
+ with_first_found:
+ - files:
+ - "{{ansible_id}}-{{ansible_lsb.major_release}}.yml" # invalid var, should be skipped
+ - "{{ansible_lsb.id}}-{{ansible_lsb.major_release}}.yml" # does not exist, but should try
+ - "{{ansible_distribution}}-{{ansible_distribution_major_version}}.yml" # does not exist, but should try
+ - itworks.yml
+ - ishouldnotbefound.yml # this exist, but should not be found
+ paths:
+ - "{{role_path}}/vars"
+
+ - name: Load variables specific for OS family, but now as list of dicts, same options as above
+ assert:
+ that:
+ - "{{item|quote}} is file"
+ - "{{item|basename == 'itworks.yml'}}"
+ with_first_found:
+ - files:
+ - "{{ansible_id}}-{{ansible_lsb.major_release}}.yml"
+ paths:
+ - "{{role_path}}/vars"
+ - files:
+ - "{{ansible_lsb.id}}-{{ansible_lsb.major_release}}.yml"
+ paths:
+ - "{{role_path}}/vars"
+ - files:
+ - "{{ansible_distribution}}-{{ansible_distribution_major_version}}.yml"
+ paths:
+ - "{{role_path}}/vars"
+ - files:
+ - itworks.yml
+ paths:
+ - "{{role_path}}/vars"
+ - files:
+ - ishouldnotbefound.yml
+ paths:
+ - "{{role_path}}/vars"
diff --git a/test/integration/targets/lookup_first_found/vars/ishouldnotbefound.yml b/test/integration/targets/lookup_first_found/vars/ishouldnotbefound.yml
new file mode 100644
index 0000000000..e4cc6d5dbc
--- /dev/null
+++ b/test/integration/targets/lookup_first_found/vars/ishouldnotbefound.yml
@@ -0,0 +1 @@
+really: i hide
diff --git a/test/integration/targets/lookup_first_found/vars/itworks.yml b/test/integration/targets/lookup_first_found/vars/itworks.yml
new file mode 100644
index 0000000000..8f8a21a46d
--- /dev/null
+++ b/test/integration/targets/lookup_first_found/vars/itworks.yml
@@ -0,0 +1 @@
+doesit: yes it does