# test code for the copy module and action plugin # (c) 2014, Michael DeHaan # (c) 2017, Ansible Project # # GNU General Public License v3 or later (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt ) # - name: Record the output directory set_fact: remote_file: "{{ remote_dir }}/foo.txt" - name: Initiate a basic copy, and also test the mode copy: src: foo.txt dest: "{{ remote_file }}" mode: 0444 register: copy_result - name: Record the sha of the test file for later tests set_fact: remote_file_hash: "{{ copy_result['checksum'] }}" - name: Check the mode of the output file file: name: "{{ remote_file }}" state: file register: file_result_check - name: Assert the mode is correct assert: that: - "file_result_check.mode == '0444'" # same as expanduser & expandvars - command: 'echo {{ remote_dir }}' register: echo - set_fact: remote_dir_expanded: '{{ echo.stdout }}' remote_file_expanded: '{{ echo.stdout }}/foo.txt' - debug: var: copy_result verbosity: 1 - name: Assert basic copy worked assert: that: - "'changed' in copy_result" - copy_result.dest == remote_file_expanded - "'group' in copy_result" - "'gid' in copy_result" - "'checksum' in copy_result" - "'owner' in copy_result" - "'size' in copy_result" - "'src' in copy_result" - "'state' in copy_result" - "'uid' in copy_result" - name: Verify that the file was marked as changed assert: that: - "copy_result.changed == true" - name: Verify that the file checksums are correct assert: that: - "copy_result.checksum == ('foo.txt\n'|hash('sha1'))" - name: Verify that the legacy md5sum is correct assert: that: - "copy_result.md5sum == ('foo.txt\n'|hash('md5'))" when: ansible_fips|bool != True - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - debug: var: stat_results verbosity: 1 - name: Assert the stat results are correct assert: that: - "stat_results.stat.exists == true" - "stat_results.stat.isblk == false" - "stat_results.stat.isfifo == false" - "stat_results.stat.isreg == true" - "stat_results.stat.issock == false" - "stat_results.stat.checksum == ('foo.txt\n'|hash('sha1'))" - name: Overwrite the file via same means copy: src: foo.txt dest: "{{ remote_file }}" decrypt: no register: copy_result2 - name: Assert that the file was not changed assert: that: - "copy_result2 is not changed" - name: Assert basic copy worked assert: that: - "'changed' in copy_result2" - copy_result2.dest == remote_file_expanded - "'group' in copy_result2" - "'gid' in copy_result2" - "'checksum' in copy_result2" - "'owner' in copy_result2" - "'size' in copy_result2" - "'state' in copy_result2" - "'uid' in copy_result2" - name: Overwrite the file using the content system copy: content: "modified" dest: "{{ remote_file }}" decrypt: no register: copy_result3 - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - debug: var: stat_results verbosity: 1 - name: Assert that the file has changed assert: that: - "copy_result3 is changed" - "'content' not in copy_result3" - "stat_results.stat.checksum == ('modified'|hash('sha1'))" - "stat_results.stat.mode != '0700'" - name: Overwrite the file again using the content system, also passing along file params copy: content: "modified" dest: "{{ remote_file }}" mode: 0700 decrypt: no register: copy_result4 - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - debug: var: stat_results verbosity: 1 - name: Assert that the file has changed assert: that: - "copy_result3 is changed" - "'content' not in copy_result3" - "stat_results.stat.checksum == ('modified'|hash('sha1'))" - "stat_results.stat.mode == '0700'" - name: Create a hardlink to the file file: src: '{{ remote_file }}' dest: '{{ remote_dir }}/hard.lnk' state: hard - name: copy the same contents into place copy: content: 'modified' dest: '{{ remote_file }}' mode: 0700 decrypt: no register: copy_results - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - name: Check the stat results of the hard link stat: path: "{{ remote_dir }}/hard.lnk" register: hlink_results - name: Check that the file did not change assert: that: - 'stat_results.stat.inode == hlink_results.stat.inode' - 'copy_results.changed == False' - "stat_results.stat.checksum == ('modified'|hash('sha1'))" - name: copy the same contents into place but change mode copy: content: 'modified' dest: '{{ remote_file }}' mode: 0404 decrypt: no register: copy_results - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - name: Check the stat results of the hard link stat: path: "{{ remote_dir }}/hard.lnk" register: hlink_results - name: Check that the file changed permissions but is still the same assert: that: - 'stat_results.stat.inode == hlink_results.stat.inode' - 'copy_results.changed == True' - 'stat_results.stat.mode == hlink_results.stat.mode' - 'stat_results.stat.mode == "0404"' - "stat_results.stat.checksum == ('modified'|hash('sha1'))" - name: copy the different contents into place copy: content: 'adjusted' dest: '{{ remote_file }}' mode: 0404 register: copy_results - name: Check the stat results of the file stat: path: "{{ remote_file }}" register: stat_results - name: Check the stat results of the hard link stat: path: "{{ remote_dir }}/hard.lnk" register: hlink_results - name: Check that the file changed and hardlink was broken assert: that: - 'stat_results.stat.inode != hlink_results.stat.inode' - 'copy_results.changed == True' - "stat_results.stat.checksum == ('adjusted'|hash('sha1'))" - "hlink_results.stat.checksum == ('modified'|hash('sha1'))" - name: Try invalid copy input location fails copy: src: invalid_file_location_does_not_exist dest: "{{ remote_dir }}/file.txt" ignore_errors: True register: failed_copy - name: Assert that invalid source failed assert: that: - "failed_copy.failed" - "'invalid_file_location_does_not_exist' in failed_copy.msg" - name: Try empty source to ensure it fails copy: src: '' dest: "{{ remote_dir }}" ignore_errors: True register: failed_copy - debug: var: failed_copy verbosity: 1 - name: Assert that empty source failed assert: that: - failed_copy is failed - "'src (or content) is required' in failed_copy.msg" - name: Try without destination to ensure it fails copy: src: foo.txt ignore_errors: True register: failed_copy - debug: var: failed_copy verbosity: 1 - name: Assert that missing destination failed assert: that: - failed_copy is failed - "'dest is required' in failed_copy.msg" - name: Try without source to ensure it fails copy: dest: "{{ remote_file }}" ignore_errors: True register: failed_copy - debug: var: failed_copy verbosity: 1 - name: Assert that missing source failed assert: that: - failed_copy is failed - "'src (or content) is required' in failed_copy.msg" - name: Try with both src and content to ensure it fails copy: src: foo.txt content: testing dest: "{{ remote_file }}" ignore_errors: True register: failed_copy - name: Assert that mutually exclusive parameters failed assert: that: - failed_copy is failed - "'mutually exclusive' in failed_copy.msg" - name: Try with content and directory as destination to ensure it fails copy: content: testing dest: "{{ remote_dir }}" ignore_errors: True register: failed_copy - debug: var: failed_copy verbosity: 1 - name: Assert that content and directory as destination failed assert: that: - failed_copy is failed - "'can not use content with a dir as dest' in failed_copy.msg" - name: Clean up file: path: "{{ remote_file }}" state: absent - name: Copy source file to destination directory with mode copy: src: foo.txt dest: "{{ remote_dir }}" mode: 0500 register: copy_results - name: Check the stat results of the file stat: path: '{{ remote_file }}' register: stat_results - debug: var: stat_results verbosity: 1 - name: Assert that the file has changed assert: that: - "copy_results is changed" - "stat_results.stat.checksum == ('foo.txt\n'|hash('sha1'))" - "stat_results.stat.mode == '0500'" # Test copy with mode=preserve - name: Create file and set perms to an odd value copy: content: "foo.txt\n" dest: '{{ local_temp_dir }}/foo.txt' mode: 0547 delegate_to: localhost - name: Copy with mode=preserve copy: src: '{{ local_temp_dir }}/foo.txt' dest: '{{ remote_dir }}/copy-foo.txt' mode: preserve register: copy_results - name: Check the stat results of the file stat: path: '{{ remote_dir }}/copy-foo.txt' register: stat_results - name: Assert that the file has changed and has correct mode assert: that: - "copy_results is changed" - "copy_results.mode == '0547'" - "stat_results.stat.checksum == ('foo.txt\n'|hash('sha1'))" - "stat_results.stat.mode == '0547'" - name: Test copy with mode=preserve and remote_src=True copy: src: '{{ remote_dir }}/copy-foo.txt' dest: '{{ remote_dir }}/copy-foo2.txt' mode: 'preserve' remote_src: True register: copy_results2 - name: Check the stat results of the file stat: path: '{{ remote_dir }}/copy-foo2.txt' register: stat_results2 - name: Assert that the file has changed and has correct mode assert: that: - "copy_results2 is changed" - "copy_results2.mode == '0547'" - "stat_results2.stat.checksum == ('foo.txt\n'|hash('sha1'))" - "stat_results2.stat.mode == '0547'" # # test recursive copy local_follow=False, no trailing slash # - name: Create empty directory in the role we're copying from (git can't store empty dirs) file: path: '{{ role_path }}/files/subdir/subdira' state: directory delegate_to: localhost - name: Set the output subdirectory set_fact: remote_subdir: "{{ remote_dir }}/sub" - name: Make an output subdirectory file: name: "{{ remote_subdir }}" state: directory - name: Setup link target for absolute link copy: dest: /tmp/ansible-test-abs-link content: target delegate_to: localhost - name: Setup link target dir for absolute link file: dest: /tmp/ansible-test-abs-link-dir state: directory delegate_to: localhost - name: Test recursive copy to directory no trailing slash, local_follow=False copy: src: subdir dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: False register: recursive_copy_result - debug: var: recursive_copy_result verbosity: 1 - name: Assert that the recursive copy did something assert: that: - "recursive_copy_result is changed" - name: Check that a file in a directory was transferred stat: path: "{{ remote_dir }}/sub/subdir/bar.txt" register: stat_bar - name: Check that a file in a deeper directory was transferred stat: path: "{{ remote_dir }}/sub/subdir/subdir2/baz.txt" register: stat_bar2 - name: Check that a file in a directory whose parent contains a directory alone was transferred stat: path: "{{ remote_dir }}/sub/subdir/subdir2/subdir3/subdir4/qux.txt" register: stat_bar3 - name: Assert recursive copy files assert: that: - "stat_bar.stat.exists" - "stat_bar2.stat.exists" - "stat_bar3.stat.exists" - name: Check symlink to absolute path stat: path: '{{ remote_dir }}/sub/subdir/subdir1/ansible-test-abs-link' register: stat_abs_link - name: Check symlink to relative path stat: path: '{{ remote_dir }}/sub/subdir/subdir1/bar.txt' register: stat_relative_link - name: Check symlink to self stat: path: '{{ remote_dir }}/sub/subdir/subdir1/invalid' register: stat_self_link - name: Check symlink to nonexistent file stat: path: '{{ remote_dir }}/sub/subdir/subdir1/invalid2' register: stat_invalid_link - name: Check symlink to directory in copy stat: path: '{{ remote_dir }}/sub/subdir/subdir1/subdir3' register: stat_dir_in_copy_link - name: Check symlink to directory outside of copy stat: path: '{{ remote_dir }}/sub/subdir/subdir1/ansible-test-abs-link-dir' register: stat_dir_outside_copy_link - name: Assert recursive copy symlinks local_follow=False assert: that: - "stat_abs_link.stat.exists" - "stat_abs_link.stat.islnk" - "'/tmp/ansible-test-abs-link' == stat_abs_link.stat.lnk_target" - "stat_relative_link.stat.exists" - "stat_relative_link.stat.islnk" - "'../bar.txt' == stat_relative_link.stat.lnk_target" - "stat_self_link.stat.exists" - "stat_self_link.stat.islnk" - "'invalid' in stat_self_link.stat.lnk_target" - "stat_invalid_link.stat.exists" - "stat_invalid_link.stat.islnk" - "'../invalid' in stat_invalid_link.stat.lnk_target" - "stat_dir_in_copy_link.stat.exists" - "stat_dir_in_copy_link.stat.islnk" - "'../subdir2/subdir3' in stat_dir_in_copy_link.stat.lnk_target" - "stat_dir_outside_copy_link.stat.exists" - "stat_dir_outside_copy_link.stat.islnk" - "'/tmp/ansible-test-abs-link-dir' == stat_dir_outside_copy_link.stat.lnk_target" - name: Stat the recursively copied directories stat: path: "{{ remote_dir }}/sub/{{ item }}" register: dir_stats with_items: - "subdir" - "subdir/subdira" - "subdir/subdir1" - "subdir/subdir2" - "subdir/subdir2/subdir3" - "subdir/subdir2/subdir3/subdir4" - debug: var: stat_results verbosity: 1 - name: Assert recursive copied directories mode (1) assert: that: - "item.stat.exists" - "item.stat.mode == '0700'" with_items: "{{dir_stats.results}}" - name: Test recursive copy to directory no trailing slash, local_follow=False second time copy: src: subdir dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: False register: recursive_copy_result - name: Assert that the second copy did not change anything assert: that: - "recursive_copy_result is not changed" - name: Cleanup the recursive copy subdir file: name: "{{ remote_subdir }}" state: absent # # Recursive copy with local_follow=False, trailing slash # - name: Set the output subdirectory set_fact: remote_subdir: "{{ remote_dir }}/sub" - name: Make an output subdirectory file: name: "{{ remote_subdir }}" state: directory - name: Setup link target for absolute link copy: dest: /tmp/ansible-test-abs-link content: target delegate_to: localhost - name: Setup link target dir for absolute link file: dest: /tmp/ansible-test-abs-link-dir state: directory delegate_to: localhost - name: Test recursive copy to directory trailing slash, local_follow=False copy: src: subdir/ dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: False register: recursive_copy_result - debug: var: recursive_copy_result verbosity: 1 - name: Assert that the recursive copy did something assert: that: - "recursive_copy_result is changed" - name: Check that a file in a directory was transferred stat: path: "{{ remote_dir }}/sub/bar.txt" register: stat_bar - name: Check that a file in a deeper directory was transferred stat: path: "{{ remote_dir }}/sub/subdir2/baz.txt" register: stat_bar2 - name: Check that a file in a directory whose parent contains a directory alone was transferred stat: path: "{{ remote_dir }}/sub/subdir2/subdir3/subdir4/qux.txt" register: stat_bar3 - name: Assert recursive copy files assert: that: - "stat_bar.stat.exists" - "stat_bar2.stat.exists" - "stat_bar3.stat.exists" - name: Check symlink to absolute path stat: path: '{{ remote_dir }}/sub/subdir1/ansible-test-abs-link' register: stat_abs_link - name: Check symlink to relative path stat: path: '{{ remote_dir }}/sub/subdir1/bar.txt' register: stat_relative_link - name: Check symlink to self stat: path: '{{ remote_dir }}/sub/subdir1/invalid' register: stat_self_link - name: Check symlink to nonexistent file stat: path: '{{ remote_dir }}/sub/subdir1/invalid2' register: stat_invalid_link - name: Check symlink to directory in copy stat: path: '{{ remote_dir }}/sub/subdir1/subdir3' register: stat_dir_in_copy_link - name: Check symlink to directory outside of copy stat: path: '{{ remote_dir }}/sub/subdir1/ansible-test-abs-link-dir' register: stat_dir_outside_copy_link - name: Assert recursive copy symlinks local_follow=False trailing slash assert: that: - "stat_abs_link.stat.exists" - "stat_abs_link.stat.islnk" - "'/tmp/ansible-test-abs-link' == stat_abs_link.stat.lnk_target" - "stat_relative_link.stat.exists" - "stat_relative_link.stat.islnk" - "'../bar.txt' == stat_relative_link.stat.lnk_target" - "stat_self_link.stat.exists" - "stat_self_link.stat.islnk" - "'invalid' in stat_self_link.stat.lnk_target" - "stat_invalid_link.stat.exists" - "stat_invalid_link.stat.islnk" - "'../invalid' in stat_invalid_link.stat.lnk_target" - "stat_dir_in_copy_link.stat.exists" - "stat_dir_in_copy_link.stat.islnk" - "'../subdir2/subdir3' in stat_dir_in_copy_link.stat.lnk_target" - "stat_dir_outside_copy_link.stat.exists" - "stat_dir_outside_copy_link.stat.islnk" - "'/tmp/ansible-test-abs-link-dir' == stat_dir_outside_copy_link.stat.lnk_target" - name: Stat the recursively copied directories stat: path: "{{ remote_dir }}/sub/{{ item }}" register: dir_stats with_items: - "subdira" - "subdir1" - "subdir2" - "subdir2/subdir3" - "subdir2/subdir3/subdir4" - debug: var: dir_stats verbosity: 1 - name: Assert recursive copied directories mode (2) assert: that: - "item.stat.mode == '0700'" with_items: "{{dir_stats.results}}" - name: Test recursive copy to directory trailing slash, local_follow=False second time copy: src: subdir/ dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: False register: recursive_copy_result - name: Assert that the second copy did not change anything assert: that: - "recursive_copy_result is not changed" - name: Cleanup the recursive copy subdir file: name: "{{ remote_subdir }}" state: absent # # test recursive copy local_follow=True, no trailing slash # - name: Set the output subdirectory set_fact: remote_subdir: "{{ remote_dir }}/sub" - name: Make an output subdirectory file: name: "{{ remote_subdir }}" state: directory - name: Setup link target for absolute link copy: dest: /tmp/ansible-test-abs-link content: target delegate_to: localhost - name: Setup link target dir for absolute link file: dest: /tmp/ansible-test-abs-link-dir state: directory delegate_to: localhost - name: Test recursive copy to directory no trailing slash, local_follow=True copy: src: subdir dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: True register: recursive_copy_result - debug: var: recursive_copy_result verbosity: 1 - name: Assert that the recursive copy did something assert: that: - "recursive_copy_result is changed" - name: Check that a file in a directory was transferred stat: path: "{{ remote_dir }}/sub/subdir/bar.txt" register: stat_bar - name: Check that a file in a deeper directory was transferred stat: path: "{{ remote_dir }}/sub/subdir/subdir2/baz.txt" register: stat_bar2 - name: Check that a file in a directory whose parent contains a directory alone was transferred stat: path: "{{ remote_dir }}/sub/subdir/subdir2/subdir3/subdir4/qux.txt" register: stat_bar3 - name: Check that a file in a directory whose parent is a symlink was transferred stat: path: "{{ remote_dir }}/sub/subdir/subdir1/subdir3/subdir4/qux.txt" register: stat_bar4 - name: Assert recursive copy files assert: that: - "stat_bar.stat.exists" - "stat_bar2.stat.exists" - "stat_bar3.stat.exists" - "stat_bar4.stat.exists" - name: Check symlink to absolute path stat: path: '{{ remote_dir }}/sub/subdir/subdir1/ansible-test-abs-link' register: stat_abs_link - name: Check symlink to relative path stat: path: '{{ remote_dir }}/sub/subdir/subdir1/bar.txt' register: stat_relative_link - name: Check symlink to self stat: path: '{{ remote_dir }}/sub/subdir/subdir1/invalid' register: stat_self_link - name: Check symlink to nonexistent file stat: path: '{{ remote_dir }}/sub/subdir/subdir1/invalid2' register: stat_invalid_link - name: Check symlink to directory in copy stat: path: '{{ remote_dir }}/sub/subdir/subdir1/subdir3' register: stat_dir_in_copy_link - name: Check symlink to directory outside of copy stat: path: '{{ remote_dir }}/sub/subdir/subdir1/ansible-test-abs-link-dir' register: stat_dir_outside_copy_link - name: Assert recursive copy symlinks local_follow=True assert: that: - "stat_abs_link.stat.exists" - "not stat_abs_link.stat.islnk" - "stat_abs_link.stat.checksum == ('target'|hash('sha1'))" - "stat_relative_link.stat.exists" - "not stat_relative_link.stat.islnk" - "stat_relative_link.stat.checksum == ('baz\n'|hash('sha1'))" - "stat_self_link.stat.exists" - "stat_self_link.stat.islnk" - "'invalid' in stat_self_link.stat.lnk_target" - "stat_invalid_link.stat.exists" - "stat_invalid_link.stat.islnk" - "'../invalid' in stat_invalid_link.stat.lnk_target" - "stat_dir_in_copy_link.stat.exists" - "not stat_dir_in_copy_link.stat.islnk" - "stat_dir_in_copy_link.stat.isdir" - - "stat_dir_outside_copy_link.stat.exists" - "not stat_dir_outside_copy_link.stat.islnk" - "stat_dir_outside_copy_link.stat.isdir" - name: Stat the recursively copied directories stat: path: "{{ remote_dir }}/sub/{{ item }}" register: dir_stats with_items: - "subdir" - "subdir/subdira" - "subdir/subdir1" - "subdir/subdir1/subdir3" - "subdir/subdir1/subdir3/subdir4" - "subdir/subdir2" - "subdir/subdir2/subdir3" - "subdir/subdir2/subdir3/subdir4" - debug: var: dir_stats verbosity: 1 - name: Assert recursive copied directories mode (3) assert: that: - "item.stat.mode == '0700'" with_items: "{{dir_stats.results}}" - name: Test recursive copy to directory no trailing slash, local_follow=True second time copy: src: subdir dest: "{{ remote_subdir }}" directory_mode: 0700 local_follow: True register: recursive_copy_result - name: Assert that the second copy did not change anything assert: that: - "recursive_copy_result is not changed" - name: Cleanup the recursive copy subdir file: name: "{{ remote_subdir }}" state: absent # # Recursive copy of tricky symlinks # - block: - name: Create a directory to copy from file: path: '{{ local_temp_dir }}/source1' state: directory - name: Create a directory outside of the tree file: path: '{{ local_temp_dir }}/source2' state: directory - name: Create a symlink to a directory outside of the tree file: path: '{{ local_temp_dir }}/source1/link' src: '{{ local_temp_dir }}/source2' state: link - name: Create a circular link back to the tree file: path: '{{ local_temp_dir }}/source2/circle' src: '../source1' state: link - name: Create output directory file: path: '{{ local_temp_dir }}/dest1' state: directory delegate_to: localhost - name: Recursive copy the source copy: src: '{{ local_temp_dir }}/source1' dest: '{{ remote_dir }}/dest1' local_follow: True register: copy_result - name: Check that the tree link is now a directory stat: path: '{{ remote_dir }}/dest1/source1/link' register: link_result - name: Check that the out of tree link is still a link stat: path: '{{ remote_dir }}/dest1/source1/link/circle' register: circle_result - name: Verify that the recursive copy worked assert: that: - 'copy_result.changed' - 'link_result.stat.isdir' - 'not link_result.stat.islnk' - 'circle_result.stat.islnk' - '"../source1" == circle_result.stat.lnk_target' - name: Recursive copy the source a second time copy: src: '{{ local_temp_dir }}/source1' dest: '{{ remote_dir }}/dest1' local_follow: True register: copy_result - name: Verify that the recursive copy made no changes assert: that: - 'not copy_result.changed' # # Recursive copy with absolute paths (#27439) # - name: Test that remote_dir is appropriate for this test (absolute path) assert: that: - '{{ remote_dir_expanded[0] == "/" }}' - block: - name: Create a directory to copy file: path: '{{ local_temp_dir }}/source_recursive' state: directory - name: Create a file inside of the directory copy: content: "testing" dest: '{{ local_temp_dir }}/source_recursive/file' - name: Create a directory to place the test output in file: path: '{{ local_temp_dir }}/destination' state: directory delegate_to: localhost - name: Copy the directory and files within (no trailing slash) copy: src: '{{ local_temp_dir }}/source_recursive' dest: '{{ remote_dir }}/destination' - name: Stat the recursively copied directory stat: path: "{{ remote_dir }}/destination/{{ item }}" register: copied_stat with_items: - "source_recursive" - "source_recursive/file" - "file" - debug: var: copied_stat verbosity: 1 - name: Assert with no trailing slash, directory and file is copied assert: that: - "copied_stat.results[0].stat.exists" - "copied_stat.results[1].stat.exists" - "not copied_stat.results[2].stat.exists" - name: Cleanup file: path: '{{ remote_dir }}/destination' state: absent # Try again with no trailing slash - name: Create a directory to place the test output in file: path: '{{ remote_dir }}/destination' state: directory - name: Copy just the files inside of the directory copy: src: '{{ local_temp_dir }}/source_recursive/' dest: '{{ remote_dir }}/destination' - name: Stat the recursively copied directory stat: path: "{{ remote_dir }}/destination/{{ item }}" register: copied_stat with_items: - "source_recursive" - "source_recursive/file" - "file" - debug: var: copied_stat verbosity: 1 - name: Assert with trailing slash, only the file is copied assert: that: - "not copied_stat.results[0].stat.exists" - "not copied_stat.results[1].stat.exists" - "copied_stat.results[2].stat.exists" # # Recursive copy with relative paths (#34893) # - name: Create a directory to copy file: path: 'source_recursive' state: directory delegate_to: localhost - name: Create a file inside of the directory copy: content: "testing" dest: 'source_recursive/file' delegate_to: localhost - name: Create a directory to place the test output in file: path: 'destination' state: directory delegate_to: localhost - name: Copy the directory and files within (no trailing slash) copy: src: 'source_recursive' dest: 'destination' - name: Stat the recursively copied directory stat: path: "destination/{{ item }}" register: copied_stat with_items: - "source_recursive" - "source_recursive/file" - "file" - debug: var: copied_stat verbosity: 1 - name: Assert with no trailing slash, directory and file is copied assert: that: - "copied_stat.results[0].stat.exists" - "copied_stat.results[1].stat.exists" - "not copied_stat.results[2].stat.exists" - name: Cleanup file: path: 'destination' state: absent # Try again with no trailing slash - name: Create a directory to place the test output in file: path: 'destination' state: directory - name: Copy just the files inside of the directory copy: src: 'source_recursive/' dest: 'destination' - name: Stat the recursively copied directory stat: path: "destination/{{ item }}" register: copied_stat with_items: - "source_recursive" - "source_recursive/file" - "file" - debug: var: copied_stat verbosity: 1 - name: Assert with trailing slash, only the file is copied assert: that: - "not copied_stat.results[0].stat.exists" - "not copied_stat.results[1].stat.exists" - "copied_stat.results[2].stat.exists" - name: Cleanup file: path: 'destination' state: absent - name: Cleanup file: path: 'source_recursive' state: absent # # issue 8394 # - name: Create a file with content and a literal multiline block copy: content: | this is the first line this is the second line this line is after an empty line this line is the last line dest: "{{ remote_dir }}/multiline.txt" register: copy_result6 - debug: var: copy_result6 verbosity: 1 - name: Assert the multiline file was created correctly assert: that: - "copy_result6.changed" - "copy_result6.dest == '{{remote_dir_expanded}}/multiline.txt'" - "copy_result6.checksum == '9cd0697c6a9ff6689f0afb9136fa62e0b3fee903'" # test overwriting a file as an unprivileged user (pull request #8624) # this can't be relative to {{remote_dir}} as ~root usually has mode 700 - block: - name: Create world writable directory file: dest: /tmp/worldwritable state: directory mode: 0777 - name: Create world writable file copy: dest: /tmp/worldwritable/file.txt content: "bar" mode: 0666 - name: Overwrite the file as user nobody copy: dest: /tmp/worldwritable/file.txt content: "baz" become: yes become_user: nobody register: copy_result7 - name: Assert the file was overwritten assert: that: - "copy_result7.changed" - "copy_result7.dest == '/tmp/worldwritable/file.txt'" - "copy_result7.checksum == ('baz'|hash('sha1'))" - name: Clean up file: dest: /tmp/worldwritable state: absent remote_user: root # # Follow=True tests # # test overwriting a link using "follow=yes" so that the link # is preserved and the link target is updated - name: Create a test file to symlink to copy: dest: "{{ remote_dir }}/follow_test" content: "this is the follow test file\n" - name: Create a symlink to the test file file: path: "{{ remote_dir }}/follow_link" src: './follow_test' state: link - name: Update the test file using follow=True to preserve the link copy: dest: "{{ remote_dir }}/follow_link" src: foo.txt follow: yes register: replace_follow_result - name: Stat the link path stat: path: "{{ remote_dir }}/follow_link" register: stat_link_result - name: Assert that the link is still a link and contents were changed assert: that: - stat_link_result['stat']['islnk'] - stat_link_result['stat']['lnk_target'] == './follow_test' - replace_follow_result['changed'] - "replace_follow_result['checksum'] == remote_file_hash" # Symlink handling when the dest is already there # https://github.com/ansible/ansible-modules-core/issues/1568 - name: test idempotency by trying to copy to the symlink with the same contents copy: dest: "{{ remote_dir }}/follow_link" src: foo.txt follow: yes register: replace_follow_result - name: Stat the link path stat: path: "{{ remote_dir }}/follow_link" register: stat_link_result - name: Assert that the link is still a link and contents were changed assert: that: - stat_link_result['stat']['islnk'] - stat_link_result['stat']['lnk_target'] == './follow_test' - not replace_follow_result['changed'] - replace_follow_result['checksum'] == remote_file_hash - name: Update the test file using follow=False to overwrite the link copy: dest: '{{ remote_dir }}/follow_link' content: 'modified' follow: False register: copy_results - name: Check the stat results of the file stat: path: '{{remote_dir}}/follow_link' register: stat_results - debug: var: stat_results verbosity: 1 - name: Assert that the file has changed and is not a link assert: that: - "copy_results is changed" - "'content' not in copy_results" - "stat_results.stat.checksum == ('modified'|hash('sha1'))" - "not stat_results.stat.islnk" # test overwriting a link using "follow=yes" so that the link # is preserved and the link target is updated when the thing being copied is a link # # File mode tests # - name: setup directory for test file: state=directory dest={{remote_dir }}/directory mode=0755 - name: set file mode when the destination is a directory copy: src=foo.txt dest={{remote_dir}}/directory/ mode=0705 - name: set file mode when the destination is a directory copy: src=foo.txt dest={{remote_dir}}/directory/ mode=0604 register: file_result - name: check that the file has the correct attributes stat: path={{ remote_dir }}/directory/foo.txt register: file_attrs - assert: that: - "file_attrs.stat.mode == '0604'" # The below assertions make an invalid assumption, these were not explicitly set # - "file_attrs.stat.uid == 0" # - "file_attrs.stat.pw_name == 'root'" - name: check that the containing directory did not change attributes stat: path={{ remote_dir }}/directory/ register: dir_attrs - assert: that: - "dir_attrs.stat.mode == '0755'" # Test that recursive copy of a directory containing a symlink to another # directory, with mode=preserve and local_follow=no works. # See: https://github.com/ansible/ansible/issues/68471 - name: Test recursive copy of dir with symlinks, mode=preserve, local_follow=False copy: src: '{{ role_path }}/files/subdir/' dest: '{{ local_temp_dir }}/preserve_symlink/' mode: preserve local_follow: no - name: check that we actually used and still have a symlink stat: path={{ local_temp_dir }}/preserve_symlink/subdir1/bar.txt register: symlink_path - assert: that: - symlink_path.stat.exists - symlink_path.stat.islnk # # I believe the below section is now covered in the recursive copying section. # Hold on for now as an original test case but delete once confirmed that # everything is passing # # Recursive copying with symlinks tests # - delegate_to: localhost block: - name: Create a test dir to copy file: path: '{{ local_temp_dir }}/top_dir' state: directory - name: Create a test dir to symlink to file: path: '{{ local_temp_dir }}/linked_dir' state: directory - name: Create a file in the test dir copy: dest: '{{ local_temp_dir }}/linked_dir/file1' content: 'hello world' - name: Create a link to the test dir file: path: '{{ local_temp_dir }}/top_dir/follow_link_dir' src: '{{ local_temp_dir }}/linked_dir' state: link - name: Create a circular subdir file: path: '{{ local_temp_dir }}/top_dir/subdir' state: directory ### FIXME: Also add a test for a relative symlink - name: Create a circular symlink file: path: '{{ local_temp_dir }}/top_dir/subdir/circle' src: '{{ local_temp_dir }}/top_dir/' state: link - name: Copy the directory's link copy: src: '{{ local_temp_dir }}/top_dir' dest: '{{ remote_dir }}/new_dir' local_follow: True - name: Stat the copied path stat: path: '{{ remote_dir }}/new_dir/top_dir/follow_link_dir' register: stat_dir_result - name: Stat the copied file stat: path: '{{ remote_dir }}/new_dir/top_dir/follow_link_dir/file1' register: stat_file_in_dir_result - name: Stat the circular symlink stat: path: '{{ remote_dir }}/new_dir/top_dir/subdir/circle' register: stat_circular_symlink_result - name: Assert that the directory exists assert: that: - stat_dir_result.stat.exists - stat_dir_result.stat.isdir - stat_file_in_dir_result.stat.exists - stat_file_in_dir_result.stat.isreg - stat_circular_symlink_result.stat.exists - stat_circular_symlink_result.stat.islnk # Relative paths in dest: - name: Smoketest that copying content to an implicit relative path works copy: content: 'testing' dest: 'ansible-testing.txt' register: relative_results - name: Assert that copying to an implicit relative path reported changed assert: that: - 'relative_results["changed"]' - 'relative_results["checksum"] == "dc724af18fbdd4e59189f5fe768a5f8311527050"' - name: Test that copying the same content with an implicit relative path reports no change copy: content: 'testing' dest: 'ansible-testing.txt' register: relative_results - name: Assert that copying the same content with an implicit relative path reports no change assert: that: - 'not relative_results["changed"]' - 'relative_results["checksum"] == "dc724af18fbdd4e59189f5fe768a5f8311527050"' - name: Test that copying different content with an implicit relative path reports change copy: content: 'testing2' dest: 'ansible-testing.txt' register: relative_results - name: Assert that copying different content with an implicit relative path reports changed assert: that: - 'relative_results["changed"]' - 'relative_results["checksum"] == "596b29ec9afea9e461a20610d150939b9c399d93"' - name: Smoketest that explicit relative path works copy: content: 'testing' dest: './ansible-testing.txt' register: relative_results - name: Assert that explicit relative paths reports change assert: that: - 'relative_results["changed"]' - 'relative_results["checksum"] == "dc724af18fbdd4e59189f5fe768a5f8311527050"' - name: Cleanup relative path tests file: path: 'ansible-testing.txt' state: absent # src is a file, dest is a non-existent directory (2 levels of directories): # using remote_src # checks that dest is created - include_tasks: file=dest_in_non_existent_directories_remote_src.yml with_items: - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' } # src is a file, dest is file in a non-existent directory: checks that a failure occurs # using remote_src - include_tasks: file=src_file_dest_file_in_non_existent_dir_remote_src.yml with_items: - 'new_sub_dir1/sub_dir2/foo.txt' - 'new_sub_dir1/foo.txt' loop_control: loop_var: 'dest' # src is a file, dest is a non-existent directory (2 levels of directories): # checks that dest is created - include_tasks: file=dest_in_non_existent_directories.yml with_items: - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' } - { src: 'subdir', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/subdir/bar.txt' } - { src: 'subdir/', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/bar.txt' } - { src: 'subdir', dest: 'new_sub_dir1/sub_dir2', check: 'new_sub_dir1/sub_dir2/subdir/bar.txt' } - { src: 'subdir/', dest: 'new_sub_dir1/sub_dir2', check: 'new_sub_dir1/sub_dir2/bar.txt' } # src is a file, dest is file in a non-existent directory: checks that a failure occurs - include_tasks: file=src_file_dest_file_in_non_existent_dir.yml with_items: - 'new_sub_dir1/sub_dir2/foo.txt' - 'new_sub_dir1/foo.txt' loop_control: loop_var: 'dest' # # Recursive copying on remote host # ## prepare for test - block: - name: execute - Create a test src dir file: path: '{{ remote_dir }}/remote_dir_src' state: directory - name: gather - Stat the remote_dir_src stat: path: '{{ remote_dir }}/remote_dir_src' register: stat_remote_dir_src_before - name: execute - Create a subdir file: path: '{{ remote_dir }}/remote_dir_src/subdir' state: directory - name: gather - Stat the remote_dir_src/subdir stat: path: '{{ remote_dir }}/remote_dir_src/subdir' register: stat_remote_dir_src_subdir_before - name: execute - Create a file in the top of src copy: dest: '{{ remote_dir }}/remote_dir_src/file1' content: 'hello world 1' - name: gather - Stat the remote_dir_src/file1 stat: path: '{{ remote_dir }}/remote_dir_src/file1' register: stat_remote_dir_src_file1_before - name: execute - Create a file in the subdir copy: dest: '{{ remote_dir }}/remote_dir_src/subdir/file12' content: 'hello world 12' - name: gather - Stat the remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/remote_dir_src/subdir/file12' register: stat_remote_dir_src_subdir_file12_before - name: execute - Create a link to the file12 file: path: '{{ remote_dir }}/remote_dir_src/link_file12' src: '{{ remote_dir }}/remote_dir_src/subdir/file12' state: link - name: gather - Stat the remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/remote_dir_src/link_file12' register: stat_remote_dir_src_link_file12_before ### test when src endswith os.sep and dest isdir - block: ### local_follow: True - name: execute - Create a test dest dir file: path: '{{ remote_dir }}/testcase1_local_follow_true' state: directory - name: execute - Copy the directory on remote with local_follow True copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase1_local_follow_true' local_follow: True register: testcase1 - name: gather - Stat the testcase1_local_follow_true stat: path: '{{ remote_dir }}/testcase1_local_follow_true' register: stat_testcase1_local_follow_true - name: gather - Stat the testcase1_local_follow_true/subdir stat: path: '{{ remote_dir }}/testcase1_local_follow_true/subdir' register: stat_testcase1_local_follow_true_subdir - name: gather - Stat the testcase1_local_follow_true/file1 stat: path: '{{ remote_dir }}/testcase1_local_follow_true/file1' register: stat_testcase1_local_follow_true_file1 - name: gather - Stat the testcase1_local_follow_true/subdir/file12 stat: path: '{{ remote_dir }}/testcase1_local_follow_true/subdir/file12' register: stat_testcase1_local_follow_true_subdir_file12 - name: gather - Stat the testcase1_local_follow_true/link_file12 stat: path: '{{ remote_dir }}/testcase1_local_follow_true/link_file12' register: stat_testcase1_local_follow_true_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase1 is changed - "stat_testcase1_local_follow_true.stat.isdir" - "stat_testcase1_local_follow_true_subdir.stat.isdir" - "stat_testcase1_local_follow_true_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase1_local_follow_true_file1.stat.checksum" - "stat_testcase1_local_follow_true_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_true_subdir_file12.stat.checksum" - "stat_testcase1_local_follow_true_link_file12.stat.exists" - "not stat_testcase1_local_follow_true_link_file12.stat.islnk" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_true_link_file12.stat.checksum" ### local_follow: False - name: execute - Create a test dest dir file: path: '{{ remote_dir }}/testcase1_local_follow_false' state: directory - name: execute - Copy the directory on remote with local_follow False copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase1_local_follow_false' local_follow: False register: testcase1 - name: gather - Stat the testcase1_local_follow_false stat: path: '{{ remote_dir }}/testcase1_local_follow_false' register: stat_testcase1_local_follow_false - name: gather - Stat the testcase1_local_follow_false/subdir stat: path: '{{ remote_dir }}/testcase1_local_follow_false/subdir' register: stat_testcase1_local_follow_false_subdir - name: gather - Stat the testcase1_local_follow_false/file1 stat: path: '{{ remote_dir }}/testcase1_local_follow_false/file1' register: stat_testcase1_local_follow_false_file1 - name: gather - Stat the testcase1_local_follow_false/subdir/file12 stat: path: '{{ remote_dir }}/testcase1_local_follow_false/subdir/file12' register: stat_testcase1_local_follow_false_subdir_file12 - name: gather - Stat the testcase1_local_follow_false/link_file12 stat: path: '{{ remote_dir }}/testcase1_local_follow_false/link_file12' register: stat_testcase1_local_follow_false_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase1 is changed - "stat_testcase1_local_follow_false.stat.isdir" - "stat_testcase1_local_follow_false_subdir.stat.isdir" - "stat_testcase1_local_follow_false_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase1_local_follow_false_file1.stat.checksum" - "stat_testcase1_local_follow_false_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_false_subdir_file12.stat.checksum" - "stat_testcase1_local_follow_false_link_file12.stat.exists" - "stat_testcase1_local_follow_false_link_file12.stat.islnk" ## test when src endswith os.sep and dest not exists - block: - name: execute - Copy the directory on remote with local_follow True copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase2_local_follow_true' local_follow: True register: testcase2 - name: gather - Stat the testcase2_local_follow_true stat: path: '{{ remote_dir }}/testcase2_local_follow_true' register: stat_testcase2_local_follow_true - name: gather - Stat the testcase2_local_follow_true/subdir stat: path: '{{ remote_dir }}/testcase2_local_follow_true/subdir' register: stat_testcase2_local_follow_true_subdir - name: gather - Stat the testcase2_local_follow_true/file1 stat: path: '{{ remote_dir }}/testcase2_local_follow_true/file1' register: stat_testcase2_local_follow_true_file1 - name: gather - Stat the testcase2_local_follow_true/subdir/file12 stat: path: '{{ remote_dir }}/testcase2_local_follow_true/subdir/file12' register: stat_testcase2_local_follow_true_subdir_file12 - name: gather - Stat the testcase2_local_follow_true/link_file12 stat: path: '{{ remote_dir }}/testcase2_local_follow_true/link_file12' register: stat_testcase2_local_follow_true_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase2 is changed - "stat_testcase2_local_follow_true.stat.isdir" - "stat_testcase2_local_follow_true_subdir.stat.isdir" - "stat_testcase2_local_follow_true_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase2_local_follow_true_file1.stat.checksum" - "stat_testcase2_local_follow_true_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_true_subdir_file12.stat.checksum" - "stat_testcase2_local_follow_true_link_file12.stat.exists" - "not stat_testcase2_local_follow_true_link_file12.stat.islnk" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_true_link_file12.stat.checksum" ### local_follow: False - name: execute - Copy the directory on remote with local_follow False copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase2_local_follow_false' local_follow: False register: testcase2 - name: execute - Copy the directory on remote with local_follow False copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase2_local_follow_false' local_follow: False register: testcase1 - name: gather - Stat the testcase2_local_follow_false stat: path: '{{ remote_dir }}/testcase2_local_follow_false' register: stat_testcase2_local_follow_false - name: gather - Stat the testcase2_local_follow_false/subdir stat: path: '{{ remote_dir }}/testcase2_local_follow_false/subdir' register: stat_testcase2_local_follow_false_subdir - name: gather - Stat the testcase2_local_follow_false/file1 stat: path: '{{ remote_dir }}/testcase2_local_follow_false/file1' register: stat_testcase2_local_follow_false_file1 - name: gather - Stat the testcase2_local_follow_false/subdir/file12 stat: path: '{{ remote_dir }}/testcase2_local_follow_false/subdir/file12' register: stat_testcase2_local_follow_false_subdir_file12 - name: gather - Stat the testcase2_local_follow_false/link_file12 stat: path: '{{ remote_dir }}/testcase2_local_follow_false/link_file12' register: stat_testcase2_local_follow_false_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase2 is changed - "stat_testcase2_local_follow_false.stat.isdir" - "stat_testcase2_local_follow_false_subdir.stat.isdir" - "stat_testcase2_local_follow_false_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase2_local_follow_false_file1.stat.checksum" - "stat_testcase2_local_follow_false_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_false_subdir_file12.stat.checksum" - "stat_testcase2_local_follow_false_link_file12.stat.exists" - "stat_testcase2_local_follow_false_link_file12.stat.islnk" ## test when src not endswith os.sep and dest isdir - block: ### local_follow: True - name: execute - Create a test dest dir file: path: '{{ remote_dir }}/testcase3_local_follow_true' state: directory - name: execute - Copy the directory on remote with local_follow True copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src' dest: '{{ remote_dir }}/testcase3_local_follow_true' local_follow: True register: testcase3 - name: gather - Stat the testcase3_local_follow_true stat: path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src' register: stat_testcase3_local_follow_true_remote_dir_src - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/subdir stat: path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/subdir' register: stat_testcase3_local_follow_true_remote_dir_src_subdir - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/file1 stat: path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/file1' register: stat_testcase3_local_follow_true_remote_dir_src_file1 - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/subdir/file12' register: stat_testcase3_local_follow_true_remote_dir_src_subdir_file12 - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/link_file12' register: stat_testcase3_local_follow_true_remote_dir_src_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase3 is changed - "stat_testcase3_local_follow_true_remote_dir_src.stat.isdir" - "stat_testcase3_local_follow_true_remote_dir_src_subdir.stat.isdir" - "stat_testcase3_local_follow_true_remote_dir_src_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_file1.stat.checksum" - "stat_testcase3_local_follow_true_remote_dir_src_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_subdir_file12.stat.checksum" - "stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.exists" - "not stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.islnk" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.checksum" ### local_follow: False - name: execute - Create a test dest dir file: path: '{{ remote_dir }}/testcase3_local_follow_false' state: directory - name: execute - Copy the directory on remote with local_follow False copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src' dest: '{{ remote_dir }}/testcase3_local_follow_false' local_follow: False register: testcase3 - name: gather - Stat the testcase3_local_follow_false stat: path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src' register: stat_testcase3_local_follow_false_remote_dir_src - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/subdir stat: path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/subdir' register: stat_testcase3_local_follow_false_remote_dir_src_subdir - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/file1 stat: path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/file1' register: stat_testcase3_local_follow_false_remote_dir_src_file1 - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/subdir/file12' register: stat_testcase3_local_follow_false_remote_dir_src_subdir_file12 - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/link_file12' register: stat_testcase3_local_follow_false_remote_dir_src_link_file12 - name: assert - remote_dir_src has copied with local_follow False. assert: that: - testcase3 is changed - "stat_testcase3_local_follow_false_remote_dir_src.stat.isdir" - "stat_testcase3_local_follow_false_remote_dir_src_subdir.stat.isdir" - "stat_testcase3_local_follow_false_remote_dir_src_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase3_local_follow_false_remote_dir_src_file1.stat.checksum" - "stat_testcase3_local_follow_false_remote_dir_src_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_false_remote_dir_src_subdir_file12.stat.checksum" - "stat_testcase3_local_follow_false_remote_dir_src_link_file12.stat.exists" - "stat_testcase3_local_follow_false_remote_dir_src_link_file12.stat.islnk" ## test when src not endswith os.sep and dest not exists - block: ### local_follow: True - name: execute - Copy the directory on remote with local_follow True copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src' dest: '{{ remote_dir }}/testcase4_local_follow_true' local_follow: True register: testcase4 - name: gather - Stat the testcase4_local_follow_true stat: path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src' register: stat_testcase4_local_follow_true_remote_dir_src - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/subdir stat: path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/subdir' register: stat_testcase4_local_follow_true_remote_dir_src_subdir - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/file1 stat: path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/file1' register: stat_testcase4_local_follow_true_remote_dir_src_file1 - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/subdir/file12' register: stat_testcase4_local_follow_true_remote_dir_src_subdir_file12 - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/link_file12' register: stat_testcase4_local_follow_true_remote_dir_src_link_file12 - name: assert - remote_dir_src has copied with local_follow True. assert: that: - testcase4 is changed - "stat_testcase4_local_follow_true_remote_dir_src.stat.isdir" - "stat_testcase4_local_follow_true_remote_dir_src_subdir.stat.isdir" - "stat_testcase4_local_follow_true_remote_dir_src_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_file1.stat.checksum" - "stat_testcase4_local_follow_true_remote_dir_src_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_subdir_file12.stat.checksum" - "stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.exists" - "not stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.islnk" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.checksum" ### local_follow: False - name: execute - Copy the directory on remote with local_follow False copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src' dest: '{{ remote_dir }}/testcase4_local_follow_false' local_follow: False register: testcase4 - name: gather - Stat the testcase4_local_follow_false stat: path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src' register: stat_testcase4_local_follow_false_remote_dir_src - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/subdir stat: path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/subdir' register: stat_testcase4_local_follow_false_remote_dir_src_subdir - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/file1 stat: path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/file1' register: stat_testcase4_local_follow_false_remote_dir_src_file1 - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/subdir/file12' register: stat_testcase4_local_follow_false_remote_dir_src_subdir_file12 - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/link_file12' register: stat_testcase4_local_follow_false_remote_dir_src_link_file12 - name: assert - remote_dir_src has copied with local_follow False. assert: that: - testcase4 is changed - "stat_testcase4_local_follow_false_remote_dir_src.stat.isdir" - "stat_testcase4_local_follow_false_remote_dir_src_subdir.stat.isdir" - "stat_testcase4_local_follow_false_remote_dir_src_file1.stat.exists" - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase4_local_follow_false_remote_dir_src_file1.stat.checksum" - "stat_testcase4_local_follow_false_remote_dir_src_subdir_file12.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_false_remote_dir_src_subdir_file12.stat.checksum" - "stat_testcase4_local_follow_false_remote_dir_src_link_file12.stat.exists" - "stat_testcase4_local_follow_false_remote_dir_src_link_file12.stat.islnk" - block: - name: execute - Clone the source directory on remote copy: remote_src: True src: '{{ remote_dir }}/remote_dir_src/' dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src' - name: Create a 2nd level subdirectory file: path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/' state: directory - name: execute - Copy the directory on remote copy: remote_src: True src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/' dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest' local_follow: True - name: execute - Create a new file in the subdir copy: dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13' content: 'very new file' - name: gather - Stat the testcase5_remote_src_subdirs_src/subdir/subdir2/file13 stat: path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13' - name: execute - Copy the directory on remote copy: remote_src: True src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/' dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/' register: testcase5_new - name: execute - Edit a file in the subdir copy: dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13' content: 'NOT hello world 12' - name: gather - Stat the testcase5_remote_src_subdirs_src/subdir/subdir2/file13 stat: path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13' register: stat_testcase5_remote_src_subdirs_file13_before - name: execute - Copy the directory on remote copy: remote_src: True src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/' dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/' register: testcase5_edited - name: gather - Stat the testcase5_remote_src_subdirs_dest/subdir/subdir2/file13 stat: path: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/subdir/subdir2/file13' register: stat_testcase5_remote_src_subdirs_file13 - name: assert - remote_dir_src has copied with local_follow False. assert: that: - testcase5_new is changed - testcase5_edited is changed - "stat_testcase5_remote_src_subdirs_file13.stat.exists" - "stat_testcase5_remote_src_subdirs_file13_before.stat.checksum == stat_testcase5_remote_src_subdirs_file13.stat.checksum" ## test copying the directory on remote with chown - block: - set_fact: ansible_copy_test_user_name: 'ansible_copy_test_{{ 100000 | random }}' - name: execute - create a user for test user: name: '{{ ansible_copy_test_user_name }}' state: present become: true register: ansible_copy_test_user - name: execute - create a group for test group: name: '{{ ansible_copy_test_user_name }}' state: present become: true register: ansible_copy_test_group - name: execute - Copy the directory on remote with chown copy: remote_src: True src: '{{ remote_dir_expanded }}/remote_dir_src/' dest: '{{ remote_dir_expanded }}/new_dir_with_chown' owner: '{{ ansible_copy_test_user_name }}' group: '{{ ansible_copy_test_user_name }}' follow: true register: testcase5 become: true - name: gather - Stat the new_dir_with_chown stat: path: '{{ remote_dir }}/new_dir_with_chown' register: stat_new_dir_with_chown - name: gather - Stat the new_dir_with_chown/file1 stat: path: '{{ remote_dir }}/new_dir_with_chown/file1' register: stat_new_dir_with_chown_file1 - name: gather - Stat the new_dir_with_chown/subdir stat: path: '{{ remote_dir }}/new_dir_with_chown/subdir' register: stat_new_dir_with_chown_subdir - name: gather - Stat the new_dir_with_chown/subdir/file12 stat: path: '{{ remote_dir }}/new_dir_with_chown/subdir/file12' register: stat_new_dir_with_chown_subdir_file12 - name: gather - Stat the new_dir_with_chown/link_file12 stat: path: '{{ remote_dir }}/new_dir_with_chown/link_file12' register: stat_new_dir_with_chown_link_file12 - name: assert - owner and group have changed assert: that: - testcase5 is changed - "stat_new_dir_with_chown.stat.uid == {{ ansible_copy_test_user.uid }}" - "stat_new_dir_with_chown.stat.gid == {{ ansible_copy_test_group.gid }}" - "stat_new_dir_with_chown.stat.pw_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown.stat.gr_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_file1.stat.uid == {{ ansible_copy_test_user.uid }}" - "stat_new_dir_with_chown_file1.stat.gid == {{ ansible_copy_test_group.gid }}" - "stat_new_dir_with_chown_file1.stat.pw_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_file1.stat.gr_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_subdir.stat.uid == {{ ansible_copy_test_user.uid }}" - "stat_new_dir_with_chown_subdir.stat.gid == {{ ansible_copy_test_group.gid }}" - "stat_new_dir_with_chown_subdir.stat.pw_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_subdir.stat.gr_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_subdir_file12.stat.uid == {{ ansible_copy_test_user.uid }}" - "stat_new_dir_with_chown_subdir_file12.stat.gid == {{ ansible_copy_test_group.gid }}" - "stat_new_dir_with_chown_subdir_file12.stat.pw_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_subdir_file12.stat.gr_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_link_file12.stat.uid == {{ ansible_copy_test_user.uid }}" - "stat_new_dir_with_chown_link_file12.stat.gid == {{ ansible_copy_test_group.gid }}" - "stat_new_dir_with_chown_link_file12.stat.pw_name == '{{ ansible_copy_test_user_name }}'" - "stat_new_dir_with_chown_link_file12.stat.gr_name == '{{ ansible_copy_test_user_name }}'" always: - name: execute - remove the user for test user: name: '{{ ansible_copy_test_user_name }}' state: absent remove: yes become: true - name: execute - remove the group for test group: name: '{{ ansible_copy_test_user_name }}' state: absent become: true ## testcase last - make sure remote_dir_src not change - block: - name: Stat the remote_dir_src stat: path: '{{ remote_dir }}/remote_dir_src' register: stat_remote_dir_src_after - name: Stat the remote_dir_src/subdir stat: path: '{{ remote_dir }}/remote_dir_src/subdir' register: stat_remote_dir_src_subdir_after - name: Stat the remote_dir_src/file1 stat: path: '{{ remote_dir }}/remote_dir_src/file1' register: stat_remote_dir_src_file1_after - name: Stat the remote_dir_src/subdir/file12 stat: path: '{{ remote_dir }}/remote_dir_src/subdir/file12' register: stat_remote_dir_src_subdir_file12_after - name: Stat the remote_dir_src/link_file12 stat: path: '{{ remote_dir }}/remote_dir_src/link_file12' register: stat_remote_dir_src_link_file12_after - name: Assert that remote_dir_src not change. assert: that: - "stat_remote_dir_src_after.stat.exists" - "stat_remote_dir_src_after.stat.isdir" - "stat_remote_dir_src_before.stat.uid == stat_remote_dir_src_after.stat.uid" - "stat_remote_dir_src_before.stat.gid == stat_remote_dir_src_after.stat.gid" - "stat_remote_dir_src_before.stat.pw_name == stat_remote_dir_src_after.stat.pw_name" - "stat_remote_dir_src_before.stat.gr_name == stat_remote_dir_src_after.stat.gr_name" - "stat_remote_dir_src_before.stat.path == stat_remote_dir_src_after.stat.path" - "stat_remote_dir_src_before.stat.mode == stat_remote_dir_src_after.stat.mode" - "stat_remote_dir_src_subdir_after.stat.exists" - "stat_remote_dir_src_subdir_after.stat.isdir" - "stat_remote_dir_src_subdir_before.stat.uid == stat_remote_dir_src_subdir_after.stat.uid" - "stat_remote_dir_src_subdir_before.stat.gid == stat_remote_dir_src_subdir_after.stat.gid" - "stat_remote_dir_src_subdir_before.stat.pw_name == stat_remote_dir_src_subdir_after.stat.pw_name" - "stat_remote_dir_src_subdir_before.stat.gr_name == stat_remote_dir_src_subdir_after.stat.gr_name" - "stat_remote_dir_src_subdir_before.stat.path == stat_remote_dir_src_subdir_after.stat.path" - "stat_remote_dir_src_subdir_before.stat.mode == stat_remote_dir_src_subdir_after.stat.mode" - "stat_remote_dir_src_file1_after.stat.exists" - "stat_remote_dir_src_file1_before.stat.uid == stat_remote_dir_src_file1_after.stat.uid" - "stat_remote_dir_src_file1_before.stat.gid == stat_remote_dir_src_file1_after.stat.gid" - "stat_remote_dir_src_file1_before.stat.pw_name == stat_remote_dir_src_file1_after.stat.pw_name" - "stat_remote_dir_src_file1_before.stat.gr_name == stat_remote_dir_src_file1_after.stat.gr_name" - "stat_remote_dir_src_file1_before.stat.path == stat_remote_dir_src_file1_after.stat.path" - "stat_remote_dir_src_file1_before.stat.mode == stat_remote_dir_src_file1_after.stat.mode" - "stat_remote_dir_src_file1_before.stat.checksum == stat_remote_dir_src_file1_after.stat.checksum" - "stat_remote_dir_src_subdir_file12_after.stat.exists" - "stat_remote_dir_src_subdir_file12_before.stat.uid == stat_remote_dir_src_subdir_file12_after.stat.uid" - "stat_remote_dir_src_subdir_file12_before.stat.gid == stat_remote_dir_src_subdir_file12_after.stat.gid" - "stat_remote_dir_src_subdir_file12_before.stat.pw_name == stat_remote_dir_src_subdir_file12_after.stat.pw_name" - "stat_remote_dir_src_subdir_file12_before.stat.gr_name == stat_remote_dir_src_subdir_file12_after.stat.gr_name" - "stat_remote_dir_src_subdir_file12_before.stat.path == stat_remote_dir_src_subdir_file12_after.stat.path" - "stat_remote_dir_src_subdir_file12_before.stat.mode == stat_remote_dir_src_subdir_file12_after.stat.mode" - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_remote_dir_src_subdir_file12_after.stat.checksum" - "stat_remote_dir_src_link_file12_after.stat.exists" - "stat_remote_dir_src_link_file12_after.stat.islnk" - "stat_remote_dir_src_link_file12_before.stat.uid == stat_remote_dir_src_link_file12_after.stat.uid" - "stat_remote_dir_src_link_file12_before.stat.gid == stat_remote_dir_src_link_file12_after.stat.gid" - "stat_remote_dir_src_link_file12_before.stat.pw_name == stat_remote_dir_src_link_file12_after.stat.pw_name" - "stat_remote_dir_src_link_file12_before.stat.gr_name == stat_remote_dir_src_link_file12_after.stat.gr_name" - "stat_remote_dir_src_link_file12_before.stat.path == stat_remote_dir_src_link_file12_after.stat.path" - "stat_remote_dir_src_link_file12_before.stat.mode == stat_remote_dir_src_link_file12_after.stat.mode" # Test for issue 69783: copy with remote_src=yes and src='dir/' preserves all permissions - block: - name: Create directory structure file: path: "{{ local_temp_dir }}/test69783/{{ item }}" state: directory loop: - "src/dir" - "dest" - name: Create source file structure file: path: "{{ local_temp_dir }}/test69783/src/{{ item.name }}" state: touch mode: "{{ item.mode }}" loop: - { name: 'readwrite', mode: '0644' } - { name: 'executable', mode: '0755' } - { name: 'readonly', mode: '0444' } - { name: 'dir/readwrite', mode: '0644' } - { name: 'dir/executable', mode: '0755' } - { name: 'dir/readonly', mode: '0444' } - name: Recursive remote copy with preserve copy: src: "{{ local_temp_dir }}/test69783/src/" dest: "{{ local_temp_dir }}/test69783/dest/" remote_src: yes mode: preserve - name: Stat dest 'readwrite' file stat: path: "{{ local_temp_dir}}/test69783/dest/readwrite" register: dest_readwrite_stat - name: Stat dest 'executable' file stat: path: "{{ local_temp_dir}}/test69783/dest/executable" register: dest_executable_stat - name: Stat dest 'readonly' file stat: path: "{{ local_temp_dir}}/test69783/dest/readonly" register: dest_readonly_stat - name: Stat dest 'dir/readwrite' file stat: path: "{{ local_temp_dir}}/test69783/dest/dir/readwrite" register: dest_dir_readwrite_stat - name: Stat dest 'dir/executable' file stat: path: "{{ local_temp_dir}}/test69783/dest/dir/executable" register: dest_dir_executable_stat - name: Stat dest 'dir/readonly' file stat: path: "{{ local_temp_dir}}/test69783/dest/dir/readonly" register: dest_dir_readonly_stat - name: Assert modes are preserved assert: that: - "dest_readwrite_stat.stat.mode == '0644'" - "dest_executable_stat.stat.mode == '0755'" - "dest_readonly_stat.stat.mode == '0444'" - "dest_dir_readwrite_stat.stat.mode == '0644'" - "dest_dir_executable_stat.stat.mode == '0755'" - "dest_dir_readonly_stat.stat.mode == '0444'" - name: fail to copy an encrypted file without the password set copy: src: '{{role_path}}/files-different/vault/vault-file' dest: '{{output_dir}}/file' register: fail_copy_encrypted_file ignore_errors: yes # weird failed_when doesn't work in this case - name: assert failure message when copying an encrypted file without the password set assert: that: - fail_copy_encrypted_file is failed - fail_copy_encrypted_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-different/vault/vault-file' - name: fail to copy a directory with an encrypted file without the password copy: src: '{{role_path}}/files-different/vault' dest: '{{output_dir}}' register: fail_copy_directory_with_enc_file ignore_errors: yes - name: assert failure message when copying a directory that contains an encrypted file without the password set assert: that: - fail_copy_directory_with_enc_file is failed - fail_copy_directory_with_enc_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-different/vault/vault-file'