diff --git a/lib/ansible/modules/files/template.py b/lib/ansible/modules/files/template.py index 57bf68aab70..a14c90213a8 100644 --- a/lib/ansible/modules/files/template.py +++ b/lib/ansible/modules/files/template.py @@ -17,92 +17,7 @@ DOCUMENTATION = r''' --- module: template version_added: historical -short_description: Template a file out to a remote server -description: -- Templates are processed by the L(Jinja2 templating language,http://jinja.pocoo.org/docs/). -- Documentation on the template formatting can be found in the - L(Template Designer Documentation,http://jinja.pocoo.org/docs/templates/). -- Additional variables listed below can be used in templates. -- C(ansible_managed) (configurable via the C(defaults) section of C(ansible.cfg)) contains a string which can be used to - describe the template name, host, modification time of the template file and the owner uid. -- C(template_host) contains the node name of the template's machine. -- C(template_uid) is the numeric user id of the owner. -- C(template_path) is the path of the template. -- C(template_fullpath) is the absolute path of the template. -- C(template_destpath) is the path of the template on the remote system (added in 2.8). -- C(template_run_date) is the date that the template was rendered. options: - src: - description: - - Path of a Jinja2 formatted template on the Ansible controller. - - This can be a relative or an absolute path. - type: path - required: yes - dest: - description: - - Location to render the template to on the remote machine. - type: path - required: yes - backup: - description: - - Determine whether a backup should be created. - - When set to C(yes), create a backup file including the timestamp information - so you can get the original file back if you somehow clobbered it incorrectly. - type: bool - default: no - newline_sequence: - description: - - Specify the newline sequence to use for templating files. - type: str - choices: [ '\n', '\r', '\r\n' ] - default: '\n' - version_added: '2.4' - block_start_string: - description: - - The string marking the beginning of a block. - type: str - default: '{%' - version_added: '2.4' - block_end_string: - description: - - The string marking the end of a block. - type: str - default: '%}' - version_added: '2.4' - variable_start_string: - description: - - The string marking the beginning of a print statement. - type: str - default: '{{' - version_added: '2.4' - variable_end_string: - description: - - The string marking the end of a print statement. - type: str - default: '}}' - version_added: '2.4' - trim_blocks: - description: - - Determine when newlines should be removed from blocks. - - When set to C(yes) the first newline after a block is removed (block, not variable tag!). - type: bool - default: yes - version_added: '2.4' - lstrip_blocks: - description: - - Determine when leading spaces and tabs should be stripped. - - When set to C(yes) leading spaces and tabs are stripped from the start of a line to a block. - - This functionality requires Jinja 2.7 or newer. - type: bool - default: no - version_added: '2.6' - force: - description: - - Determine when the file is being transferred if the destination already exists. - - When set to C(yes), replace the remote file when contents are different than the source. - - When set to C(no), the file will only be transferred if the destination does not exist. - type: bool - default: yes follow: description: - Determine whether symbolic links should be followed. @@ -112,24 +27,7 @@ options: type: bool default: no version_added: '2.4' - output_encoding: - description: - - Overrides the encoding used to write the template file defined by C(dest). - - It defaults to C(utf-8), but any encoding supported by python can be used. - - The source template file must always be encoded using C(utf-8), for homogeneity. - type: str - default: utf-8 - version_added: '2.7' notes: -- Including a string that uses a date in the template will result in the template being marked 'changed' each time. -- Since Ansible 0.9, templates are loaded with C(trim_blocks=True). -- > - Also, you can override jinja2 settings by adding a special header to template file. - i.e. C(#jinja2:variable_start_string:'[%', variable_end_string:'%]', trim_blocks: False) - which changes the variable interpolation markers to C([% var %]) instead of C({{ var }}). - This is the best way to prevent evaluation of things that look like, but should not be Jinja2. -- Using raw/endraw in Jinja2 will not work as you expect because templates in Ansible are recursively - evaluated. - You can use the M(copy) module with the C(content:) option if you prefer the template inline, as part of the playbook. - For Windows you can use M(win_template) which uses '\\r\\n' as C(newline_sequence) by default. @@ -142,6 +40,7 @@ author: - Michael DeHaan extends_documentation_fragment: - files +- template_common - validate ''' diff --git a/lib/ansible/modules/windows/win_template.py b/lib/ansible/modules/windows/win_template.py index b16bf2947b4..86898f24645 100644 --- a/lib/ansible/modules/windows/win_template.py +++ b/lib/ansible/modules/windows/win_template.py @@ -13,108 +13,27 @@ DOCUMENTATION = r''' --- module: win_template version_added: "1.9.2" -short_description: Templates a file out to a remote server -description: - - Templates are processed by the Jinja2 templating language - (U(http://jinja.pocoo.org/docs/)) - documentation on the template - formatting can be found in the Template Designer Documentation - (U(http://jinja.pocoo.org/docs/templates/)). - - "Additional variables can be used in templates: C(ansible_managed) - (configurable via the C(defaults) section of C(ansible.cfg)) contains a string - which can be used to describe the template name, host, modification time of the - template file and the owner uid." - - "C(template_host) contains the node name of the template's machine." - - "C(template_uid) the owner." - - "C(template_path) the absolute path of the template." - - "C(template_fullpath) is the absolute path of the template." - - "C(template_destpath) is the path of the template on the remote system (added in 2.8)." - - "C(template_run_date) is the date that the template was rendered." - - "Note that including a string that uses a date in the template will result in the template being marked 'changed' each time." - - For other platforms you can use M(template) which uses '\n' as C(newline_sequence). options: - src: - description: - - Path of a Jinja2 formatted template on the local server. This can be a relative or absolute path. - type: path - required: yes - dest: - description: - - Location to render the template to on the remote machine. - type: path - required: yes backup: - description: - - Determine whether a backup should be created. - - When set to C(yes), create a backup file including the timestamp information - so you can get the original file back if you somehow clobbered it incorrectly. - type: bool - default: no version_added: '2.8' newline_sequence: - description: - - Specify the newline sequence to use for templating files. - type: str - choices: [ '\n', '\r', '\r\n' ] default: '\r\n' - version_added: '2.4' - block_start_string: - description: - - The string marking the beginning of a block. - type: str - default: '{%' - version_added: '2.4' - block_end_string: - description: - - The string marking the end of a block. - type: str - default: '%}' - version_added: '2.4' - variable_start_string: - description: - - The string marking the beginning of a print statement. - type: str - default: '{{' - version_added: '2.4' - variable_end_string: - description: - - The string marking the end of a print statement. - type: str - default: '}}' - version_added: '2.4' - trim_blocks: - description: - - If this is set to C(yes) the first newline after a block is removed (block, not variable tag!). - type: bool - default: no - version_added: '2.4' force: - description: - - If C(yes), will replace the remote file when contents are different - from the source. - - If C(no), the file will only be transferred if the destination does - not exist. - type: bool - default: yes version_added: '2.4' notes: - - Templates are loaded with C(trim_blocks=yes). - - Beware fetching files from windows machines when creating templates - because certain tools, such as Powershell ISE, and regedit's export facility - add a Byte Order Mark as the first character of the file, which can cause tracebacks. - - To find Byte Order Marks in files, use C(Format-Hex -Count 16) on Windows, and use C(od -a -t x1 -N 16 ) on Linux. - - "Also, you can override jinja2 settings by adding a special header to template file. - i.e. C(#jinja2:variable_start_string:'[%', variable_end_string:'%]', trim_blocks: no) - which changes the variable interpolation markers to [% var %] instead of {{ var }}. - This is the best way to prevent evaluation of things that look like, but should not be Jinja2. - raw/endraw in Jinja2 will not work as you expect because templates in Ansible are recursively evaluated." - - You can use the M(win_copy) module with the C(content:) option if you prefer the template inline, - as part of the playbook. - +- Beware fetching files from windows machines when creating templates because certain tools, such as Powershell ISE, + and regedit's export facility add a Byte Order Mark as the first character of the file, which can cause tracebacks. +- You can use the M(win_copy) module with the C(content:) option if you prefer the template inline, as part of the + playbook. +- For Linux you can use M(template) which uses '\\n' as C(newline_sequence) by default. seealso: -- module: template - module: win_copy +- module: copy +- module: template author: - Jon Hawkesworth (@jhawkesworth) +extends_documentation_fragment: +- template_common ''' EXAMPLES = r''' diff --git a/lib/ansible/plugins/doc_fragments/template_common.py b/lib/ansible/plugins/doc_fragments/template_common.py new file mode 100644 index 00000000000..0e7dd883658 --- /dev/null +++ b/lib/ansible/plugins/doc_fragments/template_common.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2019 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Standard template documentation fragment, use by template and win_template. + DOCUMENTATION = r''' +short_description: Template a file out to a remote server +description: +- Templates are processed by the L(Jinja2 templating language,http://jinja.pocoo.org/docs/). +- Documentation on the template formatting can be found in the + L(Template Designer Documentation,http://jinja.pocoo.org/docs/templates/). +- Additional variables listed below can be used in templates. +- C(ansible_managed) (configurable via the C(defaults) section of C(ansible.cfg)) contains a string which can be used to + describe the template name, host, modification time of the template file and the owner uid. +- C(template_host) contains the node name of the template's machine. +- C(template_uid) is the numeric user id of the owner. +- C(template_path) is the path of the template. +- C(template_fullpath) is the absolute path of the template. +- C(template_destpath) is the path of the template on the remote system (added in 2.8). +- C(template_run_date) is the date that the template was rendered. +options: + src: + description: + - Path of a Jinja2 formatted template on the Ansible controller. + - This can be a relative or an absolute path. + - The file must be encoded with C(utf-8) but I(output_encoding) can be used to control the encoding of the output + template. + type: path + required: yes + dest: + description: + - Location to render the template to on the remote machine. + type: path + required: yes + backup: + description: + - Determine whether a backup should be created. + - When set to C(yes), create a backup file including the timestamp information + so you can get the original file back if you somehow clobbered it incorrectly. + type: bool + default: no + newline_sequence: + description: + - Specify the newline sequence to use for templating files. + type: str + choices: [ '\n', '\r', '\r\n' ] + default: '\n' + version_added: '2.4' + block_start_string: + description: + - The string marking the beginning of a block. + type: str + default: '{%' + version_added: '2.4' + block_end_string: + description: + - The string marking the end of a block. + type: str + default: '%}' + version_added: '2.4' + variable_start_string: + description: + - The string marking the beginning of a print statement. + type: str + default: '{{' + version_added: '2.4' + variable_end_string: + description: + - The string marking the end of a print statement. + type: str + default: '}}' + version_added: '2.4' + trim_blocks: + description: + - Determine when newlines should be removed from blocks. + - When set to C(yes) the first newline after a block is removed (block, not variable tag!). + type: bool + default: yes + version_added: '2.4' + lstrip_blocks: + description: + - Determine when leading spaces and tabs should be stripped. + - When set to C(yes) leading spaces and tabs are stripped from the start of a line to a block. + - This functionality requires Jinja 2.7 or newer. + type: bool + default: no + version_added: '2.6' + force: + description: + - Determine when the file is being transferred if the destination already exists. + - When set to C(yes), replace the remote file when contents are different than the source. + - When set to C(no), the file will only be transferred if the destination does not exist. + type: bool + default: yes + output_encoding: + description: + - Overrides the encoding used to write the template file defined by C(dest). + - It defaults to C(utf-8), but any encoding supported by python can be used. + - The source template file must always be encoded using C(utf-8), for homogeneity. + type: str + default: utf-8 + version_added: '2.7' +notes: +- Including a string that uses a date in the template will result in the template being marked 'changed' each time. +- Since Ansible 0.9, templates are loaded with C(trim_blocks=True). +- > + Also, you can override jinja2 settings by adding a special header to template file. + i.e. C(#jinja2:variable_start_string:'[%', variable_end_string:'%]', trim_blocks: False) + which changes the variable interpolation markers to C([% var %]) instead of C({{ var }}). + This is the best way to prevent evaluation of things that look like, but should not be Jinja2. +- Using raw/endraw in Jinja2 will not work as you expect because templates in Ansible are recursively + evaluated. +- To find Byte Order Marks in files, use C(Format-Hex -Count 16) on Windows, and use C(od -a -t x1 -N 16 ) + on Linux. +''' diff --git a/test/integration/targets/win_template/tasks/main.yml b/test/integration/targets/win_template/tasks/main.yml index 2d34c1d05f2..417aa89ab9c 100644 --- a/test/integration/targets/win_template/tasks/main.yml +++ b/test/integration/targets/win_template/tasks/main.yml @@ -251,47 +251,41 @@ that: - not template_to_dir_again is changed -# VERIFY MODE -# can't set file mode on windows so commenting this test out -#- name: set file mode -# win_file: path={{win_output_dir}}/foo.templated mode=0644 -# register: file_result +- name: template a file with utf-8 encoding + win_template: + src: foo.utf-8.j2 + dest: '{{ win_output_dir }}\foo.encoding.txt' + register: template_utf8 -#- name: ensure file mode did not change -# assert: -# that: -# - "file_result.changed != True" +- name: slurp utf-8 templated file + slurp: + path: '{{ win_output_dir }}\foo.encoding.txt' + register: template_utf8_actual -# commenting out all the following tests as expanduser and file modes not windows concepts. +- name: get expected templated contents + set_fact: + expected_content: '{{ lookup("template", "foo.utf-8.j2") | trim }}' -# VERIFY dest as a directory does not break file attributes -# Note: expanduser is needed to go down the particular codepath that was broken before -#- name: setup directory for test -# win_file: state=directory dest={{win_output_dir | expanduser}}/template-dir mode=0755 owner=nobody group=root +- name: assert template a file with utf-8 encoding + assert: + that: + - template_utf8 is changed + - template_utf8_actual.content | b64decode(encoding='utf-8') == expected_content + "\r\n" -#- name: set file mode when the destination is a directory -# win_template: src=foo.j2 dest={{win_output_dir | expanduser}}/template-dir/ mode=0600 owner=root group=root +- name: template a file with windows-1252 encoding + win_template: + src: foo.utf-8.j2 + dest: '{{ win_output_dir }}\foo.encoding.txt' + output_encoding: windows-1252 + register: template_windows_1252 -#- name: set file mode when the destination is a directory -# win_template: src=foo.j2 dest={{win_output_dir | expanduser}}/template-dir/ mode=0600 owner=root group=root -# register: file_result -# -#- name: check that the file has the correct attributes -# win_stat: path={{win_output_dir | expanduser}}/template-dir/foo.j2 -# register: file_attrs -# -#- assert: -# that: -# - "file_attrs.stat.uid == 0" -# - "file_attrs.stat.pw_name == 'root'" -# - "file_attrs.stat.mode == '0600'" -# -#- name: check that the containing directory did not change attributes -# win_stat: path={{win_output_dir | expanduser}}/template-dir/ -# register: dir_attrs -# -#- assert: -# that: -# - "dir_attrs.stat.uid != 0" -# - "dir_attrs.stat.pw_name == 'nobody'" -# - "dir_attrs.stat.mode == '0755'" +- name: slurp windows-1252 encoding + slurp: + path: '{{ win_output_dir }}\foo.encoding.txt' + register: template_windows_1252_actual + +- name: assert template a file with windows-1252 encoding + assert: + that: + - template_windows_1252 is changed + - template_windows_1252_actual.content | b64decode(encoding='windows-1252') == expected_content + "\r\n" diff --git a/test/integration/targets/win_template/templates/foo.utf-8.j2 b/test/integration/targets/win_template/templates/foo.utf-8.j2 new file mode 100644 index 00000000000..65b95669b8a --- /dev/null +++ b/test/integration/targets/win_template/templates/foo.utf-8.j2 @@ -0,0 +1 @@ +—café— - {{ templated_var }}