diff options
Diffstat (limited to 'test/integration/targets/file/tasks/state_link.yml')
-rw-r--r-- | test/integration/targets/file/tasks/state_link.yml | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/test/integration/targets/file/tasks/state_link.yml b/test/integration/targets/file/tasks/state_link.yml new file mode 100644 index 0000000..673fe6f --- /dev/null +++ b/test/integration/targets/file/tasks/state_link.yml @@ -0,0 +1,501 @@ +# file module tests for dealing with symlinks (state=link) + +- name: Initialize the test output dir + import_tasks: initialize.yml + +# +# Basic absolute symlink to a file +# +- name: create soft link to file + file: src={{output_file}} dest={{remote_tmp_dir_test}}/soft.txt state=link + register: file1_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/soft.txt' + follow: False + register: file1_link_stat + +- name: verify that the symlink was created correctly + assert: + that: + - 'file1_result is changed' + - 'file1_link_stat["stat"].islnk' + - 'file1_link_stat["stat"].lnk_target | expanduser == output_file | expanduser' + +# +# Change an absolute soft link into a relative soft link +# +- name: change soft link to relative + file: src={{output_file|basename}} dest={{remote_tmp_dir_test}}/soft.txt state=link + register: file2_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/soft.txt' + follow: False + register: file2_link_stat + +- name: verify that the file was marked as changed + assert: + that: + - "file2_result is changed" + - "file2_result.diff.before.src == remote_file_expanded" + - "file2_result.diff.after.src == remote_file_expanded|basename" + - "file2_link_stat['stat'].islnk" + - "file2_link_stat['stat'].lnk_target == remote_file_expanded | basename" + +# +# Check that creating the soft link a second time was idempotent +# +- name: soft link idempotency check + file: src={{output_file|basename}} dest={{remote_tmp_dir_test}}/soft.txt state=link + register: file3_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/soft.txt' + follow: False + register: file3_link_stat + +- name: verify that the file was not marked as changed + assert: + that: + - "not file3_result is changed" + - "file3_link_stat['stat'].islnk" + - "file3_link_stat['stat'].lnk_target == remote_file_expanded | basename" + +# +# Test symlink to nonexistent files +# +- name: fail to create soft link to non existent file + file: + src: '/nonexistent' + dest: '{{remote_tmp_dir_test}}/soft2.txt' + state: 'link' + force: False + register: file4_result + ignore_errors: true + +- name: verify that link was not created + assert: + that: + - "file4_result is failed" + +- name: force creation soft link to non existent + file: + src: '/nonexistent' + dest: '{{ remote_tmp_dir_test}}/soft2.txt' + state: 'link' + force: True + register: file5_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/soft2.txt' + follow: False + register: file5_link_stat + +- name: verify that link was created + assert: + that: + - "file5_result is changed" + - "file5_link_stat['stat'].islnk" + - "file5_link_stat['stat'].lnk_target == '/nonexistent'" + +- name: Prove idempotence of force creation soft link to non existent + file: + src: '/nonexistent' + dest: '{{ remote_tmp_dir_test }}/soft2.txt' + state: 'link' + force: True + register: file6a_result + +- name: verify that the link to nonexistent is idempotent + assert: + that: + - "file6a_result.changed == false" + +# In order for a symlink in a sticky world writable directory to be followed, it must +# either be owned by the follower, +# or the directory and symlink must have the same owner. +- name: symlink in sticky directory + block: + - name: Create remote unprivileged remote user + user: + name: '{{ remote_unprivileged_user }}' + register: user + notify: remove users + + - name: Create a local temporary directory + tempfile: + state: directory + register: tempdir + + - name: Set sticky bit + file: + path: '{{ tempdir.path }}' + mode: o=rwXt + + - name: 'Check mode: force creation soft link in sticky directory owned by another user (mode is used)' + file: + src: '{{ user.home }}/nonexistent' + dest: '{{ tempdir.path }}/soft3.txt' + mode: 0640 + state: 'link' + owner: '{{ remote_unprivileged_user }}' + force: true + follow: false + check_mode: true + register: missing_dst_no_follow_enable_force_use_mode1 + + - name: force creation soft link in sticky directory owned by another user (mode is used) + file: + src: '{{ user.home }}/nonexistent' + dest: '{{ tempdir.path }}/soft3.txt' + mode: 0640 + state: 'link' + owner: '{{ remote_unprivileged_user }}' + force: true + follow: false + register: missing_dst_no_follow_enable_force_use_mode2 + + - name: Get stat info for the link + stat: + path: '{{ tempdir.path }}/soft3.txt' + follow: false + register: soft3_result + + - name: 'Idempotence: force creation soft link in sticky directory owned by another user (mode is used)' + file: + src: '{{ user.home }}/nonexistent' + dest: '{{ tempdir.path }}/soft3.txt' + mode: 0640 + state: 'link' + owner: '{{ remote_unprivileged_user }}' + force: yes + follow: false + register: missing_dst_no_follow_enable_force_use_mode3 + always: + - name: Delete remote unprivileged remote user + user: + name: '{{ remote_unprivileged_user }}' + state: absent + force: yes + remove: yes + + - name: Delete unprivileged user home and tempdir + file: + path: "{{ item }}" + state: absent + loop: + - '{{ tempdir.path }}' + - '{{ user.home }}' + +- name: verify that link was created + assert: + that: + - "missing_dst_no_follow_enable_force_use_mode1 is changed" + - "missing_dst_no_follow_enable_force_use_mode2 is changed" + - "missing_dst_no_follow_enable_force_use_mode3 is not changed" + - "soft3_result['stat'].islnk" + - "soft3_result['stat'].lnk_target == '{{ user.home }}/nonexistent'" + +# +# Test creating a link to a directory https://github.com/ansible/ansible/issues/1369 +# +- name: create soft link to directory using absolute path + file: + src: '/' + dest: '{{ remote_tmp_dir_test }}/root' + state: 'link' + register: file6_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/root' + follow: False + register: file6_link_stat + +- name: Get stat info for the pointed to file + stat: + path: '{{ remote_tmp_dir_test }}/root' + follow: True + register: file6_links_dest_stat + +- name: Get stat info for the file we intend to point to + stat: + path: '/' + follow: False + register: file6_dest_stat + +- name: verify that the link was created correctly + assert: + that: + # file command reports it created something + - "file6_result.changed == true" + # file command created a link + - 'file6_link_stat["stat"]["islnk"]' + # Link points to the right path + - 'file6_link_stat["stat"]["lnk_target"] == "/"' + # The link target and the file we intended to link to have the same inode + - 'file6_links_dest_stat["stat"]["inode"] == file6_dest_stat["stat"]["inode"]' + +# +# Test creating a relative link +# + +# Relative link to file +- name: create a test sub-directory to link to + file: + dest: '{{ remote_tmp_dir_test }}/sub1' + state: 'directory' + +- name: create a file to link to in the test sub-directory + file: + dest: '{{ remote_tmp_dir_test }}/sub1/file1' + state: 'touch' + +- name: create another test sub-directory to place links within + file: + dest: '{{remote_tmp_dir_test}}/sub2' + state: 'directory' + +- name: create soft link to relative file + file: + src: '../sub1/file1' + dest: '{{ remote_tmp_dir_test }}/sub2/link1' + state: 'link' + register: file7_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/sub2/link1' + follow: False + register: file7_link_stat + +- name: Get stat info for the pointed to file + stat: + path: '{{ remote_tmp_dir_test }}/sub2/link1' + follow: True + register: file7_links_dest_stat + +- name: Get stat info for the file we intend to point to + stat: + path: '{{ remote_tmp_dir_test }}/sub1/file1' + follow: False + register: file7_dest_stat + +- name: verify that the link was created correctly + assert: + that: + # file command reports it created something + - "file7_result.changed == true" + # file command created a link + - 'file7_link_stat["stat"]["islnk"]' + # Link points to the right path + - 'file7_link_stat["stat"]["lnk_target"] == "../sub1/file1"' + # The link target and the file we intended to link to have the same inode + - 'file7_links_dest_stat["stat"]["inode"] == file7_dest_stat["stat"]["inode"]' + +# Relative link to directory +- name: create soft link to relative directory + file: + src: sub1 + dest: '{{ remote_tmp_dir_test }}/sub1-link' + state: 'link' + register: file8_result + +- name: Get stat info for the link + stat: + path: '{{ remote_tmp_dir_test }}/sub1-link' + follow: False + register: file8_link_stat + +- name: Get stat info for the pointed to file + stat: + path: '{{ remote_tmp_dir_test }}/sub1-link' + follow: True + register: file8_links_dest_stat + +- name: Get stat info for the file we intend to point to + stat: + path: '{{ remote_tmp_dir_test }}/sub1' + follow: False + register: file8_dest_stat + +- name: verify that the link was created correctly + assert: + that: + # file command reports it created something + - "file8_result.changed == true" + # file command created a link + - 'file8_link_stat["stat"]["islnk"]' + # Link points to the right path + - 'file8_link_stat["stat"]["lnk_target"] == "sub1"' + # The link target and the file we intended to link to have the same inode + - 'file8_links_dest_stat["stat"]["inode"] == file8_dest_stat["stat"]["inode"]' + +# test the file module using follow=yes, so that the target of a +# symlink is modified, rather than the link itself + +- name: create a test file + copy: + dest: '{{remote_tmp_dir_test}}/test_follow' + content: 'this is a test file\n' + mode: 0666 + +- name: create a symlink to the test file + file: + path: '{{remote_tmp_dir_test}}/test_follow_link' + src: './test_follow' + state: 'link' + +- name: modify the permissions on the link using follow=yes + file: + path: '{{remote_tmp_dir_test}}/test_follow_link' + mode: 0644 + follow: yes + register: file9_result + +- name: stat the link target + stat: + path: '{{remote_tmp_dir_test}}/test_follow' + register: file9_stat + +- name: assert that the chmod worked + assert: + that: + - 'file9_result is changed' + - 'file9_stat["stat"]["mode"] == "0644"' + +# +# Test modifying the permissions of a link itself +# +- name: attempt to modify the permissions of the link itself + file: + path: '{{remote_tmp_dir_test}}/test_follow_link' + state: 'link' + mode: 0600 + follow: False + register: file10_result + +# Whether the link itself changed is platform dependent! (BSD vs Linux?) +# Just check that the underlying file was not changed +- name: stat the link target + stat: + path: '{{remote_tmp_dir_test}}/test_follow' + register: file10_target_stat + +- name: assert that the link target was unmodified + assert: + that: + - 'file10_target_stat["stat"]["mode"] == "0644"' + + +# https://github.com/ansible/ansible/issues/56928 +- block: + + - name: Create a testing file + file: + path: "{{ remote_tmp_dir_test }}/test_follow1" + state: touch + + - name: Create a symlink and change mode of the original file, since follow == yes by default + file: + src: "{{ remote_tmp_dir_test }}/test_follow1" + dest: "{{ remote_tmp_dir_test }}/test_follow1_link" + state: link + mode: 0700 + + - name: stat the original file + stat: + path: "{{ remote_tmp_dir_test }}/test_follow1" + register: stat_out + + - name: Check if the mode of the original file was set + assert: + that: + - 'stat_out.stat.mode == "0700"' + + always: + - name: Clean up + file: + path: "{{ item }}" + state: absent + loop: + - "{{ remote_tmp_dir_test }}/test_follow1" + - "{{ remote_tmp_dir_test }}/test_follow1_link" + +# END #56928 + + +# Test failure with src and no state parameter +- name: Specify src without state + file: + src: "{{ output_file }}" + dest: "{{ remote_tmp_dir_test }}/link.txt" + ignore_errors: yes + register: src_state + +- name: Ensure src without state failed + assert: + that: + - src_state is failed + - "'src option requires state to be' in src_state.msg" + +- name: Create without src + file: + state: link + dest: "{{ output_dir }}/link.txt" + ignore_errors: yes + register: create_without_src + +- name: Ensure create without src failed + assert: + that: + - create_without_src is failed + - "'src is required' in create_without_src.msg" + +# Test creating a symlink when the destination exists and is a file +- name: create a test file + copy: + dest: '{{ remote_tmp_dir_test }}/file.txt' + content: 'this is a test file\n' + mode: 0666 + +- name: Create a symlink with dest already a file + file: + src: '{{ output_file }}' + dest: '{{ remote_tmp_dir_test }}/file.txt' + state: link + ignore_errors: true + register: dest_is_existing_file_fail + +- name: Stat to make sure the symlink was not created + stat: + path: '{{ remote_tmp_dir_test }}/file.txt' + follow: false + register: dest_is_existing_file_fail_stat + +- name: Forcefully a symlink with dest already a file + file: + src: '{{ output_file }}' + dest: '{{ remote_tmp_dir_test }}/file.txt' + state: link + force: true + register: dest_is_existing_file_force + +- name: Stat to make sure the symlink was created + stat: + path: '{{ remote_tmp_dir_test }}/file.txt' + follow: false + register: dest_is_existing_file_force_stat + +- assert: + that: + - dest_is_existing_file_fail is failed + - not dest_is_existing_file_fail_stat.stat.islnk + - dest_is_existing_file_force is changed + - dest_is_existing_file_force_stat.stat.exists + - dest_is_existing_file_force_stat.stat.islnk |