Ansible如何实现两变量二选一插值且单变量必填校验
Ansible 双变量兜底取值+非空校验的单步实现
需求逻辑:优先取变量var1的值,var1未定义时取var2的值;两个变量必须至少有一个已定义,若均未定义则直接抛出明确的自定义异常,不允许返回空值。
常见踩坑写法
很多人第一反应会写出如下逻辑:
- set_fact: result: >- var1 | default(var2 | mandatory)
这个写法无法正常运行:即使var1已经正常定义,只要var2未定义,Ansible就会抛出mandatory校验异常。原因是Ansible使用的Jinja2模板引擎不会对过滤器参数做短路求值,渲染时会提前计算所有传入过滤器的参数,不会因为var1已存在就跳过默认值分支里的var2校验逻辑。
另一种常见的临时方案是拆为校验、赋值两个步骤:
- assert: that: - var1 is defined or var2 is defined - set_fact: result: >- var1 | default(var2)
这个方案存在两个明显缺陷:
- 额外增加了独立的assert校验步骤,流程冗余;
- set_fact赋值步骤本身没有内置存在性校验,即使前置步骤已经做了校验,代码视觉上仍存在
result被赋值为null的违和感。
优雅单步实现
利用Jinja2内联条件表达式的短路求值特性,可以把校验、赋值逻辑合并在同一个set_fact步骤中,完全实现类似Perl中$var1 // $var2 // die()的逻辑,写法如下:
- set_fact: result: >- var1 if var1 is defined else ( var2 if var2 is defined else mandatory('Neither var1 nor var2 is defined, accept our condolences') )
逻辑说明
- 表达式遵循严格的短路执行规则:只要
var1已定义,就直接返回var1,不会执行后续任何分支的判断和校验; - 仅当
var1未定义时,才会检查var2的定义状态,var2已定义则直接返回var2; - 只有两个变量全部未定义时,才会触发mandatory过滤器,抛出预先写好的自定义异常信息。
如果需要兼容「变量已定义但值为空/None/False/0」的场景,只需要调整内联if的判断条件即可,比如要求变量不仅要定义,还不能为None:
- set_fact: result: >- var1 if (var1 is defined and var1 is not none) else ( var2 if (var2 is defined and var2 is not none) else mandatory('Neither var1 nor var2 is defined or both are null, accept our condolences') )
内容的提问来源于stack exchange,提问作者Volodymyr Melnyk
相关产品推荐
相关产品推荐

