Ansible - Map an array of objects to a different array of objects
Asked Answered
P

2

8

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.

Parahydrogen answered 18/12, 2017 at 10:1 Comment(1)
Please check #42152692Cracow
P
2

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 }}
Parahydrogen answered 18/12, 2017 at 18:3 Comment(0)
L
8

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!

Level answered 28/6, 2019 at 20:5 Comment(0)
P
2

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 }}
Parahydrogen answered 18/12, 2017 at 18:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.