From e528ed0e9e9f3d3fcb2f33ddc5d175faf72094ac Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Sat, 29 Apr 2023 05:14:16 +0200 Subject: [PATCH] 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 --- doc/source/index.rst | 58 ++++++++++++++++++- plugins/action/config_template.py | 9 ++- .../notes/raw_tag_fixed-9c7cc7506314f76b.yaml | 5 ++ tests/files/test_raw_content.ini.expected | 9 +++ tests/templates/test_raw_content.ini | 7 +++ tests/test-ini.yml | 51 ++++++++++++++++ tests/test.yml | 9 +++ 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/raw_tag_fixed-9c7cc7506314f76b.yaml create mode 100644 tests/files/test_raw_content.ini.expected create mode 100644 tests/templates/test_raw_content.ini diff --git a/doc/source/index.rst b/doc/source/index.rst index 6562ddd..2dcb34f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -153,7 +153,63 @@ Resulting file on the remote host: [hello] 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: diff --git a/plugins/action/config_template.py b/plugins/action/config_template.py index 44e7a63..7a82b45 100644 --- a/plugins/action/config_template.py +++ b/plugins/action/config_template.py @@ -883,7 +883,10 @@ class ActionModule(ActionBase): else: self._templar.available_variables = temp_vars - resultant = self._check_templar(data=template_data, extra=_vars) + if self._task.args.get('content'): + resultant = template_data + else: + resultant = self._check_templar(data=template_data, extra=_vars) if LooseVersion(__ansible_version__) < LooseVersion("2.9"): # Access to protected method is unavoidable in Ansible @@ -953,10 +956,6 @@ class ActionModule(ActionBase): } 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 new_module_args = self._task.args.copy() # Access to protected method is unavoidable in Ansible diff --git a/releasenotes/notes/raw_tag_fixed-9c7cc7506314f76b.yaml b/releasenotes/notes/raw_tag_fixed-9c7cc7506314f76b.yaml new file mode 100644 index 0000000..8e8210f --- /dev/null +++ b/releasenotes/notes/raw_tag_fixed-9c7cc7506314f76b.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Jinja2 {% raw %} tag and string escapnig, as well as special headers in + template files are working as expected now. diff --git a/tests/files/test_raw_content.ini.expected b/tests/files/test_raw_content.ini.expected new file mode 100644 index 0000000..be4a65c --- /dev/null +++ b/tests/files/test_raw_content.ini.expected @@ -0,0 +1,9 @@ +[foo] +# comment +bar = {{ baz }} +foo = delta +foobar = [% test_raw_content_variable %] + +[section2] +alfa = delta + diff --git a/tests/templates/test_raw_content.ini b/tests/templates/test_raw_content.ini new file mode 100644 index 0000000..9b396ae --- /dev/null +++ b/tests/templates/test_raw_content.ini @@ -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 %} diff --git a/tests/test-ini.yml b/tests/test-ini.yml index 160964a..c6734d3 100644 --- a/tests/test-ini.yml +++ b/tests/test-ini.yml @@ -284,3 +284,54 @@ config_overrides: "{{ test_diff_overrides }}" register: test_diff_remove_ini 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)" diff --git a/tests/test.yml b/tests/test.yml index e960292..ed64b93 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -78,6 +78,11 @@ src: "{{ playbook_dir }}/files/test_jinja_variables.yml.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 handlers: @@ -176,6 +181,10 @@ test_jinja_variables: section1: baz: "baz" + test_raw_content_variable: "delta" + test_raw_content_overrides: + section2: + alfa: "{{ test_raw_content_variable }}" test_enhanced_comments_ini_overrides: DEFAULT: default_availability_zone: zone1