2

I need to dynamically set a new list type variable list var.

Here's a basic playbook example:

  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 }}"

This obviously sets the instance_config to a string with the following contents:

"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}"

So while the structure of the list that I'm getting is correct, it's a String and I can't seem to make this into a variable that would be a list instead. What Am I missing here? What I need eventually is a variable:

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}
]
SergioLeone
  • 141
  • 1
  • 4

2 Answers2

1

Answering my own question as I have found a solution:

  1. enable do jinja extension in ansible.cfg: jinja2_extensions = jinja2.ext.do
  2. replace {{ inst_config.append(node_conf) }} with {% do inst_config.append(node_conf) %}
  3. trim whitespaces using {%- and -%}.

The final result of the set_fact task looks like this:

    - 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 }}
SergioLeone
  • 141
  • 1
  • 4
0

As an alternative approach to a similar problem using builtin union filter:

- 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

Worth noting that any array modifications are not applied for clarity but should be easy to adopt.

My case was about gathering systemd unit names, which were generated dynamically by a few, independent from each other, roles.

kucaahbe
  • 101
  • 2