Creating list in loop in Ansible
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.