Ansible with_dict模板使用

use*_*403 6 ansible ansible-template

我有以下任务:

- name: copy server.xml
  template: src=server.xml dest=/var/containers/{{ item.key }}/conf
  with_dict: containers
Run Code Online (Sandbox Code Playgroud)

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

containers:
  frontend:
    http_port: 8080
  backend:
    http_port: 8081
Run Code Online (Sandbox Code Playgroud)

最后,这是server.xml的相关代码段

<Connector port="{{ http_port }}" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
Run Code Online (Sandbox Code Playgroud)

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

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

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

nik*_*lia 5

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

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

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

要掌握它,请阅读Ansible解释模板所用的语言Jinja2。一个很好的例子是在此处通过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
Run Code Online (Sandbox Code Playgroud)

在那种情况下,假设您有一个需要在需要时将该密钥库复制到文件系统上的任务,则可以使用以下方法:

<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 %}
Run Code Online (Sandbox Code Playgroud)

快乐的模板!