summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/copy
diff options
context:
space:
mode:
Diffstat (limited to 'test/integration/targets/copy')
-rw-r--r--test/integration/targets/copy/aliases3
-rw-r--r--test/integration/targets/copy/defaults/main.yml2
-rw-r--r--test/integration/targets/copy/files-different/vault/folder/nested-vault-file6
-rw-r--r--test/integration/targets/copy/files-different/vault/readme.txt5
-rw-r--r--test/integration/targets/copy/files-different/vault/vault-file6
-rw-r--r--test/integration/targets/copy/files/foo.txt1
-rw-r--r--test/integration/targets/copy/files/subdir/bar.txt1
-rw-r--r--test/integration/targets/copy/files/subdir/subdir1/empty.txt0
-rw-r--r--test/integration/targets/copy/files/subdir/subdir2/baz.txt1
-rw-r--r--test/integration/targets/copy/files/subdir/subdir2/subdir3/subdir4/qux.txt1
-rw-r--r--test/integration/targets/copy/meta/main.yml4
-rw-r--r--test/integration/targets/copy/tasks/acls.yml38
-rw-r--r--test/integration/targets/copy/tasks/check_mode.yml126
-rw-r--r--test/integration/targets/copy/tasks/dest_in_non_existent_directories.yml29
-rw-r--r--test/integration/targets/copy/tasks/dest_in_non_existent_directories_remote_src.yml43
-rw-r--r--test/integration/targets/copy/tasks/main.yml126
-rw-r--r--test/integration/targets/copy/tasks/no_log.yml82
-rw-r--r--test/integration/targets/copy/tasks/selinux.yml36
-rw-r--r--test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir.yml26
-rw-r--r--test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir_remote_src.yml32
-rw-r--r--test/integration/targets/copy/tasks/src_remote_file_is_not_file.yml39
-rw-r--r--test/integration/targets/copy/tasks/tests.yml2286
22 files changed, 2893 insertions, 0 deletions
diff --git a/test/integration/targets/copy/aliases b/test/integration/targets/copy/aliases
new file mode 100644
index 0000000..961b205
--- /dev/null
+++ b/test/integration/targets/copy/aliases
@@ -0,0 +1,3 @@
+needs/root
+shippable/posix/group2
+destructive
diff --git a/test/integration/targets/copy/defaults/main.yml b/test/integration/targets/copy/defaults/main.yml
new file mode 100644
index 0000000..8e9a583
--- /dev/null
+++ b/test/integration/targets/copy/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+remote_unprivileged_user: tmp_ansible_test_user
diff --git a/test/integration/targets/copy/files-different/vault/folder/nested-vault-file b/test/integration/targets/copy/files-different/vault/folder/nested-vault-file
new file mode 100644
index 0000000..d8d1549
--- /dev/null
+++ b/test/integration/targets/copy/files-different/vault/folder/nested-vault-file
@@ -0,0 +1,6 @@
+$ANSIBLE_VAULT;1.1;AES256
+65653164323866373138353632323531393664393563633665373635623763353561386431373366
+3232353263363034313136663062623336663463373966320a333763323032646463386432626161
+36386330356637666362396661653935653064623038333031653335626164376465353235303636
+3335616231663838620a303632343938326538656233393562303162343261383465623261646664
+33613932343461626339333832363930303962633364303736376634396364643861
diff --git a/test/integration/targets/copy/files-different/vault/readme.txt b/test/integration/targets/copy/files-different/vault/readme.txt
new file mode 100644
index 0000000..0a30d8e
--- /dev/null
+++ b/test/integration/targets/copy/files-different/vault/readme.txt
@@ -0,0 +1,5 @@
+This directory contains some files that have been encrypted with ansible-vault.
+
+This is to test out the decrypt parameter in copy.
+
+The password is: password
diff --git a/test/integration/targets/copy/files-different/vault/vault-file b/test/integration/targets/copy/files-different/vault/vault-file
new file mode 100644
index 0000000..2fff761
--- /dev/null
+++ b/test/integration/targets/copy/files-different/vault/vault-file
@@ -0,0 +1,6 @@
+$ANSIBLE_VAULT;1.1;AES256
+30353665333635633433356261616636356130386330363962386533303566313463383734373532
+3933643234323638623939613462346361313431363939370a303532656338353035346661353965
+34656231633238396361393131623834316262306533663838336362366137306562646561383766
+6363373965633337640a373666336461613337346131353564383134326139616561393664663563
+3431
diff --git a/test/integration/targets/copy/files/foo.txt b/test/integration/targets/copy/files/foo.txt
new file mode 100644
index 0000000..7c6ded1
--- /dev/null
+++ b/test/integration/targets/copy/files/foo.txt
@@ -0,0 +1 @@
+foo.txt
diff --git a/test/integration/targets/copy/files/subdir/bar.txt b/test/integration/targets/copy/files/subdir/bar.txt
new file mode 100644
index 0000000..7601807
--- /dev/null
+++ b/test/integration/targets/copy/files/subdir/bar.txt
@@ -0,0 +1 @@
+baz
diff --git a/test/integration/targets/copy/files/subdir/subdir1/empty.txt b/test/integration/targets/copy/files/subdir/subdir1/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/integration/targets/copy/files/subdir/subdir1/empty.txt
diff --git a/test/integration/targets/copy/files/subdir/subdir2/baz.txt b/test/integration/targets/copy/files/subdir/subdir2/baz.txt
new file mode 100644
index 0000000..7601807
--- /dev/null
+++ b/test/integration/targets/copy/files/subdir/subdir2/baz.txt
@@ -0,0 +1 @@
+baz
diff --git a/test/integration/targets/copy/files/subdir/subdir2/subdir3/subdir4/qux.txt b/test/integration/targets/copy/files/subdir/subdir2/subdir3/subdir4/qux.txt
new file mode 100644
index 0000000..78df5b0
--- /dev/null
+++ b/test/integration/targets/copy/files/subdir/subdir2/subdir3/subdir4/qux.txt
@@ -0,0 +1 @@
+qux \ No newline at end of file
diff --git a/test/integration/targets/copy/meta/main.yml b/test/integration/targets/copy/meta/main.yml
new file mode 100644
index 0000000..e655a4f
--- /dev/null
+++ b/test/integration/targets/copy/meta/main.yml
@@ -0,0 +1,4 @@
+dependencies:
+ - prepare_tests
+ - setup_nobody
+ - setup_remote_tmp_dir
diff --git a/test/integration/targets/copy/tasks/acls.yml b/test/integration/targets/copy/tasks/acls.yml
new file mode 100644
index 0000000..d7d099e
--- /dev/null
+++ b/test/integration/targets/copy/tasks/acls.yml
@@ -0,0 +1,38 @@
+- block:
+ - name: Install the acl package on Ubuntu
+ apt:
+ name: acl
+ when: ansible_distribution in ('Ubuntu')
+
+ - block:
+ - name: Testing ACLs
+ copy:
+ content: "TEST"
+ mode: 0644
+ dest: "~/test.txt"
+
+ - shell: getfacl ~/test.txt
+ register: acls
+
+ become: yes
+ become_user: "{{ remote_unprivileged_user }}"
+
+ - name: Check that there are no ACLs leftovers
+ assert:
+ that:
+ - "'user:{{ remote_unprivileged_user }}:r-x\t#effective:r--' not in acls.stdout_lines"
+
+ - name: Check that permissions match with what was set in the mode param
+ assert:
+ that:
+ - "'user::rw-' in acls.stdout_lines"
+ - "'group::r--' in acls.stdout_lines"
+ - "'other::r--' in acls.stdout_lines"
+
+ always:
+ - name: Clean up
+ file:
+ path: "~/test.txt"
+ state: absent
+ become: yes
+ become_user: "{{ remote_unprivileged_user }}"
diff --git a/test/integration/targets/copy/tasks/check_mode.yml b/test/integration/targets/copy/tasks/check_mode.yml
new file mode 100644
index 0000000..5b405cc
--- /dev/null
+++ b/test/integration/targets/copy/tasks/check_mode.yml
@@ -0,0 +1,126 @@
+- block:
+
+ - name: check_mode - Create another clean copy of 'subdir' not messed with by previous tests (check_mode)
+ copy:
+ src: subdir
+ dest: 'checkmode_subdir/'
+ directory_mode: 0700
+ local_follow: False
+ check_mode: true
+ register: check_mode_subdir_first
+
+ - name: check_mode - Stat the new dir to make sure it really doesn't exist
+ stat:
+ path: 'checkmode_subdir/'
+ register: check_mode_subdir_first_stat
+
+ - name: check_mode - Actually do it
+ copy:
+ src: subdir
+ dest: 'checkmode_subdir/'
+ directory_mode: 0700
+ local_follow: False
+ register: check_mode_subdir_real
+
+ - name: check_mode - Stat the new dir to make sure it really exists
+ stat:
+ path: 'checkmode_subdir/'
+ register: check_mode_subdir_real_stat
+
+ # Quick sanity before we move on
+ - assert:
+ that:
+ - check_mode_subdir_first is changed
+ - not check_mode_subdir_first_stat.stat.exists
+ - check_mode_subdir_real is changed
+ - check_mode_subdir_real_stat.stat.exists
+
+ # Do some finagling here. First, use check_mode to ensure it never gets
+ # created. Then actualy create it, and use check_mode to ensure that doing
+ # the same copy gets marked as no change.
+ #
+ # This same pattern repeats for several other src/dest combinations.
+ - name: check_mode - Ensure dest with trailing / never gets created but would be without check_mode
+ copy:
+ remote_src: true
+ src: 'checkmode_subdir/'
+ dest: 'destdir_should_never_exist_because_of_check_mode/'
+ follow: true
+ check_mode: true
+ register: check_mode_trailing_slash_first
+
+ - name: check_mode - Stat the new dir to make sure it really doesn't exist
+ stat:
+ path: 'destdir_should_never_exist_because_of_check_mode/'
+ register: check_mode_trailing_slash_first_stat
+
+ - name: check_mode - Create the above copy for real now (without check_mode)
+ copy:
+ remote_src: true
+ src: 'checkmode_subdir/'
+ dest: 'destdir_should_never_exist_because_of_check_mode/'
+ register: check_mode_trailing_slash_real
+
+ - name: check_mode - Stat the new dir to make sure it really exists
+ stat:
+ path: 'destdir_should_never_exist_because_of_check_mode/'
+ register: check_mode_trailing_slash_real_stat
+
+ - name: check_mode - Do the same copy yet again (with check_mode this time) to ensure it's marked unchanged
+ copy:
+ remote_src: true
+ src: 'checkmode_subdir/'
+ dest: 'destdir_should_never_exist_because_of_check_mode/'
+ check_mode: true
+ register: check_mode_trailing_slash_second
+
+ # Repeat the same basic pattern here.
+
+ - name: check_mode - Do another basic copy (with check_mode)
+ copy:
+ src: foo.txt
+ dest: "{{ remote_dir }}/foo-check_mode.txt"
+ mode: 0444
+ check_mode: true
+ register: check_mode_foo_first
+
+ - name: check_mode - Stat the new file to make sure it really doesn't exist
+ stat:
+ path: "{{ remote_dir }}/foo-check_mode.txt"
+ register: check_mode_foo_first_stat
+
+ - name: check_mode - Do the same basic copy (without check_mode)
+ copy:
+ src: foo.txt
+ dest: "{{ remote_dir }}/foo-check_mode.txt"
+ mode: 0444
+ register: check_mode_foo_real
+
+ - name: check_mode - Stat the new file to make sure it really exists
+ stat:
+ path: "{{ remote_dir }}/foo-check_mode.txt"
+ register: check_mode_foo_real_stat
+
+ - name: check_mode - And again (with check_mode)
+ copy:
+ src: foo.txt
+ dest: "{{ remote_dir }}/foo-check_mode.txt"
+ mode: 0444
+ register: check_mode_foo_second
+
+ - assert:
+ that:
+ - check_mode_subdir_first is changed
+
+ - check_mode_trailing_slash_first is changed
+ # TODO: This is a legitimate bug
+ #- not check_mode_trailing_slash_first_stat.stat.exists
+ - check_mode_trailing_slash_real is changed
+ - check_mode_trailing_slash_real_stat.stat.exists
+ - check_mode_trailing_slash_second is not changed
+
+ - check_mode_foo_first is changed
+ - not check_mode_foo_first_stat.stat.exists
+ - check_mode_foo_real is changed
+ - check_mode_foo_real_stat.stat.exists
+ - check_mode_foo_second is not changed
diff --git a/test/integration/targets/copy/tasks/dest_in_non_existent_directories.yml b/test/integration/targets/copy/tasks/dest_in_non_existent_directories.yml
new file mode 100644
index 0000000..c86caa1
--- /dev/null
+++ b/test/integration/targets/copy/tasks/dest_in_non_existent_directories.yml
@@ -0,0 +1,29 @@
+# src is a file, dest is a non-existent directory (2 levels of directories):
+# checks that dest is created
+- name: Ensure that dest top directory doesn't exist
+ file:
+ path: '{{ remote_dir }}/{{ item.dest.split("/")[0] }}'
+ state: absent
+
+- name: Copy file, dest is a nonexistent target directory
+ copy:
+ src: '{{ item.src }}'
+ dest: '{{ remote_dir }}/{{ item.dest }}'
+ register: copy_result
+
+- name: assert copy worked
+ assert:
+ that:
+ - 'copy_result is successful'
+ - 'copy_result is changed'
+
+- name: stat copied file
+ stat:
+ path: '{{ remote_dir }}/{{ item.check }}'
+ register: stat_file_in_dir_result
+
+- name: assert that file exists
+ assert:
+ that:
+ - stat_file_in_dir_result.stat.exists
+ - stat_file_in_dir_result.stat.isreg
diff --git a/test/integration/targets/copy/tasks/dest_in_non_existent_directories_remote_src.yml b/test/integration/targets/copy/tasks/dest_in_non_existent_directories_remote_src.yml
new file mode 100644
index 0000000..fad53e7
--- /dev/null
+++ b/test/integration/targets/copy/tasks/dest_in_non_existent_directories_remote_src.yml
@@ -0,0 +1,43 @@
+# src is a file, dest is a non-existent directory (2 levels of directories):
+# checks that dest is created
+- name: Ensure that dest top directory doesn't exist
+ file:
+ path: '{{ remote_dir }}/{{ item.dest.split("/")[0] }}'
+ state: absent
+
+- name: create subdir
+ file:
+ path: subdir
+ state: directory
+
+- name: create src file
+ file:
+ path: "{{ item }}"
+ state: touch
+ loop:
+ - foo.txt
+ - subdir/bar.txt
+
+- name: Copy file, dest is a nonexistent target directory
+ copy:
+ src: '{{ item.src }}'
+ dest: '{{ remote_dir }}/{{ item.dest }}'
+ remote_src: true
+ register: copy_result
+
+- name: assert copy worked
+ assert:
+ that:
+ - 'copy_result is successful'
+ - 'copy_result is changed'
+
+- name: stat copied file
+ stat:
+ path: '{{ remote_dir }}/{{ item.check }}'
+ register: stat_file_in_dir_result
+
+- name: assert that file exists
+ assert:
+ that:
+ - stat_file_in_dir_result.stat.exists
+ - stat_file_in_dir_result.stat.isreg
diff --git a/test/integration/targets/copy/tasks/main.yml b/test/integration/targets/copy/tasks/main.yml
new file mode 100644
index 0000000..b86c56a
--- /dev/null
+++ b/test/integration/targets/copy/tasks/main.yml
@@ -0,0 +1,126 @@
+- block:
+
+ - name: Create a local temporary directory
+ shell: mktemp -d /tmp/ansible_test.XXXXXXXXX
+ register: tempfile_result
+ delegate_to: localhost
+
+ - set_fact:
+ local_temp_dir: '{{ tempfile_result.stdout }}'
+ remote_dir: '{{ remote_tmp_dir }}/copy'
+ symlinks:
+ ansible-test-abs-link: /tmp/ansible-test-abs-link
+ ansible-test-abs-link-dir: /tmp/ansible-test-abs-link-dir
+ circles: ../
+ invalid: invalid
+ invalid2: ../invalid
+ out_of_tree_circle: /tmp/ansible-test-link-dir/out_of_tree_circle
+ subdir3: ../subdir2/subdir3
+ bar.txt: ../bar.txt
+
+ - file: path={{local_temp_dir}} state=directory
+ name: ensure temp dir exists
+
+ # file cannot do this properly, use command instead
+ - name: Create symbolic link
+ command: "ln -s '{{ item.value }}' '{{ item.key }}'"
+ args:
+ chdir: '{{role_path}}/files/subdir/subdir1'
+ with_dict: "{{ symlinks }}"
+ delegate_to: localhost
+
+ - name: Create remote unprivileged remote user
+ user:
+ name: '{{ remote_unprivileged_user }}'
+ register: user
+
+ - name: Check sudoers dir
+ stat:
+ path: /etc/sudoers.d
+ register: etc_sudoers
+
+ - name: Set sudoers.d path fact
+ set_fact:
+ sudoers_d_file: "{{ '/etc/sudoers.d' if etc_sudoers.stat.exists else '/usr/local/etc/sudoers.d' }}/{{ remote_unprivileged_user }}"
+
+ - name: Create sudoers file
+ copy:
+ dest: "{{ sudoers_d_file }}"
+ content: "{{ remote_unprivileged_user }} ALL=(ALL) NOPASSWD: ALL"
+
+ - file:
+ path: "{{ user.home }}/.ssh"
+ owner: '{{ remote_unprivileged_user }}'
+ state: directory
+ mode: 0700
+
+ - name: Duplicate authorized_keys
+ copy:
+ src: $HOME/.ssh/authorized_keys
+ dest: '{{ user.home }}/.ssh/authorized_keys'
+ owner: '{{ remote_unprivileged_user }}'
+ mode: 0600
+ remote_src: yes
+
+ - file:
+ path: "{{ remote_dir }}"
+ state: directory
+ remote_user: '{{ remote_unprivileged_user }}'
+
+ # execute tests tasks using an unprivileged user, this is useful to avoid
+ # local/remote ambiguity when controller and managed hosts are identical.
+ - import_tasks: tests.yml
+ remote_user: '{{ remote_unprivileged_user }}'
+
+ - import_tasks: acls.yml
+ when: ansible_system == 'Linux'
+
+ - import_tasks: selinux.yml
+ when: ansible_os_family == 'RedHat' and ansible_selinux.get('mode') == 'enforcing'
+
+ - import_tasks: no_log.yml
+ delegate_to: localhost
+
+ - import_tasks: check_mode.yml
+
+ # https://github.com/ansible/ansible/issues/57618
+ - name: Test diff contents
+ copy:
+ content: 'Ansible managed\n'
+ dest: "{{ local_temp_dir }}/file.txt"
+ diff: yes
+ register: diff_output
+
+ - assert:
+ that:
+ - 'diff_output.diff[0].before == ""'
+ - '"Ansible managed" in diff_output.diff[0].after'
+
+ - name: tests with remote_src and non files
+ import_tasks: src_remote_file_is_not_file.yml
+
+ always:
+ - name: Cleaning
+ file:
+ path: '{{ local_temp_dir }}'
+ state: absent
+ delegate_to: localhost
+
+ - name: Remove symbolic link
+ file:
+ path: '{{ role_path }}/files/subdir/subdir1/{{ item.key }}'
+ state: absent
+ delegate_to: localhost
+ with_dict: "{{ symlinks }}"
+
+ - name: Remote unprivileged remote user
+ user:
+ name: '{{ remote_unprivileged_user }}'
+ state: absent
+ remove: yes
+ force: yes
+
+ - name: Remove sudoers.d file
+ file:
+ path: "{{ sudoers_d_file }}"
+ state: absent
diff --git a/test/integration/targets/copy/tasks/no_log.yml b/test/integration/targets/copy/tasks/no_log.yml
new file mode 100644
index 0000000..980c317
--- /dev/null
+++ b/test/integration/targets/copy/tasks/no_log.yml
@@ -0,0 +1,82 @@
+- block:
+
+ - set_fact:
+ dest: "{{ local_temp_dir }}/test_no_log"
+
+ - name: ensure playbook and dest files don't exist yet
+ file:
+ path: "{{ item }}"
+ state: absent
+ loop:
+ - "{{ local_temp_dir }}/test_no_log.yml"
+ - "{{ dest }}"
+
+ - name: create a playbook to run with command
+ copy:
+ dest: "{{local_temp_dir}}/test_no_log.yml"
+ content: !unsafe |
+ ---
+ - hosts: localhost
+ gather_facts: no
+ tasks:
+ - copy:
+ dest: "{{ dest }}"
+ content: "{{ secret }}"
+
+ - name: copy the secret while using -vvv and check mode
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=SECRET -e dest={{dest}} --check"
+ register: result
+
+ - assert:
+ that:
+ - "'SECRET' not in result.stdout"
+
+ - name: copy the secret while using -vvv
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=SECRET -e dest={{dest}}"
+ register: result
+
+ - assert:
+ that:
+ - "'SECRET' not in result.stdout"
+
+ - name: copy the secret while using -vvv and check mode again
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=SECRET -e dest={{dest}} --check"
+ register: result
+
+ - assert:
+ that:
+ - "'SECRET' not in result.stdout"
+
+ - name: copy the secret while using -vvv again
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=SECRET -e dest={{dest}}"
+ register: result
+
+ - assert:
+ that:
+ - "'SECRET' not in result.stdout"
+
+ - name: copy a new secret while using -vvv and check mode
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=NEWSECRET -e dest={{dest}} --check"
+ register: result
+
+ - assert:
+ that:
+ - "'NEWSECRET' not in result.stdout"
+
+ - name: copy a new secret while using -vvv
+ command: "ansible-playbook {{local_temp_dir}}/test_no_log.yml -vvv -e secret=NEWSECRET -e dest={{dest}}"
+ register: result
+
+ - assert:
+ that:
+ - "'NEWSECRET' not in result.stdout"
+
+ always:
+
+ - name: remove temp test files
+ file:
+ path: "{{ item }}"
+ state: absent
+ loop:
+ - "{{ local_temp_dir }}/test_no_log.yml"
+ - "{{ dest }}"
diff --git a/test/integration/targets/copy/tasks/selinux.yml b/test/integration/targets/copy/tasks/selinux.yml
new file mode 100644
index 0000000..dddee6f
--- /dev/null
+++ b/test/integration/targets/copy/tasks/selinux.yml
@@ -0,0 +1,36 @@
+# Ensure that our logic for special filesystems works as intended
+# https://github.com/ansible/ansible/issues/70244
+- block:
+ - name: Install dosfstools
+ yum:
+ name: dosfstools
+ state: present
+
+ - name: Create a file to use for a fat16 filesystem
+ command: dd if=/dev/zero of=/fat16 bs=1024 count=10240
+
+ - name: mkfs.fat
+ command: mkfs.fat -F16 /fat16
+
+ - name: Mount it
+ command: mount /fat16 /mnt
+
+ - name: Copy a file to it
+ copy:
+ src: /etc/fstab
+ dest: /mnt/fstab
+ remote_src: true
+ always:
+ - name: Unmount it
+ command: umount /mnt
+ ignore_errors: true
+
+ - name: Nuke /fat16
+ file:
+ path: /fat16
+ state: absent
+
+ - name: Uninstall dosfstools
+ yum:
+ name: dosfstools
+ state: absent
diff --git a/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir.yml b/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir.yml
new file mode 100644
index 0000000..f4ab999
--- /dev/null
+++ b/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir.yml
@@ -0,0 +1,26 @@
+- name: Ensure that dest top directory doesn't exist
+ file:
+ path: '{{ remote_dir }}/{{ dest.split("/")[0] }}'
+ state: absent
+
+- name: Copy file, dest is a file in non-existing target directory
+ copy:
+ src: foo.txt
+ dest: '{{ remote_dir }}/{{ dest }}'
+ register: copy_result
+ ignore_errors: True
+
+- name: Assert copy failed
+ assert:
+ that:
+ - 'copy_result is failed'
+
+- name: Stat dest path
+ stat:
+ path: '{{ remote_dir }}/{{ dest.split("/")[0] }}'
+ register: stat_file_in_dir_result
+
+- name: assert that dest doesn't exist
+ assert:
+ that:
+ - 'not stat_file_in_dir_result.stat.exists'
diff --git a/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir_remote_src.yml b/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir_remote_src.yml
new file mode 100644
index 0000000..61d8796
--- /dev/null
+++ b/test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir_remote_src.yml
@@ -0,0 +1,32 @@
+- name: Ensure that dest top directory doesn't exist
+ file:
+ path: '{{ remote_dir }}/{{ dest.split("/")[0] }}'
+ state: absent
+
+- name: create src file
+ file:
+ path: foo.txt
+ state: touch
+
+- name: Copy file, dest is a file in non-existing target directory
+ copy:
+ src: foo.txt
+ dest: '{{ remote_dir }}/{{ dest }}'
+ remote_src: true
+ register: copy_result
+ ignore_errors: True
+
+- name: Assert copy failed
+ assert:
+ that:
+ - 'copy_result is failed'
+
+- name: Stat dest path
+ stat:
+ path: '{{ remote_dir }}/{{ dest.split("/")[0] }}'
+ register: stat_file_in_dir_result
+
+- name: assert that dest doesn't exist
+ assert:
+ that:
+ - 'not stat_file_in_dir_result.stat.exists'
diff --git a/test/integration/targets/copy/tasks/src_remote_file_is_not_file.yml b/test/integration/targets/copy/tasks/src_remote_file_is_not_file.yml
new file mode 100644
index 0000000..2cda7d3
--- /dev/null
+++ b/test/integration/targets/copy/tasks/src_remote_file_is_not_file.yml
@@ -0,0 +1,39 @@
+- name: test remote src non files
+ vars:
+ destfile: '{{remote_dir}}/whocares'
+ block:
+ - name: mess with dev/null
+ copy:
+ src: /dev/null
+ dest: "{{destfile}}"
+ remote_src: true
+ become: true
+ register: dev_null_fail
+ ignore_errors: true
+
+ - name: ensure we failed
+ assert:
+ that:
+ - dev_null_fail is failed
+ - "'not a file' in dev_null_fail.msg"
+
+ - name: now with file existing
+ file: state=touch path="{{destfile}}"
+
+ - name: mess with dev/null again
+ copy:
+ src: /dev/null
+ dest: "{{destfile}}"
+ remote_src: true
+ become: true
+ register: dev_null_fail
+ ignore_errors: true
+
+ - name: ensure we failed, again
+ assert:
+ that:
+ - dev_null_fail is failed
+ - "'not a file' in dev_null_fail.msg"
+ always:
+ - name: cleanup
+ file: state=absent path="{{destfile}}"
diff --git a/test/integration/targets/copy/tasks/tests.yml b/test/integration/targets/copy/tasks/tests.yml
new file mode 100644
index 0000000..7220356
--- /dev/null
+++ b/test/integration/targets/copy/tasks/tests.yml
@@ -0,0 +1,2286 @@
+# 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_tasks: file=dest_in_non_existent_directories_remote_src.yml
+ with_items:
+ - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' }
+
+# src is a file, dest is file in a non-existent directory: checks that a failure occurs
+# using remote_src
+- include_tasks: file=src_file_dest_file_in_non_existent_dir_remote_src.yml
+ with_items:
+ - 'new_sub_dir1/sub_dir2/foo.txt'
+ - 'new_sub_dir1/foo.txt'
+ loop_control:
+ loop_var: 'dest'
+
+# src is a file, dest is a non-existent directory (2 levels of directories):
+# checks that dest is created
+- include_tasks: file=dest_in_non_existent_directories.yml
+ with_items:
+ - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' }
+ - { src: 'subdir', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/subdir/bar.txt' }
+ - { src: 'subdir/', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/bar.txt' }
+ - { src: 'subdir', dest: 'new_sub_dir1/sub_dir2', check: 'new_sub_dir1/sub_dir2/subdir/bar.txt' }
+ - { src: 'subdir/', dest: 'new_sub_dir1/sub_dir2', check: 'new_sub_dir1/sub_dir2/bar.txt' }
+
+# src is a file, dest is file in a non-existent directory: checks that a failure occurs
+- include_tasks: file=src_file_dest_file_in_non_existent_dir.yml
+ with_items:
+ - 'new_sub_dir1/sub_dir2/foo.txt'
+ - 'new_sub_dir1/foo.txt'
+ loop_control:
+ loop_var: 'dest'
+#
+# Recursive copying on remote host
+#
+## prepare for test
+- block:
+
+ - name: execute - Create a test src dir
+ file:
+ path: '{{ remote_dir }}/remote_dir_src'
+ state: directory
+
+ - name: gather - Stat the remote_dir_src
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src'
+ register: stat_remote_dir_src_before
+
+ - name: execute - Create a subdir
+ file:
+ path: '{{ remote_dir }}/remote_dir_src/subdir'
+ state: directory
+
+ - name: gather - Stat the remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/subdir'
+ register: stat_remote_dir_src_subdir_before
+
+ - name: execute - Create a file in the top of src
+ copy:
+ dest: '{{ remote_dir }}/remote_dir_src/file1'
+ content: 'hello world 1'
+
+ - name: gather - Stat the remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/file1'
+ register: stat_remote_dir_src_file1_before
+
+ - name: execute - Create a file in the subdir
+ copy:
+ dest: '{{ remote_dir }}/remote_dir_src/subdir/file12'
+ content: 'hello world 12'
+
+ - name: gather - Stat the remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/subdir/file12'
+ register: stat_remote_dir_src_subdir_file12_before
+
+ - name: execute - Create a link to the file12
+ file:
+ path: '{{ remote_dir }}/remote_dir_src/link_file12'
+ src: '{{ remote_dir }}/remote_dir_src/subdir/file12'
+ state: link
+
+ - name: gather - Stat the remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/link_file12'
+ register: stat_remote_dir_src_link_file12_before
+
+### test when src endswith os.sep and dest isdir
+- block:
+
+### local_follow: True
+ - name: execute - Create a test dest dir
+ file:
+ path: '{{ remote_dir }}/testcase1_local_follow_true'
+ state: directory
+
+ - name: execute - Copy the directory on remote with local_follow True
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase1_local_follow_true'
+ local_follow: True
+ register: testcase1
+
+ - name: gather - Stat the testcase1_local_follow_true
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_true'
+ register: stat_testcase1_local_follow_true
+ - name: gather - Stat the testcase1_local_follow_true/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_true/subdir'
+ register: stat_testcase1_local_follow_true_subdir
+ - name: gather - Stat the testcase1_local_follow_true/file1
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_true/file1'
+ register: stat_testcase1_local_follow_true_file1
+ - name: gather - Stat the testcase1_local_follow_true/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_true/subdir/file12'
+ register: stat_testcase1_local_follow_true_subdir_file12
+ - name: gather - Stat the testcase1_local_follow_true/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_true/link_file12'
+ register: stat_testcase1_local_follow_true_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase1 is changed
+ - "stat_testcase1_local_follow_true.stat.isdir"
+ - "stat_testcase1_local_follow_true_subdir.stat.isdir"
+ - "stat_testcase1_local_follow_true_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase1_local_follow_true_file1.stat.checksum"
+ - "stat_testcase1_local_follow_true_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_true_subdir_file12.stat.checksum"
+ - "stat_testcase1_local_follow_true_link_file12.stat.exists"
+ - "not stat_testcase1_local_follow_true_link_file12.stat.islnk"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_true_link_file12.stat.checksum"
+
+### local_follow: False
+ - name: execute - Create a test dest dir
+ file:
+ path: '{{ remote_dir }}/testcase1_local_follow_false'
+ state: directory
+
+ - name: execute - Copy the directory on remote with local_follow False
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase1_local_follow_false'
+ local_follow: False
+ register: testcase1
+
+ - name: gather - Stat the testcase1_local_follow_false
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_false'
+ register: stat_testcase1_local_follow_false
+ - name: gather - Stat the testcase1_local_follow_false/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_false/subdir'
+ register: stat_testcase1_local_follow_false_subdir
+ - name: gather - Stat the testcase1_local_follow_false/file1
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_false/file1'
+ register: stat_testcase1_local_follow_false_file1
+ - name: gather - Stat the testcase1_local_follow_false/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_false/subdir/file12'
+ register: stat_testcase1_local_follow_false_subdir_file12
+ - name: gather - Stat the testcase1_local_follow_false/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase1_local_follow_false/link_file12'
+ register: stat_testcase1_local_follow_false_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase1 is changed
+ - "stat_testcase1_local_follow_false.stat.isdir"
+ - "stat_testcase1_local_follow_false_subdir.stat.isdir"
+ - "stat_testcase1_local_follow_false_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase1_local_follow_false_file1.stat.checksum"
+ - "stat_testcase1_local_follow_false_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase1_local_follow_false_subdir_file12.stat.checksum"
+ - "stat_testcase1_local_follow_false_link_file12.stat.exists"
+ - "stat_testcase1_local_follow_false_link_file12.stat.islnk"
+
+## test when src endswith os.sep and dest not exists
+
+- block:
+ - name: execute - Copy the directory on remote with local_follow True
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase2_local_follow_true'
+ local_follow: True
+ register: testcase2
+
+ - name: gather - Stat the testcase2_local_follow_true
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_true'
+ register: stat_testcase2_local_follow_true
+ - name: gather - Stat the testcase2_local_follow_true/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_true/subdir'
+ register: stat_testcase2_local_follow_true_subdir
+ - name: gather - Stat the testcase2_local_follow_true/file1
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_true/file1'
+ register: stat_testcase2_local_follow_true_file1
+ - name: gather - Stat the testcase2_local_follow_true/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_true/subdir/file12'
+ register: stat_testcase2_local_follow_true_subdir_file12
+ - name: gather - Stat the testcase2_local_follow_true/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_true/link_file12'
+ register: stat_testcase2_local_follow_true_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase2 is changed
+ - "stat_testcase2_local_follow_true.stat.isdir"
+ - "stat_testcase2_local_follow_true_subdir.stat.isdir"
+ - "stat_testcase2_local_follow_true_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase2_local_follow_true_file1.stat.checksum"
+ - "stat_testcase2_local_follow_true_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_true_subdir_file12.stat.checksum"
+ - "stat_testcase2_local_follow_true_link_file12.stat.exists"
+ - "not stat_testcase2_local_follow_true_link_file12.stat.islnk"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_true_link_file12.stat.checksum"
+
+### local_follow: False
+ - name: execute - Copy the directory on remote with local_follow False
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase2_local_follow_false'
+ local_follow: False
+ register: testcase2
+
+ - name: execute - Copy the directory on remote with local_follow False
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase2_local_follow_false'
+ local_follow: False
+ register: testcase1
+
+ - name: gather - Stat the testcase2_local_follow_false
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_false'
+ register: stat_testcase2_local_follow_false
+ - name: gather - Stat the testcase2_local_follow_false/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_false/subdir'
+ register: stat_testcase2_local_follow_false_subdir
+ - name: gather - Stat the testcase2_local_follow_false/file1
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_false/file1'
+ register: stat_testcase2_local_follow_false_file1
+ - name: gather - Stat the testcase2_local_follow_false/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_false/subdir/file12'
+ register: stat_testcase2_local_follow_false_subdir_file12
+ - name: gather - Stat the testcase2_local_follow_false/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase2_local_follow_false/link_file12'
+ register: stat_testcase2_local_follow_false_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase2 is changed
+ - "stat_testcase2_local_follow_false.stat.isdir"
+ - "stat_testcase2_local_follow_false_subdir.stat.isdir"
+ - "stat_testcase2_local_follow_false_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase2_local_follow_false_file1.stat.checksum"
+ - "stat_testcase2_local_follow_false_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase2_local_follow_false_subdir_file12.stat.checksum"
+ - "stat_testcase2_local_follow_false_link_file12.stat.exists"
+ - "stat_testcase2_local_follow_false_link_file12.stat.islnk"
+
+## test when src not endswith os.sep and dest isdir
+- block:
+
+### local_follow: True
+ - name: execute - Create a test dest dir
+ file:
+ path: '{{ remote_dir }}/testcase3_local_follow_true'
+ state: directory
+
+ - name: execute - Copy the directory on remote with local_follow True
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src'
+ dest: '{{ remote_dir }}/testcase3_local_follow_true'
+ local_follow: True
+ register: testcase3
+
+ - name: gather - Stat the testcase3_local_follow_true
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src'
+ register: stat_testcase3_local_follow_true_remote_dir_src
+ - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/subdir'
+ register: stat_testcase3_local_follow_true_remote_dir_src_subdir
+ - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/file1'
+ register: stat_testcase3_local_follow_true_remote_dir_src_file1
+ - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/subdir/file12'
+ register: stat_testcase3_local_follow_true_remote_dir_src_subdir_file12
+ - name: gather - Stat the testcase3_local_follow_true/remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_true/remote_dir_src/link_file12'
+ register: stat_testcase3_local_follow_true_remote_dir_src_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase3 is changed
+ - "stat_testcase3_local_follow_true_remote_dir_src.stat.isdir"
+ - "stat_testcase3_local_follow_true_remote_dir_src_subdir.stat.isdir"
+ - "stat_testcase3_local_follow_true_remote_dir_src_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_file1.stat.checksum"
+ - "stat_testcase3_local_follow_true_remote_dir_src_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_subdir_file12.stat.checksum"
+ - "stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.exists"
+ - "not stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.islnk"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_true_remote_dir_src_link_file12.stat.checksum"
+
+### local_follow: False
+ - name: execute - Create a test dest dir
+ file:
+ path: '{{ remote_dir }}/testcase3_local_follow_false'
+ state: directory
+
+ - name: execute - Copy the directory on remote with local_follow False
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src'
+ dest: '{{ remote_dir }}/testcase3_local_follow_false'
+ local_follow: False
+ register: testcase3
+
+ - name: gather - Stat the testcase3_local_follow_false
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src'
+ register: stat_testcase3_local_follow_false_remote_dir_src
+ - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/subdir'
+ register: stat_testcase3_local_follow_false_remote_dir_src_subdir
+ - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/file1'
+ register: stat_testcase3_local_follow_false_remote_dir_src_file1
+ - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/subdir/file12'
+ register: stat_testcase3_local_follow_false_remote_dir_src_subdir_file12
+ - name: gather - Stat the testcase3_local_follow_false/remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase3_local_follow_false/remote_dir_src/link_file12'
+ register: stat_testcase3_local_follow_false_remote_dir_src_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow False.
+ assert:
+ that:
+ - testcase3 is changed
+ - "stat_testcase3_local_follow_false_remote_dir_src.stat.isdir"
+ - "stat_testcase3_local_follow_false_remote_dir_src_subdir.stat.isdir"
+ - "stat_testcase3_local_follow_false_remote_dir_src_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase3_local_follow_false_remote_dir_src_file1.stat.checksum"
+ - "stat_testcase3_local_follow_false_remote_dir_src_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase3_local_follow_false_remote_dir_src_subdir_file12.stat.checksum"
+ - "stat_testcase3_local_follow_false_remote_dir_src_link_file12.stat.exists"
+ - "stat_testcase3_local_follow_false_remote_dir_src_link_file12.stat.islnk"
+
+## test when src not endswith os.sep and dest not exists
+- block:
+### local_follow: True
+ - name: execute - Copy the directory on remote with local_follow True
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src'
+ dest: '{{ remote_dir }}/testcase4_local_follow_true'
+ local_follow: True
+ register: testcase4
+
+ - name: gather - Stat the testcase4_local_follow_true
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src'
+ register: stat_testcase4_local_follow_true_remote_dir_src
+ - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/subdir'
+ register: stat_testcase4_local_follow_true_remote_dir_src_subdir
+ - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/file1'
+ register: stat_testcase4_local_follow_true_remote_dir_src_file1
+ - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/subdir/file12'
+ register: stat_testcase4_local_follow_true_remote_dir_src_subdir_file12
+ - name: gather - Stat the testcase4_local_follow_true/remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_true/remote_dir_src/link_file12'
+ register: stat_testcase4_local_follow_true_remote_dir_src_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow True.
+ assert:
+ that:
+ - testcase4 is changed
+ - "stat_testcase4_local_follow_true_remote_dir_src.stat.isdir"
+ - "stat_testcase4_local_follow_true_remote_dir_src_subdir.stat.isdir"
+ - "stat_testcase4_local_follow_true_remote_dir_src_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_file1.stat.checksum"
+ - "stat_testcase4_local_follow_true_remote_dir_src_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_subdir_file12.stat.checksum"
+ - "stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.exists"
+ - "not stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.islnk"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_true_remote_dir_src_link_file12.stat.checksum"
+
+### local_follow: False
+ - name: execute - Copy the directory on remote with local_follow False
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src'
+ dest: '{{ remote_dir }}/testcase4_local_follow_false'
+ local_follow: False
+ register: testcase4
+
+ - name: gather - Stat the testcase4_local_follow_false
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src'
+ register: stat_testcase4_local_follow_false_remote_dir_src
+ - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/subdir'
+ register: stat_testcase4_local_follow_false_remote_dir_src_subdir
+ - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/file1'
+ register: stat_testcase4_local_follow_false_remote_dir_src_file1
+ - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/subdir/file12'
+ register: stat_testcase4_local_follow_false_remote_dir_src_subdir_file12
+ - name: gather - Stat the testcase4_local_follow_false/remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/testcase4_local_follow_false/remote_dir_src/link_file12'
+ register: stat_testcase4_local_follow_false_remote_dir_src_link_file12
+
+ - name: assert - remote_dir_src has copied with local_follow False.
+ assert:
+ that:
+ - testcase4 is changed
+ - "stat_testcase4_local_follow_false_remote_dir_src.stat.isdir"
+ - "stat_testcase4_local_follow_false_remote_dir_src_subdir.stat.isdir"
+ - "stat_testcase4_local_follow_false_remote_dir_src_file1.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_testcase4_local_follow_false_remote_dir_src_file1.stat.checksum"
+ - "stat_testcase4_local_follow_false_remote_dir_src_subdir_file12.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_testcase4_local_follow_false_remote_dir_src_subdir_file12.stat.checksum"
+ - "stat_testcase4_local_follow_false_remote_dir_src_link_file12.stat.exists"
+ - "stat_testcase4_local_follow_false_remote_dir_src_link_file12.stat.islnk"
+
+- block:
+ - name: execute - Clone the source directory on remote
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/remote_dir_src/'
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src'
+ - name: Create a 2nd level subdirectory
+ file:
+ path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/'
+ state: directory
+ - name: execute - Copy the directory on remote
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/'
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest'
+ local_follow: True
+ - name: execute - Create a new file in the subdir
+ copy:
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13'
+ content: 'very new file'
+ - name: gather - Stat the testcase5_remote_src_subdirs_src/subdir/subdir2/file13
+ stat:
+ path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13'
+ - name: execute - Copy the directory on remote
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/'
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/'
+ register: testcase5_new
+ - name: execute - Edit a file in the subdir
+ copy:
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13'
+ content: 'NOT hello world 12'
+ - name: gather - Stat the testcase5_remote_src_subdirs_src/subdir/subdir2/file13
+ stat:
+ path: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/subdir/subdir2/file13'
+ register: stat_testcase5_remote_src_subdirs_file13_before
+ - name: execute - Copy the directory on remote
+ copy:
+ remote_src: True
+ src: '{{ remote_dir }}/testcase5_remote_src_subdirs_src/'
+ dest: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/'
+ register: testcase5_edited
+ - name: gather - Stat the testcase5_remote_src_subdirs_dest/subdir/subdir2/file13
+ stat:
+ path: '{{ remote_dir }}/testcase5_remote_src_subdirs_dest/subdir/subdir2/file13'
+ register: stat_testcase5_remote_src_subdirs_file13
+ - name: assert - remote_dir_src has copied with local_follow False.
+ assert:
+ that:
+ - testcase5_new is changed
+ - testcase5_edited is changed
+ - "stat_testcase5_remote_src_subdirs_file13.stat.exists"
+ - "stat_testcase5_remote_src_subdirs_file13_before.stat.checksum == stat_testcase5_remote_src_subdirs_file13.stat.checksum"
+
+
+## test copying the directory on remote with chown
+- name: setting 'ansible_copy_test_user_name' outside block since 'always' section depends on this also
+ set_fact:
+ ansible_copy_test_user_name: 'ansible_copy_test_{{ 100000 | random }}'
+
+- block:
+
+ - name: execute - create a user for test
+ user:
+ name: '{{ ansible_copy_test_user_name }}'
+ state: present
+ become: true
+ register: ansible_copy_test_user
+
+ - name: execute - create a group for test
+ group:
+ name: '{{ ansible_copy_test_user_name }}'
+ state: present
+ become: true
+ register: ansible_copy_test_group
+
+ - name: execute - Copy the directory on remote with chown
+ copy:
+ remote_src: True
+ src: '{{ remote_dir_expanded }}/remote_dir_src/'
+ dest: '{{ remote_dir_expanded }}/new_dir_with_chown'
+ owner: '{{ ansible_copy_test_user_name }}'
+ group: '{{ ansible_copy_test_user_name }}'
+ follow: true
+ register: testcase5
+ become: true
+
+ - name: gather - Stat the new_dir_with_chown
+ stat:
+ path: '{{ remote_dir }}/new_dir_with_chown'
+ register: stat_new_dir_with_chown
+
+ - name: gather - Stat the new_dir_with_chown/file1
+ stat:
+ path: '{{ remote_dir }}/new_dir_with_chown/file1'
+ register: stat_new_dir_with_chown_file1
+
+ - name: gather - Stat the new_dir_with_chown/subdir
+ stat:
+ path: '{{ remote_dir }}/new_dir_with_chown/subdir'
+ register: stat_new_dir_with_chown_subdir
+
+ - name: gather - Stat the new_dir_with_chown/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/new_dir_with_chown/subdir/file12'
+ register: stat_new_dir_with_chown_subdir_file12
+
+ - name: gather - Stat the new_dir_with_chown/link_file12
+ stat:
+ path: '{{ remote_dir }}/new_dir_with_chown/link_file12'
+ register: stat_new_dir_with_chown_link_file12
+
+ - name: assert - owner and group have changed
+ assert:
+ that:
+ - testcase5 is changed
+ - "stat_new_dir_with_chown.stat.uid == {{ ansible_copy_test_user.uid }}"
+ - "stat_new_dir_with_chown.stat.gid == {{ ansible_copy_test_group.gid }}"
+ - "stat_new_dir_with_chown.stat.pw_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown.stat.gr_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_file1.stat.uid == {{ ansible_copy_test_user.uid }}"
+ - "stat_new_dir_with_chown_file1.stat.gid == {{ ansible_copy_test_group.gid }}"
+ - "stat_new_dir_with_chown_file1.stat.pw_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_file1.stat.gr_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_subdir.stat.uid == {{ ansible_copy_test_user.uid }}"
+ - "stat_new_dir_with_chown_subdir.stat.gid == {{ ansible_copy_test_group.gid }}"
+ - "stat_new_dir_with_chown_subdir.stat.pw_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_subdir.stat.gr_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_subdir_file12.stat.uid == {{ ansible_copy_test_user.uid }}"
+ - "stat_new_dir_with_chown_subdir_file12.stat.gid == {{ ansible_copy_test_group.gid }}"
+ - "stat_new_dir_with_chown_subdir_file12.stat.pw_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_subdir_file12.stat.gr_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_link_file12.stat.uid == {{ ansible_copy_test_user.uid }}"
+ - "stat_new_dir_with_chown_link_file12.stat.gid == {{ ansible_copy_test_group.gid }}"
+ - "stat_new_dir_with_chown_link_file12.stat.pw_name == '{{ ansible_copy_test_user_name }}'"
+ - "stat_new_dir_with_chown_link_file12.stat.gr_name == '{{ ansible_copy_test_user_name }}'"
+
+ always:
+ - name: execute - remove the user for test
+ user:
+ name: '{{ ansible_copy_test_user_name }}'
+ state: absent
+ remove: yes
+ become: true
+
+ - name: execute - remove the group for test
+ group:
+ name: '{{ ansible_copy_test_user_name }}'
+ state: absent
+ become: true
+
+## testcase last - make sure remote_dir_src not change
+- block:
+ - name: Stat the remote_dir_src
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src'
+ register: stat_remote_dir_src_after
+
+ - name: Stat the remote_dir_src/subdir
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/subdir'
+ register: stat_remote_dir_src_subdir_after
+
+ - name: Stat the remote_dir_src/file1
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/file1'
+ register: stat_remote_dir_src_file1_after
+
+ - name: Stat the remote_dir_src/subdir/file12
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/subdir/file12'
+ register: stat_remote_dir_src_subdir_file12_after
+
+ - name: Stat the remote_dir_src/link_file12
+ stat:
+ path: '{{ remote_dir }}/remote_dir_src/link_file12'
+ register: stat_remote_dir_src_link_file12_after
+
+ - name: Assert that remote_dir_src not change.
+ assert:
+ that:
+ - "stat_remote_dir_src_after.stat.exists"
+ - "stat_remote_dir_src_after.stat.isdir"
+ - "stat_remote_dir_src_before.stat.uid == stat_remote_dir_src_after.stat.uid"
+ - "stat_remote_dir_src_before.stat.gid == stat_remote_dir_src_after.stat.gid"
+ - "stat_remote_dir_src_before.stat.pw_name == stat_remote_dir_src_after.stat.pw_name"
+ - "stat_remote_dir_src_before.stat.gr_name == stat_remote_dir_src_after.stat.gr_name"
+ - "stat_remote_dir_src_before.stat.path == stat_remote_dir_src_after.stat.path"
+ - "stat_remote_dir_src_before.stat.mode == stat_remote_dir_src_after.stat.mode"
+
+ - "stat_remote_dir_src_subdir_after.stat.exists"
+ - "stat_remote_dir_src_subdir_after.stat.isdir"
+ - "stat_remote_dir_src_subdir_before.stat.uid == stat_remote_dir_src_subdir_after.stat.uid"
+ - "stat_remote_dir_src_subdir_before.stat.gid == stat_remote_dir_src_subdir_after.stat.gid"
+ - "stat_remote_dir_src_subdir_before.stat.pw_name == stat_remote_dir_src_subdir_after.stat.pw_name"
+ - "stat_remote_dir_src_subdir_before.stat.gr_name == stat_remote_dir_src_subdir_after.stat.gr_name"
+ - "stat_remote_dir_src_subdir_before.stat.path == stat_remote_dir_src_subdir_after.stat.path"
+ - "stat_remote_dir_src_subdir_before.stat.mode == stat_remote_dir_src_subdir_after.stat.mode"
+
+ - "stat_remote_dir_src_file1_after.stat.exists"
+ - "stat_remote_dir_src_file1_before.stat.uid == stat_remote_dir_src_file1_after.stat.uid"
+ - "stat_remote_dir_src_file1_before.stat.gid == stat_remote_dir_src_file1_after.stat.gid"
+ - "stat_remote_dir_src_file1_before.stat.pw_name == stat_remote_dir_src_file1_after.stat.pw_name"
+ - "stat_remote_dir_src_file1_before.stat.gr_name == stat_remote_dir_src_file1_after.stat.gr_name"
+ - "stat_remote_dir_src_file1_before.stat.path == stat_remote_dir_src_file1_after.stat.path"
+ - "stat_remote_dir_src_file1_before.stat.mode == stat_remote_dir_src_file1_after.stat.mode"
+ - "stat_remote_dir_src_file1_before.stat.checksum == stat_remote_dir_src_file1_after.stat.checksum"
+
+ - "stat_remote_dir_src_subdir_file12_after.stat.exists"
+ - "stat_remote_dir_src_subdir_file12_before.stat.uid == stat_remote_dir_src_subdir_file12_after.stat.uid"
+ - "stat_remote_dir_src_subdir_file12_before.stat.gid == stat_remote_dir_src_subdir_file12_after.stat.gid"
+ - "stat_remote_dir_src_subdir_file12_before.stat.pw_name == stat_remote_dir_src_subdir_file12_after.stat.pw_name"
+ - "stat_remote_dir_src_subdir_file12_before.stat.gr_name == stat_remote_dir_src_subdir_file12_after.stat.gr_name"
+ - "stat_remote_dir_src_subdir_file12_before.stat.path == stat_remote_dir_src_subdir_file12_after.stat.path"
+ - "stat_remote_dir_src_subdir_file12_before.stat.mode == stat_remote_dir_src_subdir_file12_after.stat.mode"
+ - "stat_remote_dir_src_subdir_file12_before.stat.checksum == stat_remote_dir_src_subdir_file12_after.stat.checksum"
+
+ - "stat_remote_dir_src_link_file12_after.stat.exists"
+ - "stat_remote_dir_src_link_file12_after.stat.islnk"
+ - "stat_remote_dir_src_link_file12_before.stat.uid == stat_remote_dir_src_link_file12_after.stat.uid"
+ - "stat_remote_dir_src_link_file12_before.stat.gid == stat_remote_dir_src_link_file12_after.stat.gid"
+ - "stat_remote_dir_src_link_file12_before.stat.pw_name == stat_remote_dir_src_link_file12_after.stat.pw_name"
+ - "stat_remote_dir_src_link_file12_before.stat.gr_name == stat_remote_dir_src_link_file12_after.stat.gr_name"
+ - "stat_remote_dir_src_link_file12_before.stat.path == stat_remote_dir_src_link_file12_after.stat.path"
+ - "stat_remote_dir_src_link_file12_before.stat.mode == stat_remote_dir_src_link_file12_after.stat.mode"
+
+# Test for issue 69783: copy with remote_src=yes and src='dir/' preserves all permissions
+- block:
+ - name: Create directory structure
+ file:
+ path: "{{ local_temp_dir }}/test69783/{{ item }}"
+ state: directory
+ loop:
+ - "src/dir"
+ - "dest"
+
+ - name: Create source file structure
+ file:
+ path: "{{ local_temp_dir }}/test69783/src/{{ item.name }}"
+ state: touch
+ mode: "{{ item.mode }}"
+ loop:
+ - { name: 'readwrite', mode: '0644' }
+ - { name: 'executable', mode: '0755' }
+ - { name: 'readonly', mode: '0444' }
+ - { name: 'dir/readwrite', mode: '0644' }
+ - { name: 'dir/executable', mode: '0755' }
+ - { name: 'dir/readonly', mode: '0444' }
+
+ - name: Recursive remote copy with preserve
+ copy:
+ src: "{{ local_temp_dir }}/test69783/src/"
+ dest: "{{ local_temp_dir }}/test69783/dest/"
+ remote_src: yes
+ mode: preserve
+
+ - name: Stat dest 'readwrite' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/readwrite"
+ register: dest_readwrite_stat
+
+ - name: Stat dest 'executable' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/executable"
+ register: dest_executable_stat
+
+ - name: Stat dest 'readonly' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/readonly"
+ register: dest_readonly_stat
+
+ - name: Stat dest 'dir/readwrite' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/dir/readwrite"
+ register: dest_dir_readwrite_stat
+
+ - name: Stat dest 'dir/executable' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/dir/executable"
+ register: dest_dir_executable_stat
+
+ - name: Stat dest 'dir/readonly' file
+ stat:
+ path: "{{ local_temp_dir}}/test69783/dest/dir/readonly"
+ register: dest_dir_readonly_stat
+
+ - name: Assert modes are preserved
+ assert:
+ that:
+ - "dest_readwrite_stat.stat.mode == '0644'"
+ - "dest_executable_stat.stat.mode == '0755'"
+ - "dest_readonly_stat.stat.mode == '0444'"
+ - "dest_dir_readwrite_stat.stat.mode == '0644'"
+ - "dest_dir_executable_stat.stat.mode == '0755'"
+ - "dest_dir_readonly_stat.stat.mode == '0444'"
+
+- name: fail to copy an encrypted file without the password set
+ copy:
+ src: '{{role_path}}/files-different/vault/vault-file'
+ dest: '{{remote_tmp_dir}}/copy/file'
+ register: fail_copy_encrypted_file
+ ignore_errors: yes # weird failed_when doesn't work in this case
+
+- name: assert failure message when copying an encrypted file without the password set
+ assert:
+ that:
+ - fail_copy_encrypted_file is failed
+ - fail_copy_encrypted_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-different/vault/vault-file'
+
+- name: fail to copy a directory with an encrypted file without the password
+ copy:
+ src: '{{role_path}}/files-different/vault'
+ dest: '{{remote_tmp_dir}}/copy'
+ register: fail_copy_directory_with_enc_file
+ ignore_errors: yes
+
+- name: assert failure message when copying a directory that contains an encrypted file without the password set
+ assert:
+ that:
+ - fail_copy_directory_with_enc_file is failed
+ - fail_copy_directory_with_enc_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-different/vault/vault-file'