# test code for the template module # (c) 2014, Michael DeHaan # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . - name: show python interpreter debug: msg: "{{ ansible_python['executable'] }}" - name: show jinja2 version debug: msg: "{{ lookup('pipe', '{{ ansible_python[\"executable\"] }} -c \"import jinja2; print(jinja2.__version__)\"') }}" - name: get default group shell: id -gn register: group - name: fill in a basic template template: src=foo.j2 dest={{output_dir}}/foo.templated mode=0644 register: template_result - assert: that: - "'changed' in template_result" - "'dest' in template_result" - "'group' in template_result" - "'gid' in template_result" - "'md5sum' in template_result" - "'checksum' in template_result" - "'owner' in template_result" - "'size' in template_result" - "'src' in template_result" - "'state' in template_result" - "'uid' in template_result" - name: verify that the file was marked as changed assert: that: - "template_result.changed == true" # test for import with context on jinja-2.9 See https://github.com/ansible/ansible/issues/20494 - name: fill in a template using import with context ala issue 20494 template: src=import_with_context.j2 dest={{output_dir}}/import_with_context.templated mode=0644 register: template_result - name: copy known good import_with_context.expected into place copy: src=import_with_context.expected dest={{output_dir}}/import_with_context.expected - name: compare templated file to known good import_with_context shell: diff -uw {{output_dir}}/import_with_context.templated {{output_dir}}/import_with_context.expected register: diff_result - name: verify templated import_with_context matches known good assert: that: - 'diff_result.stdout == ""' - "diff_result.rc == 0" # test for nested include https://github.com/ansible/ansible/issues/34886 - name: test if parent variables are defined in nested include template: src=for_loop.j2 dest={{output_dir}}/for_loop.templated mode=0644 - name: save templated output shell: "cat {{output_dir}}/for_loop.templated" register: for_loop_out - debug: var=for_loop_out - name: verify variables got templated assert: that: - '"foo" in for_loop_out.stdout' - '"bar" in for_loop_out.stdout' - '"bam" in for_loop_out.stdout' # test for 'import as' on jinja-2.9 See https://github.com/ansible/ansible/issues/20494 - name: fill in a template using import as ala fails2 case in issue 20494 template: src=import_as.j2 dest={{output_dir}}/import_as.templated mode=0644 register: import_as_template_result - name: copy known good import_as.expected into place copy: src=import_as.expected dest={{output_dir}}/import_as.expected - name: compare templated file to known good import_as shell: diff -uw {{output_dir}}/import_as.templated {{output_dir}}/import_as.expected register: import_as_diff_result - name: verify templated import_as matches known good assert: that: - 'import_as_diff_result.stdout == ""' - "import_as_diff_result.rc == 0" # test for 'import as with context' on jinja-2.9 See https://github.com/ansible/ansible/issues/20494 - name: fill in a template using import as with context ala fails2 case in issue 20494 template: src=import_as_with_context.j2 dest={{output_dir}}/import_as_with_context.templated mode=0644 register: import_as_with_context_template_result - name: copy known good import_as_with_context.expected into place copy: src=import_as_with_context.expected dest={{output_dir}}/import_as_with_context.expected - name: compare templated file to known good import_as_with_context shell: diff -uw {{output_dir}}/import_as_with_context.templated {{output_dir}}/import_as_with_context.expected register: import_as_with_context_diff_result - name: verify templated import_as_with_context matches known good assert: that: - 'import_as_with_context_diff_result.stdout == ""' - "import_as_with_context_diff_result.rc == 0" # VERIFY trim_blocks - name: Render a template with "trim_blocks" set to False template: src: trim_blocks.j2 dest: "{{output_dir}}/trim_blocks_false.templated" trim_blocks: False register: trim_blocks_false_result - name: Get checksum of known good trim_blocks_false.expected stat: path: "{{role_path}}/files/trim_blocks_false.expected" register: trim_blocks_false_good - name: Verify templated trim_blocks_false matches known good using checksum assert: that: - "trim_blocks_false_result.checksum == trim_blocks_false_good.stat.checksum" - name: Render a template with "trim_blocks" set to True template: src: trim_blocks.j2 dest: "{{output_dir}}/trim_blocks_true.templated" trim_blocks: True register: trim_blocks_true_result - name: Get checksum of known good trim_blocks_true.expected stat: path: "{{role_path}}/files/trim_blocks_true.expected" register: trim_blocks_true_good - name: Verify templated trim_blocks_true matches known good using checksum assert: that: - "trim_blocks_true_result.checksum == trim_blocks_true_good.stat.checksum" # VERIFY lstrip_blocks - name: Check support for lstrip_blocks in Jinja2 shell: "{{ ansible_python.executable }} -c 'import jinja2; jinja2.defaults.LSTRIP_BLOCKS'" register: lstrip_block_support ignore_errors: True - name: Render a template with "lstrip_blocks" set to False template: src: lstrip_blocks.j2 dest: "{{output_dir}}/lstrip_blocks_false.templated" lstrip_blocks: False register: lstrip_blocks_false_result - name: Get checksum of known good lstrip_blocks_false.expected stat: path: "{{role_path}}/files/lstrip_blocks_false.expected" register: lstrip_blocks_false_good - name: Verify templated lstrip_blocks_false matches known good using checksum assert: that: - "lstrip_blocks_false_result.checksum == lstrip_blocks_false_good.stat.checksum" - name: Render a template with "lstrip_blocks" set to True template: src: lstrip_blocks.j2 dest: "{{output_dir}}/lstrip_blocks_true.templated" lstrip_blocks: True register: lstrip_blocks_true_result ignore_errors: True - name: Verify exception is thrown if Jinja2 does not support lstrip_blocks but lstrip_blocks is used assert: that: - "lstrip_blocks_true_result.failed" - 'lstrip_blocks_true_result.msg is search(">=2.7")' when: "lstrip_block_support is failed" - name: Get checksum of known good lstrip_blocks_true.expected stat: path: "{{role_path}}/files/lstrip_blocks_true.expected" register: lstrip_blocks_true_good when: "lstrip_block_support is successful" - name: Verify templated lstrip_blocks_true matches known good using checksum assert: that: - "lstrip_blocks_true_result.checksum == lstrip_blocks_true_good.stat.checksum" when: "lstrip_block_support is successful" # VERIFY CONTENTS - name: check what python version ansible is running on command: "{{ ansible_python.executable }} -c 'import distutils.sysconfig ; print(distutils.sysconfig.get_python_version())'" register: pyver delegate_to: localhost - name: copy known good into place copy: src=foo.txt dest={{output_dir}}/foo.txt - name: compare templated file to known good shell: diff -uw {{output_dir}}/foo.templated {{output_dir}}/foo.txt register: diff_result - name: verify templated file matches known good assert: that: - 'diff_result.stdout == ""' - "diff_result.rc == 0" # VERIFY MODE - name: set file mode file: path={{output_dir}}/foo.templated mode=0644 register: file_result - name: ensure file mode did not change assert: that: - "file_result.changed != True" # 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 file: state=directory dest={{output_dir | expanduser}}/template-dir mode=0755 owner=nobody group={{ group.stdout }} - name: set file mode when the destination is a directory template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir/ mode=0600 owner=root group={{ group.stdout }} - name: set file mode when the destination is a directory template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir/ mode=0600 owner=root group={{ group.stdout }} register: file_result - name: check that the file has the correct attributes stat: path={{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 stat: path={{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: Check that template to a directory where the directory does not end with a / is allowed template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir mode=0600 owner=root group={{ group.stdout }} - name: make a symlink to the templated file file: path: '{{ output_dir }}/foo.symlink' src: '{{ output_dir }}/foo.templated' state: link - name: check that templating the symlink results in the file being templated template: src: foo.j2 dest: '{{output_dir}}/foo.symlink' mode: 0600 follow: True register: template_result - assert: that: - "template_result.changed == True" - name: check that the file has the correct attributes stat: path={{output_dir | expanduser}}/template-dir/foo.j2 register: file_attrs - assert: that: - "file_attrs.stat.mode == '0600'" - name: check that templating the symlink again makes no changes template: src: foo.j2 dest: '{{output_dir}}/foo.symlink' mode: 0600 follow: True register: template_result - assert: that: - "template_result.changed == False" # Test strange filenames - name: Create a temp dir for filename tests file: state: directory dest: '{{ output_dir }}/filename-tests' - name: create a file with an unusual filename template: src: foo.j2 dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated" register: template_result - assert: that: - "template_result.changed == True" - name: check that the unusual filename was created command: "ls {{ output_dir }}/filename-tests/" register: unusual_results - assert: that: - "\"foo t'e~m\\plated\" in unusual_results.stdout_lines" - "{{unusual_results.stdout_lines| length}} == 1" - name: check that the unusual filename can be checked for changes template: src: foo.j2 dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated" register: template_result - assert: that: - "template_result.changed == False" # check_mode - name: fill in a basic template in check mode template: src=short.j2 dest={{output_dir}}/short.templated register: template_result check_mode: True - name: check file exists stat: path={{output_dir}}/short.templated register: templated - name: verify that the file was marked as changed in check mode but was not created assert: that: - "not templated.stat.exists" - "template_result is changed" - name: fill in a basic template template: src=short.j2 dest={{output_dir}}/short.templated - name: fill in a basic template in check mode template: src=short.j2 dest={{output_dir}}/short.templated register: template_result check_mode: True - name: verify that the file was marked as not changes in check mode assert: that: - "template_result is not changed" - "'templated_var_loaded' in lookup('file', '{{output_dir | expanduser}}/short.templated')" - name: change var for the template set_fact: templated_var: "changed" - name: fill in a basic template with changed var in check mode template: src=short.j2 dest={{output_dir}}/short.templated register: template_result check_mode: True - name: verify that the file was marked as changed in check mode but the content was not changed assert: that: - "'templated_var_loaded' in lookup('file', '{{output_dir | expanduser }}/short.templated')" - "template_result is changed" # Create a template using a child template, to ensure that variables # are passed properly from the parent to subtemplate context (issue #20063) - name: test parent and subtemplate creation of context template: src=parent.j2 dest={{output_dir}}/parent_and_subtemplate.templated register: template_result - stat: path={{output_dir}}/parent_and_subtemplate.templated - name: verify that the parent and subtemplate creation worked assert: that: - "template_result is changed" # # template module can overwrite a file that's been hard linked # https://github.com/ansible/ansible/issues/10834 # - name: ensure test dir is absent file: path: '{{ output_dir | expanduser }}/hlink_dir' state: absent - name: create test dir file: path: '{{ output_dir | expanduser }}/hlink_dir' state: directory - name: template out test file to system 1 template: src: foo.j2 dest: '{{ output_dir | expanduser }}/hlink_dir/test_file' - name: make hard link file: src: '{{ output_dir | expanduser }}/hlink_dir/test_file' dest: '{{ output_dir | expanduser }}/hlink_dir/test_file_hlink' state: hard - name: template out test file to system 2 template: src: foo.j2 dest: '{{ output_dir | expanduser }}/hlink_dir/test_file' register: hlink_result - name: check that the files are still hardlinked stat: path: '{{ output_dir | expanduser }}/hlink_dir/test_file' register: orig_file - name: check that the files are still hardlinked stat: path: '{{ output_dir | expanduser }}/hlink_dir/test_file_hlink' register: hlink_file # We've done nothing at this point to update the content of the file so it should still be hardlinked - assert: that: - "hlink_result.changed == False" - "orig_file.stat.inode == hlink_file.stat.inode" - name: change var for the template set_fact: templated_var: "templated_var_loaded" # UNIX TEMPLATE - name: fill in a basic template (Unix) template: src: foo2.j2 dest: '{{ output_dir }}/foo.unix.templated' register: template_result - name: verify that the file was marked as changed (Unix) assert: that: - 'template_result is changed' - name: fill in a basic template again (Unix) template: src: foo2.j2 dest: '{{ output_dir }}/foo.unix.templated' register: template_result2 - name: verify that the template was not changed (Unix) assert: that: - 'template_result2 is not changed' # VERIFY UNIX CONTENTS - name: copy known good into place (Unix) copy: src: foo.unix.txt dest: '{{ output_dir }}/foo.unix.txt' - name: Dump templated file (Unix) command: hexdump -C {{ output_dir }}/foo.unix.templated - name: Dump expected file (Unix) command: hexdump -C {{ output_dir }}/foo.unix.txt - name: compare templated file to known good (Unix) command: diff -u {{ output_dir }}/foo.unix.templated {{ output_dir }}/foo.unix.txt register: diff_result - name: verify templated file matches known good (Unix) assert: that: - 'diff_result.stdout == ""' - "diff_result.rc == 0" # DOS TEMPLATE - name: fill in a basic template (DOS) template: src: foo2.j2 dest: '{{ output_dir }}/foo.dos.templated' newline_sequence: '\r\n' register: template_result - name: verify that the file was marked as changed (DOS) assert: that: - 'template_result is changed' - name: fill in a basic template again (DOS) template: src: foo2.j2 dest: '{{ output_dir }}/foo.dos.templated' newline_sequence: '\r\n' register: template_result2 - name: verify that the template was not changed (DOS) assert: that: - 'template_result2 is not changed' # VERIFY DOS CONTENTS - name: copy known good into place (DOS) copy: src: foo.dos.txt dest: '{{ output_dir }}/foo.dos.txt' - name: Dump templated file (DOS) command: hexdump -C {{ output_dir }}/foo.dos.templated - name: Dump expected file (DOS) command: hexdump -C {{ output_dir }}/foo.dos.txt - name: compare templated file to known good (DOS) command: diff -u {{ output_dir }}/foo.dos.templated {{ output_dir }}/foo.dos.txt register: diff_result - name: verify templated file matches known good (DOS) assert: that: - 'diff_result.stdout == ""' - "diff_result.rc == 0" # VERIFY DOS CONTENTS - name: copy known good into place (Unix) copy: src: foo.unix.txt dest: '{{ output_dir }}/foo.unix.txt' - name: Dump templated file (Unix) command: hexdump -C {{ output_dir }}/foo.unix.templated - name: Dump expected file (Unix) command: hexdump -C {{ output_dir }}/foo.unix.txt - name: compare templated file to known good (Unix) command: diff -u {{ output_dir }}/foo.unix.templated {{ output_dir }}/foo.unix.txt register: diff_result - name: verify templated file matches known good (Unix) assert: that: - 'diff_result.stdout == ""' - "diff_result.rc == 0" # Check that mode=preserve works with template - name: Create a template which has strange permissions copy: content: !unsafe '{{ ansible_managed }}\n' dest: '{{ output_dir }}/foo-template.j2' mode: 0547 delegate_to: localhost - name: Use template with mode=preserve template: src: '{{ output_dir }}/foo-template.j2' dest: '{{ output_dir }}/foo-templated.txt' mode: 'preserve' register: template_results - name: Get permissions from the templated file stat: path: '{{ output_dir }}/foo-templated.txt' register: stat_results - name: Check that the resulting file has the correct permissions assert: that: - 'template_results is changed' - 'template_results.mode == "0547"' - 'stat_results.stat["mode"] == "0547"' # aliases file requires root for template tests so this should be safe - include: backup_test.yml