【问题标题】:Ansible Nested Loop in Template模板中的 Ansible 嵌套循环
【发布时间】:2016-04-27 21:15:00
【问题描述】:

我有一个 YAML 文件,其中包含我想在 Ansible 模板中使用的变量。该文件如下所示:

---
config:
  version: "4.0"
  description: "Global configuration"
  sites:
  - name: "Site J"
    description: "Ficititious Site J"
    servers:
    - hostname: server1
    - hostname: server2
    - hostname: server3
  - name: "Site K"
    description: "Ficititious Site K"
  - name: "Site L"
    description: "Ficititious Site L"

我试图引用服务器,但是,我一生都无法弄清楚 Jinja2 模板中的语法。这是我当前的模板:

{{ config | to_nice_json }}

{% for site in config['sites'] %}
{{ site['name'] }}
{{ site['description'] }}

{% endfor %}

输出是:

{
    "description": "Global configuration", 
    "sites": [
        {
            "description": "Ficititious Site J", 
            "name": "Site J", 
            "servers": [
                {
                    "hostname": "server1"
                }, 
                {
                    "hostname": "server2"
                }, 
                {
                    "hostname": "server3"
                }
            ]
        }, 
        {
            "description": "Ficititious Site K", 
            "name": "Site K"
        }, 
        {
            "description": "Ficititious Site L", 
            "name": "Site L"
        }
    ], 
    "version": "4.0"
} 

Site J
Ficititious Site J

Site K
Ficititious Site K

Site L
Ficititious Site L

我的问题是在现有站点循环中访问“服务器:”下的数据。嵌套循环最明显的语法:

{% for server in site['servers'] %}
{{ server['hostname'] }}
{% endfor %}

不起作用。我收到这个 Ansible 错误:

fatal: [localhost] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict' object has no attribute 'servers'", 'failed': True}

在每个站点下的 YAML 文件中循环访问服务器的正确语法是什么?我尝试了很多变体,但似乎找不到合适的。

【问题讨论】:

    标签: templates ansible jinja2


    【解决方案1】:

    为此工作了几个小时。尝试理解嵌套字典和列表,以及作为列表的字典键,并取得了一些成功。对于没有 Python 经验的人来说,在 Jinja2 中处理复杂的嵌套结构可能会很困难。无论如何,这就是我想出的一个模板,它可以实现我所寻求的目标。该模板包含大量代码来帮助我理解所涉及的结构。这对我来说是一次学习经历。我觉得这可以用更少的代码完成,但这是我能做的最好的。如果有人能找到缩短或以其他方式改进模板的方法,那就太好了。

    {#
      Top-level "config" element contains a dictionary 
    #}
    {%- for config_key,config_value in config.iteritems() -%}
    
    {%- if config_key == "sites" -%}
    
    {%- set sites_list = config_value -%}
    
    {# 
      Under config, "sites" is a list. 
    #}
    {%- for site_dict in sites_list -%}
    
    {# 
      Each element of the sites list is a dictionary 
    #}
    {%- for site_key,site_value in site_dict.iteritems() -%}
    
    {# 
      The dictionary with key="servers" has a list as its value 
    #}
    {%- if site_key == "servers" -%}
    
    {%- set servers_list = site_value -%}
    {%- for server_dict in servers_list -%}
    
    {# 
      Each list value is a dictionary 
    #}
    {%- for server_key,server_value in server_dict.iteritems() -%}
    
    {#
      Looking for values where the key is "hostname"
    #}
    {%- if server_key == "hostname" -%}
    {{ server_value }}
    {% endif %}
    
    {%- endfor -%}
    
    {%- endfor -%}
    
    {%- endif -%}
    
    {%- endfor -%}
    
    {%- endfor -%}
    
    {%- endif -%}
    
    {%- endfor -%}
    

    使用这个输入文件:

    ---
    config:
      version: "4.0"
      description: "Global configuration"
      sites:
      - name: "Site J"
        description: "Ficititious Site J"
        servers:
        - hostname: server1
        - hostname: server2
        - hostname: server3
      - name: "Site K"
        description: "Ficititious Site K"
      - name: "Site L"
        description: "Ficititious Site L"
    

    模板产生这个输出:

    server1
    server2
    server3
    

    【讨论】:

      【解决方案2】:

      servers 键并非在所有站点中都存在,因此您需要在未定义时跳过循环,或者使用空的默认列表,例如:

      {% for server in site['servers'] | default([]) %}
      {{ server['hostname'] }}
      {% endfor %}
      

      【讨论】:

      • 谢谢,马特。在使用它的值做任何事情之前,我最终检查了“服务器”键的模板,这是一个字典列表。我的模板很长,但至少我现在了解了数据结构!
      猜你喜欢
      • 1970-01-01
      • 2012-10-25
      • 2020-09-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 2016-07-12
      • 1970-01-01
      • 2019-04-04
      相关资源
      最近更新 更多