Due to the fact that we cannot run loop on block with Ansible, therefore I have to do include_tasks
in the loop where the referenced file contains more than 1 task.
What if I need to dynamically end the loop earlier (lets say 5 iterations instead of 10 as defined by the loop:
statements). trying to use when:
condition but that only take in pre-defined/statically defined variables, if I have to update the variable that will be evaluated in when:
for each iteration, I have to do register:
or set_fact
in a task before that, which is not possible when the loop task is running...
Also in the included_tasks
I can set meta: end_play
to end the loop and the play execution but that is not what I want, the play should continue after the loop.
You can't end it. You can only skip the rest. For example,
- command: "echo {{ item }}"
with_sequence: end=5
register: out
when: out.stdout|d(0)|int < 3
gives (on localhost)
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)
changed: [localhost] => (item=3)
skipping: [localhost] => (item=4)
skipping: [localhost] => (item=5)
See:
include_tasks
The include_tasks situation is quite complex. The attribute ignore_conditional says:
The action is not subject to conditional execution so it will ignore the when: keyword
You can't use when with include_tasks, but you can apply keywords, including the keyword when, to the tasks within the include. For example, create the file
shell> cat tasks_1.yml
- name: Display item
debug:
var: item
- name: Execute command
command: "echo {{ item }}"
register: out
- name: Display stdout
debug:
var: out.stdout
When you include this file
- include_tasks:
file: tasks_1.yml
apply:
when: out.stdout|d(0)|int < 3
with_sequence: end=5
you apply the condition "to the tasks within the include". Effectively, this will make the included tasks look like below
- name: Display item
debug:
var: item
when: out.stdout|d(0)|int < 3
- name: Execute command
command: "echo {{ item }}"
register: out
when: out.stdout|d(0)|int < 3
- name: Display stdout
debug:
var: out.stdout
when: out.stdout|d(0)|int < 3
Run the play below
- hosts: localhost
tasks:
- include_tasks:
file: tasks_1.yml
apply:
when: out.stdout|d(0)|int < 3
with_sequence: end=5
gives (abridged)
TASK [include_tasks] **************************************************************************
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost => (item=1)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost => (item=2)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost => (item=3)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost => (item=4)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost => (item=5)
TASK [Display item] ***************************************************************************
ok: [localhost] =>
item: '1'
TASK [Execute command] ************************************************************************
changed: [localhost]
TASK [Display stdout] *************************************************************************
ok: [localhost] =>
out.stdout: '1'
TASK [Display item] ***************************************************************************
ok: [localhost] =>
item: '2'
TASK [Execute command] ************************************************************************
changed: [localhost]
TASK [Display stdout] *************************************************************************
ok: [localhost] =>
out.stdout: '2'
TASK [Display item] ***************************************************************************
ok: [localhost] =>
item: '3'
TASK [Execute command] ************************************************************************
changed: [localhost]
TASK [Display stdout] *************************************************************************
skipping: [localhost]
TASK [Display item] ***************************************************************************
skipping: [localhost]
TASK [Execute command] ************************************************************************
skipping: [localhost]
TASK [Display stdout] *************************************************************************
ok: [localhost] =>
out.stdout: VARIABLE IS NOT DEFINED!
TASK [Display item] ***************************************************************************
ok: [localhost] =>
item: '5'
TASK [Execute command] ************************************************************************
changed: [localhost]
TASK [Display stdout] *************************************************************************
skipping: [localhost]
You can see that all iterations are included at once and then executed serially. The results look fine until item: '4'
. The explanation always depends on the current value of the variable out.stdout before the execution of a task:
[ok] [Display item] item: '3'; out.stdout=2
[changed] [Execute command] out.stdout=2
[skipping] [Display stdout] out.stdout=3
[skipping] [Display item] out.stdout=3
[skipping] [Execute command] out.stdout=3
[ok] [Display stdout] out.stdout VARIABLE IS NOT DEFINED! (default(0) will apply because there is no attribute stdout in the registered variable out from the previous task)
[ok] [Display item] item: '5'; default(0)
[changed] [Execute command] default(0)
[skipping] [Display stdout] out.stdout=5
This is unusable.
You can improve the framework by creating a variable condition. For example, put the tasks into a block and always set the condition
shell> cat tasks_2.yml
- block:
- name: Execute command {{ item }}
command: "echo {{ item }}"
register: out
- debug:
var: out.stdout
always:
- set_fact:
condition: "{{ out.stdout|int < 3 }}"
Run the play below
- hosts: localhost
tasks:
- include_tasks:
file: tasks_2.yml
apply:
when: condition|d(true)
with_sequence: end=5
gives (abridged)
TASK [include_tasks] **************************************************************************
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=1)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=2)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=3)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=4)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=5)
TASK [Execute command 1] **********************************************************************
changed: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
out.stdout: '1'
TASK [set_fact] *******************************************************************************
ok: [localhost]
TASK [Execute command 2] **********************************************************************
changed: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
out.stdout: '2'
TASK [set_fact] *******************************************************************************
ok: [localhost]
TASK [Execute command 3] **********************************************************************
changed: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] =>
out.stdout: '3'
TASK [set_fact] *******************************************************************************
ok: [localhost]
TASK [Execute command 4] **********************************************************************
skipping: [localhost]
TASK [debug] **********************************************************************************
skipping: [localhost]
TASK [set_fact] *******************************************************************************
skipping: [localhost]
TASK [Execute command 5] **********************************************************************
skipping: [localhost]
TASK [debug] **********************************************************************************
skipping: [localhost]
TASK [set_fact] *******************************************************************************
skipping: [localhost]
This seems reasonable.