在同一映射中交叉引用 Ansible 变量

在同一映射中交叉引用 Ansible 变量

我如何定义一个 Ansible 变量value 是同一映射结构中的另一个变量

为了允许变量的合理命名空间,我定义了如下映射结构,其中某些值依赖于同一结构中的其他变量:

acme:
  directory:
    hostname: "acme-staging-v02.api.letsencrypt.org"
letsencrypt:
  config_dir: "/etc/letsencrypt"
  keys_dir: "{{ letsencrypt.config_dir }}/keys"
  csrs_dir: "{{ letsencrypt.config_dir }}/csr"
  certs_dir: "{{ letsencrypt.config_dir }}/certs"
  accounts_dir: "{{ letsencrypt.config_dir }}/accounts"
  csr_file: "{{ letsencrypt.csrs_dir }}/{{ site_domain }}.csr"
  account_key_file: "{{ letsencrypt.csrs_dir }}/{{ acme.directory.hostname }}"
  email_address: "certificate-reminders@{{ site_domain }}"

这会失败,因为 Ansible 无法解析引用同一数据结构中的其他值:

在模板字符串中检测到递归循环:{{ letsencrypt.config_dir }}/keys

所以我认为查找vars将允许推迟该决议:

acme:
  directory:
    hostname: "acme-staging-v02.api.letsencrypt.org"
letsencrypt:
  config_dir: "/etc/letsencrypt"
  keys_dir: "{{ lookup('vars', 'letsencrypt.config_dir') }}/keys"
  csrs_dir: "{{ lookup('vars', 'letsencrypt.config_dir') }}/csr"
  certs_dir: "{{ lookup('vars', 'letsencrypt.config_dir') }}/certs"
  accounts_dir: "{{ lookup('vars', 'letsencrypt.config_dir') }}/accounts"
  csr_file: "{{ lookup('vars', 'letsencrypt.csrs_dir') }}/{{ site_domain }}.csr"
  account_key_file: >-
    {{ lookup('vars', 'letsencrypt.csrs_dir') }}/{{ acme.directory.hostname }}
  email_address: "certificate-reminders@{{ site_domain }}"

这会失败,因为 Ansible 正在尝试立即解决该查找:

未找到具有此名称的变量:letsencrypt.config_dir


当然我可以将它们拆分成单独的变量。不过,这违背了我把紧密相关的变量都放在同一个命名空间中的目的。

那么如何定义数据结构以便一些值可能依赖于同一结构中的其他变量

答案1

(感谢@michael-hampton 提供此答案。)

正如所述Ansible 问题 #8603,配置解析器正在读取变量值立即尝试渲染遇到的模板定义变量时。当模板引用尚未完全定义的变量时,这会导致解析失败。

A来自“rquelibari”的评论给出了很好的分析:

这个特征实际上在含义上是明确定义的。这种“反向引用”的语法和语义(在逻辑上)都定义得很好。[…]

并详细解释了这一现象是如何发生的。

随后来自“cmpunches”的评论直接说明所需的解决方案:

此问题直接源于 ansibles 使用 yaml 解析器的插值功能,而不是加载 yaml 对象并进行第二次插值。这不仅仅是 jinja 错误,这是 ansible 中的实现错误。请检查。加载为原始字符串,然后在第二次传递中处理已初始化的对象成员应该可以解决这个问题。

因此,除非 Ansible 中的 YAML 解析器被修正为将变量值读取为纯文本,而不尝试立即呈现模板(并推迟呈现直到所有变量都被定义),否则在 Ansible 变量中还不能完成值的交叉引用。

相关内容