如何在Ansible中动态结束include_tasks循环

huangapple go评论62阅读模式
英文:

How to dynamically end an include_tasks loop in Ansible

问题

由于在Ansible中我们无法在块上运行循环,因此我必须在引用的文件包含多个任务的循环中使用include_tasks

如果我需要在循环中动态提前结束循环(比如说在loop:语句中定义的10次循环中提前结束5次),尝试使用when:条件,但这只能接受预定义/静态定义的变量。如果我需要在每次迭代中更新在when:中进行评估的变量,我必须在此之前在任务中使用register:set_fact:,但当循环任务正在运行时这是不可能的...

此外,在included_tasks中,我可以设置meta: end_play来结束循环和播放执行,但这不是我想要的,播放应该在循环后继续。

英文:

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.

答案1

得分: 2

你无法结束它。你只能跳过剩下的部分。例如,

```yaml
    - command: "echo {{ item }}"
      with_sequence: end=5
      register: out
      when: out.stdout|d(0)|int < 3

在本地运行时会得到:

  changed: [localhost] => (item=1)
  changed: [localhost] => (item=2)
  changed: [localhost] => (item=3)
  skipping: [localhost] => (item=4) 
  skipping: [localhost] => (item=5)

参见:


include_tasks

include_tasks 的情况相当复杂。ignore_conditional 属性说明:

> 该操作不受条件执行的影响,因此将忽略 when: 关键字

你不能在 include_tasks 中使用 when,但可以将关键字(包括 when)应用于包含的任务。例如,创建文件:

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

当你包含这个文件时:

    - include_tasks:
        file: tasks_1.yml
        apply:
          when: out.stdout|d(0)|int < 3
      with_sequence: end=5

你会将条件应用于“包含的任务”。实际上,这将使包含的任务看起来像下面这样:

- 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

运行下面的任务:

- hosts: localhost

  tasks:

    - include_tasks:
        file: tasks_1.yml
        apply:
          when: out.stdout|d(0)|int < 3
      with_sequence: end=5

会得到(已缩减):

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]

你可以看到所有的迭代都会一次性包含,然后依次执行。结果看起来很好,直到 item: '4'。解释总是取决于变量 out.stdout 在任务执行之前的当前值:

  • [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!
    (因为在前一个任务的注册变量 out 中没有 stdout 属性,所以将应用 default(0)

  • [ok] [Display item] item: '5'; default(0)

  • [changed] [Execute command] default(0)

  • [skipping] [Display stdout] out.stdout=5

这是无法使用的。


你可以通过创建一个名为 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 }}"

运行下面的任务:

- hosts: localhost

  tasks:

    - include_tasks:
        file: tasks_2.yml
        apply:
          when: condition|d(true)
      with_sequence: end=5

会得到(已缩减):

TASK [include_tasks] **************************************************************************
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost => (item=1

<details>
<summary>英文:</summary>

You can&#39;t end it. You can only skip the rest. For example,

```yaml
    - command: &quot;echo {{ item }}&quot;
      with_sequence: end=5
      register: out
      when: out.stdout|d(0)|int &lt; 3

gives (on localhost)

  changed: [localhost] =&gt; (item=1)
  changed: [localhost] =&gt; (item=2)
  changed: [localhost] =&gt; (item=3)
  skipping: [localhost] =&gt; (item=4) 
  skipping: [localhost] =&gt; (item=5)

See:

<hr>

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&gt; cat tasks_1.yml
- name: Display item
  debug:
    var: item
- name: Execute command
  command: &quot;echo {{ item }}&quot;
  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 &lt; 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 &lt; 3
- name: Execute command
  command: &quot;echo {{ item }}&quot;
  register: out
  when: out.stdout|d(0)|int &lt; 3
- name: Display stdout
  debug:
    var: out.stdout
  when: out.stdout|d(0)|int &lt; 3

Run the play below

- hosts: localhost

  tasks:

    - include_tasks:
        file: tasks_1.yml
        apply:
          when: out.stdout|d(0)|int &lt; 3
      with_sequence: end=5

gives (abridged)

TASK [include_tasks] **************************************************************************
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost =&gt; (item=1)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost =&gt; (item=2)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost =&gt; (item=3)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost =&gt; (item=4)
included: /export/scratch/tmp7/test-389/tasks_1.yml for localhost =&gt; (item=5)

TASK [Display item] ***************************************************************************
ok: [localhost] =&gt; 
  item: &#39;1&#39;

TASK [Execute command] ************************************************************************
changed: [localhost]

TASK [Display stdout] *************************************************************************
ok: [localhost] =&gt; 
  out.stdout: &#39;1&#39;

TASK [Display item] ***************************************************************************
ok: [localhost] =&gt; 
  item: &#39;2&#39;

TASK [Execute command] ************************************************************************
changed: [localhost]

TASK [Display stdout] *************************************************************************
ok: [localhost] =&gt; 
  out.stdout: &#39;2&#39;

TASK [Display item] ***************************************************************************
ok: [localhost] =&gt; 
  item: &#39;3&#39;

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] =&gt; 
  out.stdout: VARIABLE IS NOT DEFINED!

TASK [Display item] ***************************************************************************
ok: [localhost] =&gt; 
  item: &#39;5&#39;

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: &#39;4&#39;. 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.

<hr>

You can improve the framework by creating a variable condition. For example, put the tasks into a block and always set the condition

shell&gt; cat tasks_2.yml
- block:

    - name: Execute command {{ item }}
      command: &quot;echo {{ item }}&quot;
      register: out
    - debug:
        var: out.stdout

  always:

    - set_fact:
        condition: &quot;{{ out.stdout|int &lt; 3 }}&quot;

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 =&gt; (item=1)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost =&gt; (item=2)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost =&gt; (item=3)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost =&gt; (item=4)
included: /export/scratch/tmp7/test-389/tasks_2.yml for localhost =&gt; (item=5)

TASK [Execute command 1] **********************************************************************
changed: [localhost]

TASK [debug] **********************************************************************************
ok: [localhost] =&gt; 
  out.stdout: &#39;1&#39;

TASK [set_fact] *******************************************************************************
ok: [localhost]

TASK [Execute command 2] **********************************************************************
changed: [localhost]

TASK [debug] **********************************************************************************
ok: [localhost] =&gt; 
  out.stdout: &#39;2&#39;

TASK [set_fact] *******************************************************************************
ok: [localhost]

TASK [Execute command 3] **********************************************************************
changed: [localhost]

TASK [debug] **********************************************************************************
ok: [localhost] =&gt; 
  out.stdout: &#39;3&#39;

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.

huangapple
  • 本文由 发表于 2023年6月22日 03:15:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定