Fix usage of {% raw %} tags and Jinja2 headers

At the moment we do resolve template 2 times for some historical reasons

This leads to {% raw %} tag as well as any other content be not respected
on the second renderring, since after the first one these tags
are gone, so no escaping or whatsoever work.

At the same time there're no obvious reasons to render second time,
since all override content is being renderred already. So there should
not be anything left that indeed needs this second run.

Change-Id: I414b1b3b4e426316707dda23b9aeff6b6f4f7c2f
Closes-Bug: #1649381
This commit is contained in:
Dmitriy Rabotyagov 2023-04-29 05:14:16 +02:00
parent fdb572d0ba
commit e528ed0e9e
7 changed files with 142 additions and 6 deletions

View File

@ -153,7 +153,63 @@ Resulting file on the remote host:
[hello] [hello]
cruel = world cruel = world
Installing collection
Preventing content from renderring
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are few different way that can be used to prevent some content
from being renderred. First one is to use Jinja's ``{% raw %}`` tag.
Template:
.. code-block :: ini
[foo]
# comment
bar = {% raw %}{{ baz }}{% endraw %}
Result:
.. code-block :: ini
[foo]
# comment
bar = {{ baz }}
Another way around could be customizing Jinja tags used to identify variables
and block string. For that `variable_start/end_string` or `block_start/end_string`
options could be used. These variables could be provided as an arguments to
the module or by adding a special header to template file.
.. Note::
Please mention, that changing identification for start/end of blocks works only
inside the template and does not affect ``config_overrides`` option.
Template:
.. code-block :: ini
#jinja2:variable_start_string:'[%', variable_end_string:'%]'
[foo]
# comment
bar = {{ baz }}
foo = [% inventory_hostname %]
Result:
.. code-block :: ini
[foo]
# comment
bar = {{ baz }}
foo = localhost
--------------------- ---------------------
To use the collection, include this in your meta/main.yml: To use the collection, include this in your meta/main.yml:

View File

@ -883,6 +883,9 @@ class ActionModule(ActionBase):
else: else:
self._templar.available_variables = temp_vars self._templar.available_variables = temp_vars
if self._task.args.get('content'):
resultant = template_data
else:
resultant = self._check_templar(data=template_data, extra=_vars) resultant = self._check_templar(data=template_data, extra=_vars)
if LooseVersion(__ansible_version__) < LooseVersion("2.9"): if LooseVersion(__ansible_version__) < LooseVersion("2.9"):
@ -953,10 +956,6 @@ class ActionModule(ActionBase):
} }
changed = len(mods['changed']) > 0 changed = len(mods['changed']) > 0
# Re-template the resultant object as it may have new data within it
# as provided by an override variable.
resultant = self._check_templar(data=resultant, extra=_vars)
# run the copy module # run the copy module
new_module_args = self._task.args.copy() new_module_args = self._task.args.copy()
# Access to protected method is unavoidable in Ansible # Access to protected method is unavoidable in Ansible

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Jinja2 {% raw %} tag and string escapnig, as well as special headers in
template files are working as expected now.

View File

@ -0,0 +1,9 @@
[foo]
# comment
bar = {{ baz }}
foo = delta
foobar = [% test_raw_content_variable %]
[section2]
alfa = delta

View File

@ -0,0 +1,7 @@
#jinja2:variable_start_string:'[%', variable_end_string:'%]'
[foo]
# comment
bar = {{ baz }}
foo = [% test_raw_content_variable %]
foobar = {% raw %}[% test_raw_content_variable %]{% endraw %}

View File

@ -284,3 +284,54 @@
config_overrides: "{{ test_diff_overrides }}" config_overrides: "{{ test_diff_overrides }}"
register: test_diff_remove_ini register: test_diff_remove_ini
notify: test_diff_remove_ini check diff notify: test_diff_remove_ini check diff
# Check if {% raw %} is working
- name: Test template with jinja vars in it
config_template:
src: "{{ playbook_dir }}/templates/test_raw_content.ini"
dest: "/tmp/test_raw_content.ini"
config_overrides: "{{ test_raw_content_overrides }}"
config_type: ini
- name: Test content with jinja vars in it
config_template:
content: |
#jinja2:variable_start_string:'[%', variable_end_string:'%]'
[foo]
# comment
bar = {{ baz }}
foo = [% test_raw_content_variable %]
foobar = {% raw %}[% test_raw_content_variable %]{% endraw %}
dest: "/tmp/test_raw_usr_content.ini"
config_overrides: "{{ test_raw_content_overrides }}"
config_type: ini
- name: Read test_raw_content.ini
slurp:
src: /tmp/test_raw_content.ini
register: test_raw_content
- name: Read test_raw_usr_content.ini
slurp:
src: /tmp/test_raw_usr_content.ini
register: test_raw_usr_content
- debug:
msg: "Raw Jinja content - {{ test_raw_content.content | b64decode }}"
- debug:
msg: "Raw Jinja user content - {{ test_raw_usr_content.content | b64decode }}"
- debug:
msg: "Raw Jinja content Expected - {{ test_raw_content_expected.content | b64decode }}"
- name: Compare files
assert:
that:
- "(test_raw_content_expected.content | b64decode) == (test_raw_usr_content.content | b64decode)"
- name: Compare files
assert:
that:
- "(test_raw_content_expected.content | b64decode) == (test_raw_content.content | b64decode)"

View File

@ -78,6 +78,11 @@
src: "{{ playbook_dir }}/files/test_jinja_variables.yml.expected" src: "{{ playbook_dir }}/files/test_jinja_variables.yml.expected"
register: test_jinja_variables_expected register: test_jinja_variables_expected
- name: Read expected test_jinja_variables.yml
slurp:
src: "{{ playbook_dir }}/files/test_raw_content.ini.expected"
register: test_raw_content_expected
- import_tasks: test-common-tasks.yml - import_tasks: test-common-tasks.yml
handlers: handlers:
@ -176,6 +181,10 @@
test_jinja_variables: test_jinja_variables:
section1: section1:
baz: "baz" baz: "baz"
test_raw_content_variable: "delta"
test_raw_content_overrides:
section2:
alfa: "{{ test_raw_content_variable }}"
test_enhanced_comments_ini_overrides: test_enhanced_comments_ini_overrides:
DEFAULT: DEFAULT:
default_availability_zone: zone1 default_availability_zone: zone1