mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
a8e4c9be7a
* Fail if an empty string is set as src for copy module Fixes #27363 * Cleanup task formatting on copy tests Use multi-line YAML Add debug statements with verbosity: 1 rather than leave them in there commented out. * Add test for empty string as source * Do more checks in order to add more specific errors messages Add more integration tests for the various failure scenarios. Cleanup some syntax on existing integration test tasks.
1166 lines
30 KiB
YAML
1166 lines
30 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: Locate sha1sum/shasum
|
||
shell: which sha1sum || which shasum
|
||
register: sha1sum
|
||
|
||
- name: Initiate a basic copy, and also test the mode
|
||
copy:
|
||
src: foo.txt
|
||
dest: "{{ remote_file }}"
|
||
mode: 0444
|
||
register: copy_result
|
||
|
||
- 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 }}'
|
||
|
||
- debug:
|
||
var: copy_result
|
||
verbosity: 1
|
||
|
||
- name: Assert basic copy worked
|
||
assert:
|
||
that:
|
||
- "'changed' in copy_result"
|
||
- "'dest' in copy_result"
|
||
- "'group' in copy_result"
|
||
- "'gid' in copy_result"
|
||
- "'md5sum' 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: Verify that the legacy md5sum is correct
|
||
assert:
|
||
that:
|
||
- "stat_results.stat.md5 == ('foo.txt\n'|hash('md5'))"
|
||
when: ansible_fips|bool != True
|
||
|
||
- name: Overwrite the file via same means
|
||
copy:
|
||
src: foo.txt
|
||
dest: "{{ remote_file }}"
|
||
register: copy_result2
|
||
|
||
- name: Assert that the file was not changed
|
||
assert:
|
||
that:
|
||
- "not copy_result2|changed"
|
||
|
||
- name: Overwrite the file using the content system
|
||
copy:
|
||
content: "modified"
|
||
dest: "{{ remote_file }}"
|
||
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|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
|
||
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|changed"
|
||
- "'content' not in copy_result3"
|
||
- "stat_results.stat.checksum == ('modified'|hash('sha1'))"
|
||
- "stat_results.stat.mode == '0700'"
|
||
|
||
- 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 | 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 | 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 | 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 | 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 | 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|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
|
||
connection: local
|
||
|
||
- 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|changed"
|
||
- "copy_results.mode == '0547'"
|
||
- "stat_results.stat.checksum == ('foo.txt\n'|hash('sha1'))"
|
||
- "stat_results.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
|
||
connection: local
|
||
|
||
- 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
|
||
connection: local
|
||
|
||
- name: Setup link target dir for absolute link
|
||
file:
|
||
dest: /tmp/ansible-test-abs-link-dir
|
||
state: directory
|
||
connection: local
|
||
|
||
- 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|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:
|
||
- "not recursive_copy_result|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
|
||
connection: local
|
||
|
||
- name: Setup link target dir for absolute link
|
||
file:
|
||
dest: /tmp/ansible-test-abs-link-dir
|
||
state: directory
|
||
connection: local
|
||
|
||
- 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|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:
|
||
- "not recursive_copy_result|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
|
||
connection: local
|
||
|
||
- name: Setup link target dir for absolute link
|
||
file:
|
||
dest: /tmp/ansible-test-abs-link-dir
|
||
state: directory
|
||
connection: local
|
||
|
||
- 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|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:
|
||
- "not recursive_copy_result|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
|
||
connection: local
|
||
|
||
- 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
|
||
connection: local
|
||
|
||
- 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"
|
||
|
||
#
|
||
# 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
|
||
|
||
# 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"
|
||
content: "this is the new content\n"
|
||
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
|
||
assert:
|
||
that:
|
||
- stat_link_result.stat.islnk
|
||
|
||
- name: Get the checksum of the link target
|
||
shell: "{{ sha1sum.stdout }} {{remote_dir}}/follow_test | cut -f1 -sd ' '"
|
||
register: target_file_result
|
||
|
||
- name: Assert that the link target was updated
|
||
assert:
|
||
that:
|
||
- replace_follow_result.checksum == target_file_result.stdout
|
||
|
||
- 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|changed"
|
||
- "'content' not in copy_results"
|
||
- "stat_results.stat.checksum == ('modified'|hash('sha1'))"
|
||
- "not stat_results.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
|
||
#
|
||
- 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
|
||
|
||
connection: local
|
||
|
||
- 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
|
||
|
||
# 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'
|