我正在尝试创建一本字典。使用var时,事情按预期工作。然而,Set_fact就像被忽略了一样,我无法隔离。
阅读Jinja2手册,多次迭代
---
- hosts: localbox gather_facts: false
vars:
app_servers: 5
ipaddress_base: "192.168.0"
rmi_portbase: 10000
host_info: |
{% set res = [] -%}
{%- for number in range(1,app_servers + 1) -%}
{% set ignored = res.extend([{
'hostname': 'app' + number|string,
'ipaddress': ipaddress_base + '.' + number|string,
'rmi_port': rmi_portbase|int + ( number * 10)
}]) -%}
{%- endfor %}
{{ res }}
tasks:
- name: thing
set_fact:
thing2: "{% set res = [] -%}
{%- for number in range(1,app_servers + 1) -%}
{% set ignored = res.extend([{
'hostname': 'app' + number|string,
'ipaddress': ipaddress_baase + '.' + number|string,
'rmi_port': rmi_portbase|int + ( number * 10)
}]) -%}
{%- endfor %}
{{ res }}"
- debug: var=host_info[0].hostname
- debug: var=thing2[0]
我期待像thing2的host_info这样的结果。
TASK [debug] *******************************************************************
ok: [localhost] => {
"host_info[0].hostname": "app1"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"thing2[0]": " "
}
如果您运行已发布的playbook,它将失败并显示以下错误:
任务[事物]
致命:[localhost]:失败! => {“msg”:“任务包含一个带有未定义变量的选项。错误是:'ipaddress_baase'未定义\ n \ n错误似乎出现在'/ home / lars / tmp / ansible / playbook.yml中':第25行,第7列,但可能在文件的其他位置,具体取决于确切的语法问题。\ n \ n违规行似乎是:\ n \ n \ n - 名称:thing \ n ^ her e \ n “}
事实上,你拼错了ipaddress_base
作为ipaddress_baase
(注意额外的a
)。如果您修复了这个拼写错误并添加修改最终的debug
任务,如下所示:
- debug: var=thing2
您应该看到以下输出:
TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
"thing2": " [{'rmi_port': 10010, 'hostname': u'app1', 'ipaddress': u'192.168.0.1'}, {'rmi_port': 10020, 'hostname': u'app2', 'ipaddress': u'192.168.0.2'}, {'rmi_port': 10030, 'hostname': u'app3', 'ipaddress': u'192.168.0.3'}, {'rmi_port': 10040, 'hostname': u'app4', 'ipaddress': u'192.168.0.4'}, {'rmi_port': 10050, 'hostname': u'app5', 'ipaddress': u'192.168.0.5'}]"
}
这告诉我们的是thing2
是一个字符串,而不是字典。所以,当你为thing2[0]
任务时,你将获得该字符串位置0
的角色。
它是字符串而不是字典的原因是因为索引0处的前导空格。我们可以通过将endfor
语句中的终端标记从%}
更改为-%}
来修复它,这会占用以下任何空格:
- set_fact:
thing2: "{% set res = [] -%}
{%- for number in range(1,app_servers + 1) -%}
{% set ignored = res.extend([{
'hostname': 'app' + number|string,
'ipaddress': ipaddress_baase + '.' + number|string,
'rmi_port': rmi_portbase|int + ( number * 10)
}]) -%}
{%- endfor -%}
{{ res }}"
有了这个和你原来的debug
任务,我们看到输出:
TASK [set_fact] *******************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
"host_info[0].hostname": "app1"
}
TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
"thing2[0]": {
"hostname": "app1",
"ipaddress": "192.168.0.1",
"rmi_port": 10010
}
}
话虽如此,我会停止尝试使用这种技术来生成复杂的数据结构,因为它 - 正如我们所见 - 容易出错。我会这样写:
- set_fact:
thing2: "{{ thing2|default([]) + [{
'hostname': 'app' ~ item,
'ipaddress': ipaddress_base ~ '.' ~ item,
'rmi_port': rmi_portbase ~ (item * 10)}]
}}"
loop: "{{ range(1, app_servers+1)|list }}"
我认为这既易于实现又更易于阅读。