Creating list in loop in Ansible

George Shuklin
OpsOps
Published in
1 min readApr 5, 2022

Today I found a new way to create list for set_fact within loop.

Old approach

- set_fact:
foo: '{{ (foo|d([])).combine([{"id": hostvars[item]["ID"]}]) }}'
loop: '{{ groups.mygroup }}'

The main downside is that this is ansible loop, which is relatively slow and verbose.

New approach

- set_fact:
foo: |-
[
{% for host in groups.mygroup %}
{"id": "{{ hostvars[host]['ID'] }}"},
{% endfor %}
]

It generates ‘almost json’, which is accepted by ansible parser as valid yaml.

It’s almost json because there is comma at the end:

["ID": "foo", "ID": "bar",]

Turned out, trailing coma is permitted in yaml, so Ansible realizes that foo is not a string, but a list with dicts inside.

There are few advantages:

It’s multiline for writer.

I can redo it like that:

- set_fact:
foo: |-
[
{% for host in groups.mygroup %}
{
"id": "{{ hostvars[host]['ID'] }}",
"something": "else",
"even_a_list_is_ok": [
{% for gr in groups %}
{{ gr }},
{% endfor %}
},
{% endfor %}
]

Just imagine this madness in combine form.

It’s faster and more concise in reporting.

Jinja loops do not produce ‘task’ output, whilst ‘loop’ in Ansible does.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.