Entirely skipping a `first_found` loop based on a conditional

Let’s say I have the task:

- name: Template the foo file with the first template found
  loop: "{{ query('first_found', templates) }}"
  vars:
    templates:
      - "templates/fqdn/{{ inventory_hostname }}/foo.j2"
      - "templates/debian/{{ ansible_distribution_release }}/foo.j2"
  ansible.builtin.template:
    src: "{{ item }}"
    dest: /etc/foo

All fine, but now let’s say I only want to run that task at all on Debian 12 or newer.

This doesn’t work:

- name: Template the foo file with the first template found
  when: ansible_distribution_version is version('12', '>=')
  loop: "{{ query('first_found', templates) }}"
  vars:
    templates:
      - "templates/fqdn/{{ inventory_hostname }}/foo.j2"
      - "templates/debian/{{ ansible_distribution_release }}/foo.j2"
  ansible.builtin.template:
    src: "{{ item }}"
    dest: /etc/foo

because the when: applies to every iteration of the loop:. So if for example on hosts that are not Debian 12+ the loop: never gets started because none of those files exist on those hosts (the entire point of trying to skip this task here), and that’s a playbook error.

I also cannot do the trick of supplying a default value to query('first_found', templates) because that also will be a non-existent file causing the play to error out.

So what is the correct way to entirely skip this task in the case that ansible_distribution_version is version('12', '>=') does not return true?

Thanks!

You can make a list in loop: to be empty for Debian <= 12, e.g:

loop: "{{ query('first_found', templates) if ansible_distribution_version is version('12', '>=') else [] }}"

The other way is to put your task inside a separate .yml file and include it with include_tasks and when: ansible_distribution_version is version('12', '>=') condition on include_tasks.

1 Like

Just have first_found return empty instead of error:
query('first_found', templates, skip=True)

1 Like

@bcoca nice one :slightly_smiling_face:… and definitely the most elegant.

I have to make a notice though. It allows for an unexpected failure to go unnoticed. Since template file paths are dependent on inventory_hostname and ansible_distribution_release, in case there is something missing for some particular combination of these variables, the task will not fail which is maybe undesirable. Being explicit about the condition ansible_distribution_version is version('12', '>=') is more robust.