假设我们需要从两个变量之一中插入一个值。如果未定义第一个,请使用第二个的值。
- set_fact:
result: >-
var1 | default(var2)
虽然我们也不能接受结果为空,所以我们需要确保至少定义了var1
或var2
中的一个(尽管不是两个)。在这种情况下,我们愿意做这样的事情:
- set_fact:
result: >-
var1 | default(var2 | mandatory)
它看起来不错,但它不起作用。唉,如果var2
没有定义,即使var1
很好,Ansible 也会引发异常。是否定义var1
并不重要,Ansible 只是检查是否定义了var2
,而不考虑如果它实际上不打算分配默认值,则不需要此检查。
坦率地说,从我的角度来看,如果定义了var1
,则永远不应该进行此var2 | mandatory
,但 Ansible 不是一种编程语言,因此我知道它以另一种方式工作。
我唯一的想法是确保事先定义了其中一个变量,因此它如下所示:
- assert:
that:
- (var1 | mandatory) or (var2 | mandatory)
- set_fact:
result: >-
var1 | default(var2)
虽然我不喜欢这样,但由于两个原因,他们在这里。
- 我必须添加一个完整的附加步骤(
assert
)。 - 我不喜欢
var2
没有在set_fact
步骤中检查。当然,Ansible 在上一步中检查了它们,但看起来result
仍然可能会获得null
值,这是不希望的。即使它只是看起来那样,它仍然让我有点恼火。
我想要的是找到一些替代mandatory
过滤器的替代方案,但我需要只有在未定义时才考虑这个"准mandatory
"var1
。
有没有办法用一些简短而整洁的成语而不是这两个步骤来解决它?类似于 Perl 中的$var1 // $var2 // any_way_to_raise_an_exception('Neither $var1 nor #var2 is defined, accept our condolences');
。:-)
对于我尝试过的情况,它适用于一组外部参数,我还发现mandatory
接受未记录的消息,当它死亡时
- debug:
msg: the value is {{ ((var1|default(var2))|mandatory("need var1 or var2") }}
并优先于var1
,如果提供,则使用var2
,如果两者都不是,则与fatal: [localhost]: FAILED! => {"msg": "need var1 or var2"}
一起死亡
问题是你不必要的mandatory
介绍。没有这个,Ansible 的行为是正确的,除非你(非常不明智地)禁用了error_on_undefined_vars
- hosts: localhost
vars:
foo: eh
bar: bee
tasks:
# foo is set, so we get its value
- debug:
msg: "{{ foo | default(bar) }}"
# baz is not set, so we get bar
- debug:
msg: "{{ baz | default(bar) }}"
# foo is set, so we get its value
- debug:
msg: "{{ foo | default(quux) }}"
# neither baz nor quux is set, so we get an error
- debug:
msg: "{{ baz | default(quux) }}"
输出:
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "eh"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "bee"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "eh"
}
TASK [debug] *******************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'quux' is undefinednnThe error appears to be in '/home/ec2-user/test.yml': line 20, column 7, but maynbe elsewhere in the file depending on the exact syntax problem.nnThe offending line appears to be:nn # neither baz nor quux is set, so we get an errorn - debug:n ^ heren"}
如果禁用了error_on_undefined_vars
,则应使用mandatory
作为最终筛选器,而不是将其放在非必需值上:
- debug:
msg: "{{ baz | default(quux) | mandatory }}"
或者,如果你要求设置一个和正好一个值,则无法使用assert
(因为你正在施加非标准要求),但你应该使用defined
测试,而不是mandatory
筛选器。
- hosts: localhost
vars:
foo: eh
bar: bee
tasks:
- assert:
that: "[foo, baz] | select('defined') | length == 1"
- assert:
that: "[foo, bar] | select('defined') | length == 1"
ignore_errors: true
- assert:
that: "[baz, quux] | select('defined') | length == 1"
TASK [assert] ******************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
TASK [assert] ******************************************************************
fatal: [localhost]: FAILED! => {
"assertion": "[foo, bar] | select('defined') | length == 1",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}
...ignoring
TASK [assert] ******************************************************************
fatal: [localhost]: FAILED! => {
"assertion": "[baz, quux] | select('defined') | length == 1",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}
旁注:如果未定义var1和var2,则可以声明默认值。例如
result: "{{ var1|default(var2)|default('default') }}"
但是,问题的用例是:如果未定义var1和var2,则失败。
问:"不能接受结果为空,因此我们需要确保至少定义了 var1 或 var2 中的一个。
答:断言没有按照您期望的方式工作。如果未定义var1,它将失败。例如
- debug:
var: var1
- debug:
var: var2
- assert:
that: var1|mandatory or var2|mandatory
TASK [debug] *********************************************************************************
ok: [localhost] =>
var1: VARIABLE IS NOT DEFINED!
TASK [debug] *********************************************************************************
ok: [localhost] =>
var2: test
TASK [assert] ********************************************************************************
fatal: [localhost]: FAILED! =>
msg: 'The conditional check ''(var1|mandatory) or (var2|mandatory)'' failed. The error was: Mandatory variable ''var1'' not defined.'
相反,下面的任务可以执行您想要的操作
- assert:
that: (var1|default('')|length > 0) or
(var2|default('')|length > 0)
问:">简短整洁的成语而不是两步?像exception('Neither $var1 nor #var2 is defined')
。
答:实际上,默认过滤器会这样做。下面的例外说:'var2' is undefined
.(我们知道,只有当var1未定义时,才需要var2。为什么要重复它?
- debug:
var: var1
- debug:
var: var2
- set_fact:
result: "{{ var1|default(var2) }}"
TASK [debug] *********************************************************************************
ok: [localhost] =>
var1: VARIABLE IS NOT DEFINED!
TASK [debug] *********************************************************************************
ok: [localhost] =>
var2: VARIABLE IS NOT DEFINED!
TASK [set_fact] ******************************************************************************
fatal: [localhost]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: 'var2' is undefined