0ae4dac65a
When using 'remote_src: yes' and 'mode: preserve', the code handling the file modes has to be handled on the remote node because it's the one that has access to the source files. This means that the copy module itself must handle this, rather than the copy action plugin (which is where all that logic exists). The copy module handles this when we copy a single file over. But when it is a directory as the src parameter value, the mode of the files beneath it are not considered. Subdirectories are copied with shutil.copytree() which will preserve permissions automatically. Individual files are copied with shutil.copyfile() which does NOT preserve permissions. We need to add some calls to shutil.copymode() to correct that. Note: This *always* retains individial file permissions. Specifying a 'mode' other than 'preserve' when giving a source directory for the 'src' param does not make sense so will be ignored in that case only. Fixes #69783 * Add changelog and test
2261 lines
73 KiB
YAML
2261 lines
73 KiB
YAML
# test code for the copy module and action plugin
|
||
# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||
# (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: 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: 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: 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: 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'"
|