Search code examples
ansiblejinja2

How to format a dict to a string in ansible


I want to format a dict in ansible like so,

from

{'a': 1, 'b': 2, 'c': 3}

to

'a=1,b=2,c=3'

and have to set it as an environment variable in a block like so,

vars:
  test_env:
    a: 1
    b: 2
    c: 3

- block:
    # tasks
  environment:
    SOME_ENV: 'a=1,b=2,c=3'

here I want to convert test_env dict to 'a=1,b=2,c=3' I can not set the fact to modify the dict and then set it to the SOME_ENV because environment is a different clause, maybe I can modify the dict in the vars clause but is there any other solution?


Solution

  • Decompose the dictionary to the lists of keys and values. Then zip the lists and join the items. For example,

        - block:
            - command: echo $SOME_ENV
              register: result
            - debug:
                var: result.stdout
          environment:
            SOME_ENV: "{{ test_env.keys()|
                          zip(test_env.values())|
                          map('join', '=')|
                          join(',') }}"
    

    give

      result.stdout: a=1,b=2,c=3
    

    update

    There are more options. You can also use Jinja or JMESPath. The below expressions give the same result

      SOME_ENV: |-
        {%- for k,v in test_env.items() %}
        {{ k }}={{ v }}{% if not loop.last %},{% endif %}
        {%- endfor %}
    
      SOME_ENV: "{{ test_env|dict2items|
                    json_query('[].join(`=`, [key, to_string(value)])')|
                    join(',') }}"
    

    Example of a complete playbook for testing

    - hosts: all
    
      vars:
    
        test_env:
          a: 1
          b: 2
          c: 3
    
      tasks:
    
        - block:
    
            - command: "echo ${{ item }}"
              register: result
              loop: [SOME_ENV, SOME_EN2, SOME_EN3]
    
            - debug:
                msg: "{{ result.results|
                         items2dict(key_name='item', value_name='stdout') }}"
    
          environment:
    
            SOME_ENV: "{{ test_env.keys()|
                          zip(test_env.values())|
                          map('join', '=')|
                          join(',') }}"
    
            SOME_EN2: |-
              {%- for k,v in test_env.items() %}
              {{ k }}={{ v }}{% if not loop.last %},{% endif %}
              {%- endfor %}
    
            SOME_EN3: "{{ test_env|dict2items|
                          json_query('[].join(`=`, [key, to_string(value)])')|
                          join(',') }}"
    

    gives (abridged)

      msg:
        SOME_EN2: a=1,b=2,c=3
        SOME_EN3: a=1,b=2,c=3
        SOME_ENV: a=1,b=2,c=3