Search code examples
linuxbashdocker-composeansiblestring-interpolation

Preserve single/double quotes around value after interpolation and escape dollar($) sign


I have docker-compose file and try to provide environment variable like this:

    environment:
      {{ envs | to_nice_yaml(indent=2) | indent(width=6) }}

Overall it's fine except one env var SPRING_SECURITY_USER_PASSWORD: $2b$10$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS which contains $ in its value and other special characters. $ causes an bash interpolation issue when I try to run services, because it tried to substitute variable which doesn't exist. How to wrap this value into single quotas and escape $ sign?

What I tried already:

  • SPRING_SECURITY_USER_PASSWORD: "{{ spring_security_user_password | password_hash('bcrypt', rounds=10) }}" -> $2b$10$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS

  • SPRING_SECURITY_USER_PASSWORD: '"{{ spring_security_user_password | password_hash('bcrypt', rounds=10) }}"' -> '"$2b$10$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS"' no idea why it preserved both ' and "

  • SPRING_SECURITY_USER_PASSWORD: "{{ spring_security_user_password | password_hash('bcrypt', rounds=10) | quote }}" -> '''$2b$10$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS''' not idea why it add triple '

  • SPRING_SECURITY_USER_PASSWORD: " {{ spring_security_user_password | password_hash('bcrypt', rounds=10) }} " -> ' $2b$10$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS ' yoohoo I wrapped it into ', but it added extra whitespace - why?

How can I get value like this SPRING_SECURITY_USER_PASSWORD: '$$2b$$10$$J82IHSFuwneniWNTrkn8RO2N9Gjvi3juBa805IGyqR/y/w0as29VS' $ escapped using $ and literal wrapped using '


Solution

  • Another more reliable solution using jinja2 script:

        environment:
    {% for name, value in envs.items() %}
    {%  if value is string %}
    {%    if not value.startswith('\'') and not value.startswith('"') %}
          {{ name }}: '{{ value | replace('$', '$$') }}'
    {%    else %}
          {{ name }}: {{ value | replace('$', '$$') }}
    {%    endif %}
    {%  else %}
          {{ name }}: {{ value }}
    {%  endif %}
    {% endfor %}
    

    which also does the work