首页 > 解决方案 > 为什么 Ansible 将列表转换为字符串?

问题描述

Ansible 在合并列表时意外将列表转换为字符串,有人可以帮我解释一下原因吗?

剧本:

---
- hosts: localhost
  vars:
    list1:
      - aaa: 'aaa'
  tasks:
    - set_fact:
        a: 'asdfg'
    - set_fact:
        list2: "{{ list1|d([]) + [ hostvars['localhost']['a']] }}"
    - debug: var=list2
    - set_fact:
        list3: "{{ list1|d([]) + [ hostvars['localhost']['undefined variable']] }}"
    - debug: var=list3

这是播放结果(省略了不必要的部分):

TASK [debug] *************************************************************************************************************************************************************************************************************************************************
Wednesday 05 September 2018  09:52:31 +0200 (0:00:00.071)       0:00:00.203 ***
ok: [localhost] => {
    "list2": [
        {
            "aaa": "aaa"
        },
        "asdfg"
    ]
}

...

TASK [debug] *************************************************************************************************************************************************************************************************************************************************
Wednesday 05 September 2018  09:52:31 +0200 (0:00:00.085)       0:00:00.345 ***
ok: [localhost] => {
    "list3": "[{'aaa': 'aaa'}, Undefined]"
}

PLAY RECAP ***************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0

第二个调试任务输出字符串而不是预期的字典。这是我不理解的正确行为还是应该提交错误?

标签: ansiblejinja2

解决方案


这个答案描述了 Ansible 2.6.x 之前的状态。Ansible v2.7 中有一个支持原生 Python 对象的运动。


为什么 Ansible 将列表转换为字符串?

在您的示例中, Ansible没有将任何列表转换为字符串。


Ansible 获取数据:

  1. 来自 YAML 解析器

    它们可以是:列表、字典、标量(字符串、布尔值或数值)。

  2. 来自其他来源(例如:Jinja2、库存、CLI extravars)

    任何来自其他来源的数据都是一个字符串


由于 Jinja2 总是返回一个字符串,您可以在头脑中计算结果并将值作为 YAML 引用的标量传递(由 Ansible 解释为字符串):

  • 上面的第一个任务相当于:

    - set_fact:
        list2: "[{'aaa': 'aaa'}, 'asdfg']"
    

    Ansible 获取一个字符串(不是列表)并尝试解释它。它查找与列表匹配的 JSON 字符串并创建一个列表对象。

  • 第二个任务相当于:

    - set_fact:
        list3: "[{'aaa': 'aaa'}, Undefined]"
    

    您在此处观察到的是 Jinja2 将列表替换为具有未定义值的元素和字符串Undefined(而不是引用该字符串)。

    Ansible 获取一个字符串并尝试解释它。它没有找到合适的数据结构*并创建一个字符串对象。


*有一种特殊情况,如果一个名为的变量Undefined存在,那么 Ansible 将Undefined用该变量值替换未引用的变量并创建一个列表对象。


推荐阅读