在角色的默认变量中进行Ansible递归循环

时间:2017-02-25 16:52:28

标签: variables ansible

如何在 Ansible (2.1.x)中的其他变量中重用变量而不会导致递归循环?

设置

考虑这个roles/<role>/defaults/main.yml文件:

---
liquibase:
  version: "3.5.3"
  download_file: "liquibase-{{liquibase.version}}-bin.tar.gz"

  # I also tried this alternative with a similar result:
  # download_file: "liquibase-{{liquibase[version]}}-bin.tar.gz
...

和此roles/<role>/tasks/main.yml文件:

---
- name: Liquibase | Download
  debug:
    msg: "download_file: {{liquibase.download_file}}"
...

错误

我希望变量liquibase.download_file的值为liquibase-3.5.3-bin.tar.gz但是当我使用此角色运行一个剧本时,我收到以下错误:

...
TASK [liquibase : Liquibase | Download] *******************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "...: recursive loop detected in template string: liquibase-{{liquibase.version}}-bin.tar.gz"}
...

我的用例

显然我想下载Liquibase,我想让角色的用户决定使用哪个版本。我还希望能够完全覆盖下载位置(文件,URL等),例如,使用公司的FTP服务器或类似服务器。

2 个答案:

答案 0 :(得分:4)

不支持在同一父dict中引用其他dict键。请参阅此issue

您只能重构变量,以便在不同的变量树中生成versiondownload_file,例如:

liquibase_version: "3.5.3"
liquibase_download_file: "liquibase-{{liquibase_version}}-bin.tar.gz"

P.S。如果这是您的角色的默认设置,将liquibase_version分隔为独立变量会更加明显。这样,用户只需重新定义liquibase_versionliquibase_download_file即可获得更改;如果是dict(如你的问题),你不能只覆盖一个密钥,用户必须使用versiondownload_file密钥设置完整的字典。

答案 1 :(得分:0)

当尝试将YAML结构的优雅与Jinja2的灵活性相结合时,我感到沮丧。由于不被支持,解决该问题的一种方法(我承认这有点不合时宜)是引入一个伪私有部分来帮助打破周期。首先,我们声明任何可能导致依赖的内容:

# Pseudo private KV pairs, used to work around recursion issues.
_liquibase_version: "3.5.3"

我们只需要声明将在字典中声明的任何内容,并形成另一个字典键的依赖项。接下来,我们可以根据需要声明字典,但在必要时使用“专用”键值对:

liquibase:
  version: "{{_liquibase_version}}"
  download_file: "liquibase-{{_liquibase_version}}-bin.tar.gz"

当然,_liquibase_version不是真正的 ,而是充当助手,因此我们只需要定义一次值,但仍然可以引用{{ 1}}和{{liquibase.version}}