如何让 Ansible 解释变量内的变量?

β.ε*_*.βε 3 jinja2 ansible

每当我尝试让 Ansible 解释嵌套变量 \xe2\x80\x94 时,另一个变量 \xe2\x80\x94 中的变量我无法得到我期望的结果。

\n

给定变量:

\n
key: bar\nfoo:\n  bar: baz\nfoo_bar: baz\n
Run Code Online (Sandbox Code Playgroud)\n

bar我已经尝试过这三种方法,但没有太多运气来动态访问字典的键foo或 key foo_bar,当从值构造时key

\n
    \n
  • \n
    - ansible.builtin.debug:\n    msg: "{{ foo[{{ key }}] }}"\n
    Run Code Online (Sandbox Code Playgroud)\n

    但是,我收到错误:

    \n
    \n

    \'模板化字符串时出现模板错误:预期标记\'\':\'\',得到\'\'}\'\'。字符串:{{ foo[{{ key }}] }}\'

    \n
    \n
  • \n
  • \n
    - ansible.builtin.debug:\n      msg: "{{ foo_{{ key }} }}"\n
    Run Code Online (Sandbox Code Playgroud)\n

    但是,我遇到了类似的错误

    \n
    \n

    \'模板化字符串时出现模板错误:预期标记\'\'打印语句结束\'\',得到\'\'{\'\'。字符串:{{ foo_{{ key }} }}\'

    \n
    \n
  • \n
  • \n
    - ansible.builtin.debug:\n    msg: "{{ foo[\'{{ key }}\'] }}"\n
    Run Code Online (Sandbox Code Playgroud)\n

    在这里,我得到了错误

    \n
    \n

    该任务包含一个带有未定义变量的选项。错误是:\'dict object\'没有属性\'{{ key }}\'

    \n
    \n
  • \n
\n

我期望得到foo.baror的值foo_bar,所以baz
\n实现这一目标的正确方法是什么?

\n

β.ε*_*.βε 6

正如Ansible常见问题中所建议的,小胡子不能堆叠

\n
\n

另一个规则是\xe2\x80\x98moustache don\xe2\x80\x99t stack\xe2\x80\x99。我们经常看到这样的情况:

\n
{{ somevar_{{other_var}} }}\n
Run Code Online (Sandbox Code Playgroud)\n

上面的内容并不像您期望的那样工作,如果您需要使用动态变量,请酌情使用以下内容:

\n
{{ hostvars[inventory_hostname][\'somevar_\' ~ other_var] }}\n
Run Code Online (Sandbox Code Playgroud)\n

对于 \xe2\x80\x98non 主机 vars\xe2\x80\x99 您可以使用vars 查找插件:

\n
{{ lookup(\'vars\', \'somevar_\' ~ other_var) }}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

来源:https ://docs.ansible.com/ansible/latest/reference_appendices/faq.html#when-should-i-use-also-how-to-interpolate-variables-or-dynamic-variable-names

\n
\n

因此,有两种情况适用:

\n
    \n
  1. 当尝试从变量访问字典的键时,您只需按原样使用该变量,请记住,当您位于表达式分隔符内时{{ ... }}内时,如果未将字符串括在简单引号或双引号内,则字符串将被解释为变量。

    \n
    {{ somevar_{{other_var}} }}\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 当尝试从变量构造变量的名称或字典的键时,您必须使用串联运算符,~

    \n
    {{ hostvars[inventory_hostname][\'somevar_\' ~ other_var] }}\n
    Run Code Online (Sandbox Code Playgroud)\n

    您可能还需要使用vars查找来访问动态变量:

    \n
    {{ lookup(\'vars\', \'somevar_\' ~ other_var) }}\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
\n
\n

旁注:

\n
    \n
  • 请使用vars查找 \xe2\x80\x94 lookup(\'vars\', \'somevar_\' ~ other_var)\xe2\x80\x94 而不是字典vars\xe2\x80\x94 vars[\'somevar_\' ~ other_var],因为它从未打算成为 Ansible 功能,并将在未来版本中删除

    \n
    \n

    简短的历史,vars是以前使用它来将变量传递给模板的代码的遗留物,它从未打算供外部使用,并且大多数时候没有模板化任何内容。

    \n

    不相关的更改允许它“有时”模板化,但这从来不是故意的,它没有被删除的唯一原因是因为有些人依赖它,这是通过查看代码和/或其他人已经发现的使用它。尽管我们长期以来一直打算弃用和删除该vars构造,但由于缺乏触发运行时消息的好方法,我们无法这样做。

    \n

    我们通过查找varnames和创建了两个替代方案vars,这可能不如字典那么灵活,但也不会因为不需要的访问而占用内存,因为大多数用户只想匹配现有变量的一小部分。

    \n
    \n

    来源:https ://github.com/ansible/ansible/issues/74904#issuecomment-854137949

    \n
  • \n
  • 出于 Jinja 文档中提出的原因,建议使用正确的串联运算符,而不是Ansible 文档中建议的~数学运算符:+

    \n
    \n

    通常对象是数字,但如果两者都是字符串或列表,则可以通过这种方式连接它们。然而,这不是连接字符串的首选方式!对于字符串连接,请查看~运算符。

    \n
    \n

    来源: https: //jinja.palletsprojects.com/en/2.11.x/templates/#math

    \n
  • \n
\n