Score:4

Ansible: Convert comma separated string with key:value pairs to dictionary

fr flag

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!

Score:5
br flag

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'}
Josef Glatz avatar
fr flag
Thank you for you answer and the great examples/explanations!!! This works great for the actual need. May I ask you kindle if you can also extend your answer with an example where the dictionary has named keys like the following example? ```yaml {{ name: "main_de", language: "german" }, { name: "main_en", language: "english" }} ```
br flag
It's not [YAML](https://www.yamllint.com/). If you want to pars anything, you must agree on a syntax first.
Josef Glatz avatar
fr flag
OK lets rephase: is it possible to create a dict where the string before ":" is not the key but a value of a defined key?
br flag
What is preventing you from posting a [mre](https://stackoverflow.com/help/minimal-reproducible-example)? (Not in the comment, of course. Edit your question or open a new one).
br flag
See [How do comments work?](https://meta.stackexchange.com/questions/19756/how-do-comments-work). In particular the part: `What are comments for, and when shouldn't I comment?` Comments are for 1) clarification 2) constructive criticism 3) minor or transient information.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.