Ansible run_once+when触发的BUG及其处理方式
Conditional expression, determines if an iteration of a task is run or not.
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中有一个帖子:
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
最后:
本文中描述的方法是在playbook的hosts配置文件不可变的前提前提出的,如果能在hosts文件生成阶段就加一个run_sth=true/false的配置,那么只需要使用简单的when条件判断就可以了。