yktoo
yktoo

Reputation: 2986

Ansible: convert dictionary into a name=value string

Given a dictionary like:

- set_fact:
      VARS: {foo: bar, baz: biz}

How can I turn this into a string of name=value pairs, line-break-separated, preferably using filters, something like "{{ VARS | format(???) | join('\n') }}"?

The desired result is the following string with line breaks:

foo=bar
baz=biz

I know I can use map() to transform keys or values, but not both of them at once.

Upvotes: 1

Views: 6531

Answers (2)

Nick Guenther
Nick Guenther

Reputation: 161

items converts a dictionary into a list of [key, value] lists and the nested lists can be flattened by maping join over them.

This is the expression you need:

"{{ VARS | items | map('join', '=') | join('\n') }}"

Full Demonstration

[ ~]$ cd /tmp/
[ tmp]$ 
[ tmp]$ cat vars.yml 
- hosts: all
  gather_facts: false
  tasks:
    - set_fact:
        VARS: {foo: bar, baz: biz}

    - set_fact:
        AS_SHELL: "{{ VARS | items | map('join', '=') | join('\n') }}"

    - copy:
        dest: /tmp/vars.txt
        content: "{{AS_SHELL}}\n"
[ tmp]$ ansible-playbook -i localhost, -e ansible_connection=local vars.yml 
PLAY [all] *************************************************************************************************************************************************

TASK [set_fact] ********************************************************************************************************************************************
ok: [localhost]

TASK [set_fact] ********************************************************************************************************************************************
ok: [localhost]

TASK [copy] ************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *************************************************************************************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[ tmp]$ cat vars.txt
foo=bar
baz=biz
[ tmp]$ ansible-playbook --version
ansible-playbook [core 2.14.0]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.10/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible-playbook
  python version = 3.10.8 (main, Nov  1 2022, 14:18:21) [GCC 12.2.0] (/usr/bin/python)
  jinja version = 3.1.2
  libyaml = True

Upvotes: 2

PicoutputCls
PicoutputCls

Reputation: 1579

This problem is very similar to the following: Create a string using Jinja2 template

You could probably employ an similar solution to the one provided there. The following would give you your desired string with line breaks:

"{{ VARS | to_json | regex_replace('\\:\\ ','=') | regex_replace('[\\[\\]{}\\\"]') | regex_replace('\\,\\ ','\\n') }}"

This should give you a string like:

foo=bar
baz=biz

I'm not sure what you intend to use this output for but if you're intending to loop over this elsewhere in Ansible, for example, it may be more useful to split the string into a list of strings rather than using linebreaks. This could be done by using the following alternative:

{{ (VARS | to_json | regex_replace('\\:\\ ','=') | regex_replace('[\\[\\]{}\\\"]')).split(", ") }}

This will return a list like:

[ "foo=bar", "baz=biz" ]

Upvotes: 1

Related Questions