使用 jinja 在 Ansible 中动态创建列表

使用 jinja 在 Ansible 中动态创建列表

我需要动态设置一个新的列表类型变量list var。

以下是基本的剧本示例:

  vars:
    app_instances:
      - host_name: host1-domain
        inst_count: 3
      - host_name: host2-domain
        inst_count: 1
      - host_name: host3-domain
        inst_count: 1

  tasks:
    - set_fact:
        instance_config: >-
          {% set inst_config = [] %}
          {% for inst in app_instances %}
            {% for inst_num in range(inst.inst_count) %}
              {% set node_number = inst.host_name.split('-') | first | replace('host', '') %}
              {% set host_name = "host_name" %}
              {% set host_num = "host_num" %}
              {% set inst_name = "inst_name" %}
              {% set node_conf = { host_name: inst.host_name, host_num: node_number, inst_name: inst_num+1 } %}
              {{ inst_config.append(node_conf) }}
            {% endfor %}
          {% endfor %}
          {{ inst_config|join(",") }}

    - debug:
        msg: "{{ instance_config }}"

这显然将设置instance_config为具有以下内容的字符串:

"instance_config": "                           \n                          \n                          \n                            \n                            \n   {'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 1},{'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 2},{'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 3},{'host_name': 'host2-domain', 'host_num': '2', 'inst_name': 1},{'host_name': 'host3-domain', 'host_num': '3', 'inst_name': 1}"

因此,虽然我得到的列表的结构是正确的,但它是一个字符串,我似乎无法将其变成一个变量,而这个变量将是一个列表。我在这里缺少什么?我最终需要一个变量:

instance_config = [
  {'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 1},
  {'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 2},
  {'host_name': 'host1-domain', 'host_num': '1', 'inst_name': 3},
  {'host_name': 'host2-domain', 'host_num': '2', 'inst_name': 1},
  {'host_name': 'host3-domain', 'host_num': '3', 'inst_name': 1}
]

答案1

我找到了解决方案,因此回答我自己的问题:

  1. do在 ansible.cfg 中启用jinja 扩展:jinja2_extensions = jinja2.ext.do
  2. {{ inst_config.append(node_conf) }}用。。。来代替{% do inst_config.append(node_conf) %}
  3. {%-使用和修剪空格-%}

任务的最终结果set_fact如下:

    - set_fact:
        instance_config: >-
          {%- set instance_config = [] -%}
          {%- for inst in app_instances -%}
            {%- for inst_num in range(inst.inst_count) -%}
              {%- set node_number = inst.host_name.split('-') | first | replace('host', '') | int -%}
              {%- set host_name = "host_name" -%}
              {%- set host_num = "host_num" -%}
              {%- set inst_name = "inst_name" -%}
              {%- set node_conf = { host_name: inst.host_name, host_num: node_number, inst_name: inst_num+1 } -%}
              {%- do instance_config.append(node_conf) -%}
            {%- endfor -%}
          {%- endfor -%}
          {{ instance_config }}

答案2

作为使用内置过滤器解决类似问题的替代方法union

- hosts: localhost
  vars:
    app_instances:
      - host_name: host1-domain
        inst_count: 3
      - host_name: host2-domain
        inst_count: 1
      - host_name: host3-domain
        inst_count: 1

  tasks:
    - set_fact:
        instance_config: >-
          {{ instance_config | default([]) | union(app_instances) }}
    # just to demo that with approach could be used anywhere, without
    # worrying about overriding previously set values
    - set_fact:
        instance_config: >-
          {{ instance_config | default([]) | union(['more', 'items']) }}

    - debug:
        var: instance_config

值得注意的是,任何数组修改都不是为了清晰起见而应用的,但应该易于采用。

我的案例是收集 systemd 单元名称,这些名称是由一些彼此独立的角色动态生成的。

相关内容