9uzman7
9uzman7

Reputation: 488

Jinja escaping beginning of comment tag

I am trying to create a bash script in a jinja template. I have the following line:

SOME_ARRAY_COUNT=${#SOME_ARRAY[@]}

But it throws an error:

AnsibleError: template error while templating string: Missing end of comment tag

After investigating I found out that a {% raw %}...{% endraw %} block can be used to take literals, but it still doesn't work for {# obtaining a similar error:

An unhandled exception occurred while templating
Error was a <class 'ansible.errors.AnsibleError'>, original message: template error while templating string: Missing end of comment tag

Is there a workaround for this without changing bash logic?

Thanks

UPDATE: including examples

ansible playbook:

... more ansible playbook stuff ...    

tasks:
- name: create script 
  template:
    src: "src/path/to/script.sh.j2"
    dest: "dest/path/to/output/script.sh"

- name: user data script as string
  set_fact:
    userdata: "{{ lookup('file', 'path/to/script.sh') }}"

- name: some cloudformation thing
  cloudformation:
    stack_name: "stack_name"
    state: present
    region: "some region"
    template: "path/to/template/cloudformation.json"
    template_parameters:
      ... a bunch of params ...
      UserDataScript: "{{ userdata }}"
    tags:
      ... tags ..
      metadata: "... metadata ..."
  register: cloudformation_results

jinja template (script.sh.j2):

... more script stuff ...

SOME_ARRAY="some array with elements"
SOME_ARRAY=($SOME_ARRAY)
SOME_ARRAY_COUNT=${#SOME_ARRAY[@]}

... more script stuff ...

THE PROBLEM:

This line: SOME_ARRAY_COUNT=${#SOME_ARRAY[@]} caused in the first template task to ask for a closing #} comment tag. First fix adding raw block:

{% raw %}
SOME_ARRAY_COUNT=${#SOME_ARRAY[@]}
{% endraw %}

Fixes the templating part, but the cloudformation module also applies templating substitutions so it would then have the same error.

THE FIX:

{% raw %}
SOME_ARRAY_COUNT=${{ '{#' }}SOME_ARRAY[@]}
{% endraw %}

First template module removes raw block and keeps {{ '{$' }} and cloudformation module finds {{ '{$' }} and applies literal substitution.

Upvotes: 11

Views: 9578

Answers (1)

larsks
larsks

Reputation: 312263

If I put this into script.sh:

SOME_ARRAY="some array with elements"
SOME_ARRAY=($SOME_ARRAY)
{% raw %}
SOME_ARRAY_COUNT=${#SOME_ARRAY[@]}
{% endraw %}

And this into playbook.yml:

---
- hosts: localhost
  gather_facts: false

  tasks:
    - name: create script
      template:
        src: ./script.sh.j2
        dest: ./script.sh

When I run ansible-playbook playbook.yml, I get as output:

PLAY [localhost] *************************************************************************************************************************************************************

TASK [create script] *********************************************************************************************************************************************************
changed: [localhost]

And script.sh looks like:

SOME_ARRAY="some array with elements"
SOME_ARRAY=($SOME_ARRAY)

SOME_ARRAY_COUNT=${#SOME_ARRAY[@]}

As far as I can tell, everything seems to work as expected.

Upvotes: 10

Related Questions