【问题标题】:Return same data from set_fact as var从 set_fact 返回与 var 相同的数据
【发布时间】:2019-04-23 10:54:29
【问题描述】:

我正在尝试创建字典。使用 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]": " "
}

【问题讨论】:

    标签: ansible jinja2 ansible-facts


    【解决方案1】:

    如果您运行您发布的剧本,它应该会失败并出现以下错误:

    任务[事物]


    致命:[本地主机]:失败! => {"msg": "任务包含一个选项 带有未定义的变量。错误是:“ipaddress_baase”是 未定义\n\n错误似乎出现在 '/home/lars/ tmp/ansible/playbook.yml':第 25 行,第 7 列,但可能\n在其他地方 文件取决于确切的语法问题。\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 }}"
    

    我认为这既更易于实现,也更易于阅读。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      相关资源
      最近更新 更多