Dynamically generating complex data in Ansible

Viewed 30

I'm facing the following problem set in writing an Ansible playbook:

A list is given to me:

rooms:
  - room_name: bedroom-1
    chairs: 1
  - room_name: bedroom-2
    chairs: 0
  - room_name: bathroom
    chairs: 0
  - room_name: kitchen
    chairs: 4

And I need to transform that into a list of dictionaries with these two keys per item:

  1. chair_name: <room_name>-chair-<chair_number>
  2. room_name: <room_name>

With the example above that would give me:

chair_names:
  - chair_name: bedroom-1-chair-1
    room_name: bedroom-1
  - chair_name: kitchen-chair-1
    room_name: kitchen
  - chair_name: kitchen-chair-2
    room_name: kitchen
  - chair_name: kitchen-chair-3
    room_name: kitchen
  - chair_name: kitchen-chair-4
    room_name: kitchen

I've been struggling to accomplish this using Ansible. Is there a way to do it?

1 Answers

Use Jinja to create the structure

    chair_names_str: |-
      {% for room in rooms %}
      {% for i in range(1, room.chairs + 1) %}
      - chair_name: {{ room.room_name }}-chair-{{ i }}
        room_name: {{ room.room_name }}
      {% endfor %}
      {% endfor %}
    chair_names: "{{ chair_names_str|from_yaml }}"

gives

  chair_names:
    - {chair_name: bedroom-1-chair-1, room_name: bedroom-1}
    - {chair_name: kitchen-chair-1, room_name: kitchen}
    - {chair_name: kitchen-chair-2, room_name: kitchen}
    - {chair_name: kitchen-chair-3, room_name: kitchen}
    - {chair_name: kitchen-chair-4, room_name: kitchen}

Q: "Is it possible to achieve the same results using Ansible loops?"

A: Yes. It is. In the first loop create lists of the chairs

    - set_fact:
        chairs: "{{ chairs|d([]) +  [{'chairs': range(1, item|int + 1)|list}] }}"
      loop: "{{ rooms|map(attribute='chairs')|list }}"

gives

  chairs:
    - chairs: [1]
    - chairs: []
    - chairs: []
    - chairs: [1, 2, 3, 4]

In the second loop create the list. The task below gives the same result

    - set_fact:
        chair_names: "{{ chair_names|d([]) + [_item] }}"
      with_subelements:
        - "{{ rooms|zip(chairs)|map('combine') }}"
        - chairs
      vars:
        _item:
          chair_name: "{{ item.0.room_name }}-chair-{{ item.1 }}"
          room_name: "{{ item.0.room_name }}"

You can see that the first option is much simpler.

Related