Reputation: 1332
Is there a way to map an array of objects in Ansible Playbook to a different array of objects? Let's say we have a source array being:
arr:
- value: a
- value: b
- value: c
And what we want is to get a different array based on objects in the first array, let's say:
arr2:
- const: 1
var: a
- const: 1
var: b
- const: 1
var: c
This would be doable by an element template of:
const: 1
var: {{ value }}
Is there a way to apply such a template to every element in an array? I haven't found an appropriate map
filter, as lookup('template', ...)
cannot be used inside map
.
Upvotes: 8
Views: 7841
Reputation: 3805
Based on your answer (I must say it opened my eyes and I can't find words that tell the infinite gratitude I feel) I worked out what I think is a slightly more elegant solution.
I try to avoid the set_facts
module because the result will have a rather high precedence. I prefer to stick to role defaults and host and group inventory variables.
Also, I am more used to jinja2 templating than Ansible filters.
- hosts: localhost
gather_facts: no
vars:
arr:
- value: a
- value: b
- value: c
arr2: "{{ lookup('template', 'template.yaml.j2') | from_yaml }}"
tasks:
- debug:
var: "arr2"
And the very template.yaml.j2 file will contain the iteration:
{% for item in arr %}
- const: 1
var: {{ item.value }}
{% endfor %}
This opens the door for really crazy variable manipulation while keeping the playbook pretty simple.
Hope it helps somebody as much as it helped me!
Upvotes: 8
Reputation: 1332
As Konstantin Suvorov mentioned in the comment it can be done using recursive array building. This is how I did it:
#role test
---
- hosts: localhost
gather_facts: no
vars:
arr:
- value: a
- value: b
- value: c
tasks:
- set_fact:
arr2: "{{ (arr2 | default([])) + [ lookup('template', 'template.yaml.j2') | from_yaml ] }}"
with_items: "{{ arr }}"
- debug:
msg: "{{ arr2 }}"
#template.yaml.j2
const: 1
var: {{ item.value }}
Upvotes: 2