Ansible: Convert Comma Separated String to Dictionary

ansiblejinja2

I'm launching a setup playbook for a docker-compose service (apache solr) via extra vars. Those vars are set while executing since this playbook should be flexible and multiple configurations exists on one server.

My idea is, that the user can setup the variable in the ansible ui (ansible semaphore) as string:

  • Variable name project_cores
  • Variable value (string) main_en:english,main_de:german

I would like to iterate those cores as a dictionary. What I want at the end is:

{
  {
    name: main_en,
    language: english
  },
  {
    name: main_de,
    language: german
  },
}

The first step is to split them by , (this is already working):


- name: "debug: split cores"
  debug:
    msg: "{{ item }}"
  loop: "{{ project_cores.split(',') }}"

I tried then the following without success as this does not add the keys of the sub elements:


- name: "Extract solr cores configuration."
  set_fact:
    dict: "{{ dict|default({}) | combine ( { item.split(':')[0] : item.split(':')[1] } ) }}"
  with_items:
    - "{{ project_cores.split(',') }}"

I tested some combinations but does not find a working solution on how to add the keys.

Any idea how to convert that string to a real directory stated in the first example? thanks in advance!

Best Answer

The below declaration

  project_cores_dict: "{{ dict(project_cores|
                               split(',')|
                               map('split',':')) }}"

gives what you want

  project_cores_dict:
    main_de: german
    main_en: english

  • Example of a complete playbook for testing
- hosts: localhost

  vars:

    project_cores: 'main_en:english,main_de:german'
    project_cores_dict: "{{ dict(project_cores|
                                 split(',')|
                                 map('split',':')) }}"

  tasks:

    - debug:
        var: project_cores_dict
  • Make the conversion more robust and trim the items
  project_cores_dict: "{{ dict(project_cores|
                               split(',')|map('trim')|
                               map('split',':')|map('map', 'trim')) }}"

Test it

    - debug:
        msg: |
          {{ pcd|to_yaml }}
      loop:
        - 'main_en:english,main_de:german'
        - 'main_en:english, main_de:german'
        - 'main_en: english, main_de:german'
      vars:
        pcd: "{{ dict(item|
                      split(',')|map('trim')|
                      map('split',':')|map('map', 'trim')) }}"

gives (abridged)

  msg: |-
    {main_de: german, main_en: english}
  msg: |-
    {main_de: german, main_en: english}
  msg: |-
    {main_de: german, main_en: english}

Without the trimming

    - debug:
        msg: |
          {{ pcd|to_yaml }}
      loop:
        - 'main_en:english,main_de:german'
        - 'main_en:english, main_de:german'
        - 'main_en: english,main_de:german'
      vars:
        pcd: "{{ dict(item|
                      split(',')|
                      map('split',':')) }}"

the spaces will become part of the keys and values

  msg: |-
    {main_de: german, main_en: english}
  msg: |-
    {' main_de': german, main_en: english}
  msg: |-
    {main_de: german, main_en: ' english'}