如何在 jinja2 中为 ansible 添加列表

问题描述 投票:0回答:7

下面是我编写的在 ansible 中使用的 jinja2 模板。

{% set port = 1234 %}
{% set server_ip = [] %}
{% for ip in host_ip  %}
{% do server_ip.append({{ ip }}:{{ port }}) %}
{% endfor %}
{% server_ip|join(', ') %}

以下是我想要的输出:

devices = 192.168.56.14:1234,192.168.56.13:1234,192.168.56.10:1234

但是当我运行ansible playbook时,它抛出如下错误:

"AnsibleError: teme templating string: Encountered unknown tag 'do'. Jinja was looking for th: 'endfor' or 'else'

任何帮助将不胜感激..

templates ansible jinja2 ansible-template
7个回答
73
投票

尝试下面的代码:

{% set port = '1234' %}
{% set server_ip = [] %}
{% for ip in host_ip  %}
{{ server_ip.append( ip+":"+port ) }}
{% endfor %}
{{ server_ip|join(',') }}

你会得到:

192.168.56.14:1234,192.168.56.13:1234,192.168.56.10:1234


15
投票

我不喜欢任何答案,它们感觉太老套了(不得不担心输出

None
,或使用其他技术的虚假空格),但我认为我已经找到了一个效果很好的解决方案。我从这个相关问题的答案中获得灵感,并意识到您可以对同一变量多次调用
set
,并且似乎不会产生任何惩罚。

它仍然是一个 tad hacky,因为我不认为它是这样工作的(话又说回来,Jinja 中的几个设计决策让我摸不着头脑,所以谁知道呢)。

{% set server_ip = server_ip.append({{ ip }}:{{ port }}) %}

有趣的是,虽然该值确实附加到

server_ip
,但该附加的返回值(我们现在非常清楚是
None
)并未分配回 LHS 上的
server_ip
。这让我发现该声明的 LHS 一侧似乎是一个禁止操作。

所以你也可以这样做并且附加有效:

{% set tmp = server_ip.append({{ ip }}:{{ port }}) %}

但是,如果您打印

tmp
,则不会显示任何内容。去算算吧。


10
投票

这对我有用:

- set_fact:
    devices: >-
      {% for ip in host_ip %}{{ ip }}:1234{% if not loop.last %},{% endif %}{% endfor %}

如果您仍想使用

do
,请添加

jinja2_extensions = jinja2.ext.do

到你的 ansible 配置文件并更改

{% do server_ip.append({{ ip }}:{{ port }}) %}` to `{% do server_ip.append({ip:port}) %}`

3
投票

得票最多的答案会导致渲染结果中出现大量空格。除了使用 jinja 的

do
扩展之外,替代解决方案是使用 jinja 的 whitespace control。在块内添加减号
-

{%- for ip in host_ip -%}...{%- endfor %}

将删除空格。


2
投票

为了避免使用

None
打印出
{{ server_ip.append( ip+":"+port ) }}
(刚刚花了 20 分钟调试这个),如果你不想使用误导性的
{% set _ = server_ip.append( ip+":"+port ) %}
,你可以回到 Python 基础知识并执行以下操作:


# Remember that [1, 2] + [3] = [1, 2, 3]

{% set server_ip = server_ip + [ip+":"+port] %}

在 99.9% 的情况下,这可以完成工作。然而,在特殊情况下,当您使用very大型列表时,在内存使用方面可能会出现小的性能下降:在上面的示例中,

[1, 2] + [3] = [1, 2, 3]
[1, 2]
[1, 2, 3]
(初始列表和修改后的列表)将在内存中短暂共存,这与
append
方法相反,该方法不会在内存中创建额外的对象。


1
投票

使用

map()
regex
的单行解决方案:

{{ ["1.1.1.1","2.2.2.2"]|map('regex_replace', '(.+)', "\\1:1234")|join(', ') }}

map('regex_replace', '(.+)', "\\1:1234")
:1234
添加到传递的数组
(.+)
中的任何非空字符串
["1.1.1.1","2.2.2.2"]
。结果:

1.1.1.1:1234, 2.2.2.2:1234

0
投票

使用命名空间的另一种解决方案:

{% set port = "1234" %}
{% set data = namespace(server_ip=[]) %}
{% for ip in host_ip  %}
  {% set data.server_ip = data.server_ip + [ip + ":" + port] %}
{% endfor %}

{% set data.server_ip = data.server_ip|join(",") %}

{{ data.server_ip }}
© www.soinside.com 2019 - 2024. All rights reserved.