Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible - Map an array of objects to a different array of objects

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.

like image 696
Bartek Andrzejczak Avatar asked Dec 18 '17 10:12

Bartek Andrzejczak


2 Answers

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!

like image 74
N1ngu Avatar answered Sep 30 '22 14:09

N1ngu


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 }}
like image 20
Bartek Andrzejczak Avatar answered Sep 30 '22 14:09

Bartek Andrzejczak