Adam Donahue
Adam Donahue

Reputation: 1658

Convert list of dicts to list of strings in Ansible

Here's something I think should be straight-forward in Ansible, but I'm having trouble finding a canonical best practice.

In Ansible, I have a list of dicts in YAML:

config:
  - id: x
    value: X
  - id: y
    value: Y

I want to generate a list of strings that can be passed as a whole to the mysql_query module.

I've tried various elegant ways of doing this using Ansible filters, but that best I've come up with is to generate a list of newline-separate strings in a single template that iterates over config and then trim | split('\n') the resulting single string.

Template:

{% for item in config %}
{{ item.id }} => {{ item.value }}
{% endfor %}

Playbook task:

set_fact:
  converted_items: "{{ lookup('template', './template.j2') | trim | split('\n') }}"

But this feels like a kludge.

What am I missing here?

[Note this is a canned example, to keep things simple.]

Upvotes: 1

Views: 5550

Answers (2)

Frenchy
Frenchy

Reputation: 17017

if you want to transform list of dicts to list of strings, just use loop and union:

- name: vartest
  hosts: localhost
  vars:
    config:
    - id: x
      value: X
    - id: y
      value: Y
  tasks:
    - name: transform value
      set_fact:
        result: "{{ result | default([]) | union([item.id ~ ' => ' ~ item.value]) }}"
      loop: "{{ config  }}"

    - name: display result
      debug:
        var: result

equivalent of union: result | default([]) + [item.id ~ ' => ' ~ item.value]


result:

ok: [localhost] => {
    "result": [
        "x => X",
        "y => Y"
    ]
}

Upvotes: 1

Vladimir Botka
Vladimir Botka

Reputation: 68074

You don't have to use a file. Put the Jinja template into the local vars, e.g.

    - set_fact:
        converted_items: "{{ _converted_items|trim|split('\n') }}"
      vars:
        _converted_items: |
          {% for item in config %}
          {{ item.id }} => {{ item.value }}
          {% endfor %}

gives

  converted_items:
  - x => X
  - y => Y

There are many options of how to transform the data, e.g. the task below gives the same result

    - set_fact:
        converted_items: "{{ _keys|zip(_vals)|map('join', ' => ')|list }}"
      vars:
        _keys: "{{ config|map(attribute='id')|list }}"
        _vals: "{{ config|map(attribute='value')|list }}"

Upvotes: 1

Related Questions