Ansible run_once+when触发的BUG及其处理方式

关于run_once和when:
when

Conditional expression, determines if an iteration of a task is run or not.

run_once

Boolean that will bypass the host loop, forcing the task to attempt to execute on the first host available and afterwards apply any results and facts to all active hosts in the same batch.

when表示只在符合when条件的host上执行task,run_once表示只在当前host group中第一个可用host上执行task。

有时候我们需要两者混用以便实现:在符合when条件的首个host上执行task的功能。

如果用一个自创的关键字来描述上述功能,那么比较符合的应该是:run_once_when_condition_true.

但当when和run_once同时出现时,实际表现是:无论在第一个host上when条件是否满足,都不会继续在其他host执行了,如果第一个host上when条件为false那么task会被直接skipped。

关于这个BUG在ansible的github issues中有一个帖子:

run_once: true with delegate_to now getting skipped (2.3.0) · Issue #23594 · ansible/ansible (github.com)

issue中作者试图使用delegate_to来解决此问题,但实际上这种方式并不靠谱。

Ansible可能会在未来推出类似于run_once_when_condition_true的功能,但现在并没有(截止2021年2月)。

 

变通的方式:

run_once和when同时出现会导致以下BUG:如果第一个host满足when条件那么BUG不触发,否则task被跳过(就是因为在第一个host上when条件未满足)。

一个可行的办法是将两者分开,那么就需要使用include关键字。

核心逻辑是:

1.先使用when条件过滤出所有满足条件的host。

2.再在include子任务中使用run_once执行任务。

示例:

driver.yml

- include_tasks: tasks_to_include.yml
  when: conditional_matching_multiple_hosts

tasks_to_include.yml

- debug: msg="only run on one of the matching hosts"
  run_once: true
driver.yml负责过滤出符合条件的hosts,子任务通过run_once实现只在单个host执行的功能,变相的实现了run_once_when_condition_true的目的。
 
注意事项:
Ansible2.4以后使用include_tasks替代了之前的include,我在ansible2.9的环境下使用include发现会跳过when条件的筛选直接执行子任务,换为include_tasks才正常。

最后:

本文中描述的方法是在playbook的hosts配置文件不可变的前提前提出的,如果能在hosts文件生成阶段就加一个run_sth=true/false的配置,那么只需要使用简单的when条件判断就可以了。

posted @ 2021-02-23 15:06  realcp1018  阅读(1434)  评论(0编辑  收藏  举报