在Ansible yaml文件中评估多行布尔变量时结果错误

时间:2019-01-28 09:33:19

标签: ansible yaml

使用ansible 2.7.5,我正在尝试创建多行布尔参数。

我首先通过以下方法验证了它可以按预期运行:

FOOD: apple
IS_FRUIT: '{% if FOOD == "carrot" %}false{% elif FOOD == "apple" or FOOD == "banana" %}true{% endif %}'

然后是任务:

- name: "FOOD is: {{ FOOD }}" 
  debug: msg="FOOD is {{ FOOD }} where IS_FRUIT {{ IS_FRUIT | bool }}"

打印:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT [ True ]"
}

运行时如预期。

基于:

In YAML, how do I break a string over multiple lines?

然后我尝试了:

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

但会打印:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT [ False ]"
}

这是错误的。我发现这篇文章描述了类似的问题: https://github.com/ansible/ansible/issues/18142

但它并没有真正提供解决方案。关于如何在Ansible中创建多行布尔变量的任何建议?

基于以下答案,我也尝试过:

FOOD: apple

IS_FRUIT: |
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

但是当我用上面的相同任务运行它时,我仍然得到:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT False"
}

这是错误的。

3 个答案:

答案 0 :(得分:4)

令人生厌的解释

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

请注意,在YAML中,折叠的块标量(以>开头)将单个换行符替换为空格(将多个换行符替换为一个换行符)。所以上面的代码等同于

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false {% elif FOOD == "apple" or FOOD == "banana" %}true {% endif %}

因此,在Jinja处理之后,您将得到falsetrue 带有尾随空格。由于存在尾随空格,YAML不会将这些标量映射为布尔值。

现在,我,Ansible看到它获得了一个非布尔值,并且以某种方式将该非布尔值映射为一个布尔值。因此,即使标量为False且尾随空格,标量的计算结果也仍然为true(markdown不能让我正确地呈现它)。


有关如何修复的重要部分

您可以改用文字块标量(根据 clockworknet 的建议):

IS_FRUIT: |-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

之所以起作用,是因为现在换行符不会转换为空格,而是保留换行符。在Jinja处理之后,仅剩下一行,并且最后的换行符将被-中的|-剥离。

但是,如果您有更复杂的表达式要在其中将内容实际拆分为多行,这将无济于事。有一个更好的解决方案是Jinja whitespace control

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {%- elif FOOD == "apple" or FOOD == "banana" %}true
 {%- endif %}

Jinja标签上的-告诉Jinja在此标签之前删除 all 所有空格,因此,这基本上等同于

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false{% elif FOOD == "apple" or FOOD == "banana" %}true{% endif %}

您也可以像这样-%}一样使用它来删除标签 之后的所有空格。但是,请注意:Jinja处理发生在YAML处理之前,因此它可能会破坏您精心编写的YAML缩进!例如,不要在块标量中的第一个Jinja标签上使用{%-,因为Jinja会将文本与|-放在同一行,这是无效的YAML!最后一个标签和-%}也是如此。

答案 1 :(得分:1)

尼斯解释发生了什么由@flyx回事。

我建议避免使用金贾的语句的,从而有利于神社你的剧本的表达式的。
在文件模板中还可以执行静态语句。

您可以如下编写vars定义:

IS_FRUIT: >-
  {{ false if FOOD == 'carrot'
     else
     (
       true if FOOD in ['apple', 'banana']
       else 'unknown'
     )
  }}

在此情况下,我们只关心被剥去与最后换行符>-

答案 2 :(得分:-1)

这对我有用:

IS_FRUIT: |
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

(更改为|符号以使用文字多行行为)