6

我有以下任务:

- name: copy server.xml
  template: src=server.xml dest=/var/containers/{{ item.key }}/conf
  with_dict: containers

而且我还在我的 group_vars 中添加了容器字典

containers:
  frontend:
    http_port: 8080
  backend:
    http_port: 8081

最后这里是来自 server.xml 的相关片段

<Connector port="{{ http_port }}" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

我想要发生的是相关的 http_port 在模板模块中使用。但相反,我得到了错误:

致命:[localhost] => {'msg':“AnsibleUndefinedVariable:一个或多个未定义变量:'http_port'未定义”,'失败':True}

这可能吗?如何利用项目的值进行变量替换?

4

1 回答 1

6

使用{{ item.value.http_port }}正是正确的解决方案。

当您通过 with_dict 时,它会循环通过将容器字典中的每个项目传递为的任务{{ item }},其中项目有一个键以及字典项目包含的任何值 - 在您的情况下,键/值对的键是 http_port 和values 是这两个不同的整数 - 但是您可以传递非常复杂的嵌套字典,使用{{ item.value.http_port }}您想出的语法访问内容变得更加重要。

当您使用更复杂的模板时要警惕的是,当您有一些额外的变量要为一个主机(或容器或其他)模板而不是另一个主机时,如何混合并设置默认值并使用 if 语句。

要掌握它,请阅读 Jinja2,Ansible 解释模板的语言。一个很好的例子是在前端通过 SSL 提供文件,而不是后端。使用类似语法{{ foo | default('bar') }}以避免 Ansible 对您尝试使用未定义的变量和 if 语句感到愤怒,以确保您只是在模板化您需要的东西。

一个粗略的草图 - 假设你有:

containers:
  frontend:
    http_port: 8080
    https_port: 8443
    ssl_cert: ./files/keystore
    ssl_pass: "{{ vaulted_vars.ssl_pass }}" 
  backend:
    http_port: 8081

在这种情况下,假设您有一项任务在需要时将该密钥库复制到文件系统上,您可以使用以下内容:

<Connector port="{{ item.value.http_port }}" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="{{ item.value.https_port | default('8443')" />
           {% if item.value.ssl_cert is defined %} 
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="${user.home}/.keystore" keystorePass="{{ item.value.ssl_pass }}"
           clientAuth="false" sslProtocol="TLS"/>
           {% endif %}

快乐的模板!

于 2015-09-01T18:55:01.707 回答