ansible - 为什么 Ansible 会评估这个变量,即使是在一个 false if block 内?

标签 ansible jinja2

当 Ansible 遇到 if block ,以及 if条件涉及groups变量,它似乎在评估 if 之前扩展了 block 的内容健康)状况。这会导致 if 的 undefined variable 错误。条件否则会防止。

为什么会出现错误?是预期的行为,还是错误?

我已将行为减少到最小的测试用例。

库存.yml

group1:

group2:
  hosts:
    localhost:
  vars:
    foo: "{{ groups.group1[0] }}"

预期的

一个空字符串,因为在这两种情况下 if条件为假
$ ansible -i inventory.yml group2 -mdebug -amsg="{% if false %}{{ foo }}{% endif %}"
localhost | SUCCESS => {
    "msg": ""
}
$ ansible -i inventory.yml group2 -mdebug -amsg="{% if groups.group1 %}{{ foo }}{% endif %}"
localhost | SUCCESS => {
    "msg": ""
}

实际的

if条件涉及groups变量,foo被评估,导致 undefined variable 消息
$ ansible -i inventory.yml group2 -mdebug -amsg="{% if false %}{{ foo }}{% endif %}"
localhost | SUCCESS => {
    "msg": ""
}
$ ansible -i inventory.yml group2 -mdebug -amsg="{% if groups.group1 %}{{ foo }}{% endif %}"
localhost | FAILED! => {
    "msg": "The task includes an option with an undefined variable. The error was: list object has no element 0"
}

我正在使用 Ansible 2.7.9。

最佳答案

Ansible 根据 Jinja 的请求从它传递给 Jinja 的神奇上下文字典中按需扩展模板化键,但是 Jinja 在任何处理开始之前提前绑定(bind)模板引用的任何名称。

Jinja 期望上下文产生一个具体值或等价于 KeyError (“未定义”IIRC),Ansible OTOH 使用这个时刻递归调用 Jinja 以构建传递给原始模板调用的值。正是在此递归调用中,您的错误正在发生。

查看类似模板的原始 Jinja 源代码可能会有所帮助(使用 jinja2.Environment().compile(..., raw=True) 准备:

from __future__ import division
from jinja2.runtime import LoopContext, TemplateReference, Macro, Markup, TemplateRuntimeError, missing, concat, escape, markup_join, unicode_join, to_string, identity, TemplateNotFound, Namespace
name = None

def root(context, missing=missing, environment=environment):
    resolve = context.resolve_or_missing
    undefined = environment.undefined
    if 0: yield None
    l_0_foo = resolve('foo')
    l_0_groups = resolve('groups')
    pass
    if environment.getattr((undefined(name='groups') if l_0_groups is missing else l_0_groups), 'group1'):
        pass
        yield to_string((undefined(name='foo') if l_0_foo is missing else l_0_foo))

blocks = {}
debug_info = '1=12'

注意对 resolve() 的调用在任何条件评估发生之前完成。它在 resolve() 内Ansible 尝试递归地扩展您的 foo多变的。

应该可以进行调整,以便 foo仅在 Jinja 尝试将其转换为字符串(或类似字符串)时才会扩展,因此我建议提交上游错误。

关于ansible - 为什么 Ansible 会评估这个变量,即使是在一个 false if block 内?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55651731/

相关文章:

amazon-web-services - 向 Application Load Balancer (ALB) 注册 EC2 实例的问题

python - 在 Ansible 中使用 JINJA2 从 JSON 中提取带条件的嵌套字典值

python - Flask-WTF 表单填充整数字段和单选字段

python - 如何在 html 表中编辑从数据库中获取的数据? flask ,Jinja2

ansible - 如何访问 Ansible 中包含连字符的变量名

ansible - 如何使用 root 用户运行 Ansible,然后更改为另一个用户?

python - Ansible 字典/哈希键作为特殊变量

python - 如何为 jinja 模板启用 {% trans %} 标签?

python - Jinja2中的多个同名 block

ansible - 从 Ansible 中的两个字典列表中选择值