From 0399960e34a5476fdb823064d03ff2fdc17cce91 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 6 Aug 2020 12:37:56 -0400 Subject: [PATCH] [stable-2.9] unarchive - Check 'fut_gid' against 'run_gid' in addition to supplemental groups (#65666) (#71002) * [stable-2.9] unarchive - Check 'fut_gid' against 'run_gid' in addition to supplemental groups (#65666) Add integration tests for unarchiving as unprivileged user Break tasks into separate files for easier reading and maintenance Create a user by specifying a default group of 'staff' for macOS. The user module does not actually remove the user directory on macOS, so explicitly remove it. Put the removal tasks in an always block to ensure they always run Co-authored-by: Philip Douglass Co-authored-by: Sam Doran . (cherry picked from commit ac5f3f8befaff088450c97f783cb145519b8f6bf) Co-authored-by: Philip Douglass * [stable-2.9] Fix unstable unarchive test (#71004) * Add mode to copy tasks * Fix unreliable test by ignoring errors (cherry picked from commit f99f96ceb63fd2251f4286a2da2e10a9031d241e) Co-authored-by: Philip Douglass --- ...chive-check-future-gid-against-run-gid.yml | 2 + lib/ansible/modules/files/unarchive.py | 2 +- .../targets/unarchive/tasks/main.yml | 666 +----------------- .../targets/unarchive/tasks/prepare_tests.yml | 92 +++ .../targets/unarchive/tasks/test_download.yml | 34 + .../targets/unarchive/tasks/test_exclude.yml | 48 ++ .../unarchive/tasks/test_missing_files.yml | 47 ++ .../targets/unarchive/tasks/test_mode.yml | 151 ++++ .../tasks/test_non_ascii_filename.yml | 66 ++ .../tasks/test_parent_not_writeable.yml | 32 + .../tasks/test_quotable_characters.yml | 38 + .../targets/unarchive/tasks/test_symlink.yml | 64 ++ .../targets/unarchive/tasks/test_tar.yml | 26 + .../targets/unarchive/tasks/test_tar_gz.yml | 28 + .../unarchive/tasks/test_tar_gz_creates.yml | 53 ++ .../tasks/test_tar_gz_keep_newer.yml | 57 ++ .../tasks/test_tar_gz_owner_group.yml | 48 ++ .../tasks/test_unprivileged_user.yml | 86 +++ .../targets/unarchive/tasks/test_zip.yml | 45 ++ 19 files changed, 934 insertions(+), 651 deletions(-) create mode 100644 changelogs/fragments/unarchive-check-future-gid-against-run-gid.yml create mode 100644 test/integration/targets/unarchive/tasks/prepare_tests.yml create mode 100644 test/integration/targets/unarchive/tasks/test_download.yml create mode 100644 test/integration/targets/unarchive/tasks/test_exclude.yml create mode 100644 test/integration/targets/unarchive/tasks/test_missing_files.yml create mode 100644 test/integration/targets/unarchive/tasks/test_mode.yml create mode 100644 test/integration/targets/unarchive/tasks/test_non_ascii_filename.yml create mode 100644 test/integration/targets/unarchive/tasks/test_parent_not_writeable.yml create mode 100644 test/integration/targets/unarchive/tasks/test_quotable_characters.yml create mode 100644 test/integration/targets/unarchive/tasks/test_symlink.yml create mode 100644 test/integration/targets/unarchive/tasks/test_tar.yml create mode 100644 test/integration/targets/unarchive/tasks/test_tar_gz.yml create mode 100644 test/integration/targets/unarchive/tasks/test_tar_gz_creates.yml create mode 100644 test/integration/targets/unarchive/tasks/test_tar_gz_keep_newer.yml create mode 100644 test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml create mode 100644 test/integration/targets/unarchive/tasks/test_unprivileged_user.yml create mode 100644 test/integration/targets/unarchive/tasks/test_zip.yml diff --git a/changelogs/fragments/unarchive-check-future-gid-against-run-gid.yml b/changelogs/fragments/unarchive-check-future-gid-against-run-gid.yml new file mode 100644 index 00000000000..2b0ed71892c --- /dev/null +++ b/changelogs/fragments/unarchive-check-future-gid-against-run-gid.yml @@ -0,0 +1,2 @@ +bugfixes: + - unarchive - check ``fut_gid`` against ``run_gid`` in addition to supplemental groups (https://github.com/ansible/ansible/issues/49284) diff --git a/lib/ansible/modules/files/unarchive.py b/lib/ansible/modules/files/unarchive.py index 03d6a5bcc47..994ae776ea1 100644 --- a/lib/ansible/modules/files/unarchive.py +++ b/lib/ansible/modules/files/unarchive.py @@ -567,7 +567,7 @@ class ZipArchive(object): except (KeyError, ValueError, OverflowError): gid = st.st_gid - if run_uid != 0 and fut_gid not in groups: + if run_uid != 0 and (fut_group != run_group or fut_gid != run_gid) and fut_gid not in groups: raise UnarchiveError('Cannot change group ownership of %s to %s, as user %s' % (path, fut_group, run_owner)) if group and group != fut_group: diff --git a/test/integration/targets/unarchive/tasks/main.yml b/test/integration/targets/unarchive/tasks/main.yml index 9794e6a8006..7051539c63e 100644 --- a/test/integration/targets/unarchive/tasks/main.yml +++ b/test/integration/targets/unarchive/tasks/main.yml @@ -1,650 +1,16 @@ -# Test code for the unarchive module. -# (c) 2014, Richard Isaacson - -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . -# Make sure we start fresh - -# Need unzip for unarchive module, and zip for archive creation. -- name: Ensure zip and unzip is present to create test archive (yum) - yum: name=zip,unzip state=latest - when: ansible_pkg_mgr == 'yum' - -- name: Ensure zip is present to create test archive (dnf) - dnf: name=zip state=latest - when: ansible_pkg_mgr == 'dnf' - -- name: Ensure zip & unzip is present to create test archive (apt) - apt: name=zip,unzip state=latest - when: ansible_pkg_mgr == 'apt' - -- name: Ensure zip & unzip is present to create test archive (pkg) - pkgng: name=zip,unzip state=present - when: ansible_pkg_mgr == 'pkgng' - -- name: prep our file - copy: src=foo.txt dest={{remote_tmp_dir}}/foo-unarchive.txt - -- name: prep a tar file - shell: tar cvf test-unarchive.tar foo-unarchive.txt chdir={{remote_tmp_dir}} - -- name: prep a tar.gz file - shell: tar czvf test-unarchive.tar.gz foo-unarchive.txt chdir={{remote_tmp_dir}} - -- name: prep a chmodded file for zip - copy: src=foo.txt dest={{remote_tmp_dir}}/foo-unarchive-777.txt mode=0777 - -- name: prep a windows permission file for our zip - copy: src=foo.txt dest={{remote_tmp_dir}}/FOO-UNAR.TXT - -# This gets around an unzip timestamp bug in some distributions -# Recent unzip on Ubuntu and BSD will randomly round some timestamps up. -# But that doesn't seem to happen when the timestamp has an even second. -- name: Bug work around - command: touch -t "201705111530.00" {{remote_tmp_dir}}/foo-unarchive.txt {{remote_tmp_dir}}/foo-unarchive-777.txt {{remote_tmp_dir}}/FOO-UNAR.TXT -# See Ubuntu bug 1691636: https://bugs.launchpad.net/ubuntu/+source/unzip/+bug/1691636 -# When these are fixed, this code should be removed. - -- name: prep a zip file - shell: zip test-unarchive.zip foo-unarchive.txt foo-unarchive-777.txt chdir={{remote_tmp_dir}} - -- name: Prepare - Create test dirs - file: - path: "{{remote_tmp_dir}}/{{item}}" - state: directory - with_items: - - created/include - - created/exclude - - created/other - -- name: Prepare - Create test files - file: - path: "{{remote_tmp_dir}}/created/{{item}}" - state: touch - with_items: - - include/include-1.txt - - include/include-2.txt - - include/include-3.txt - - exclude/exclude-1.txt - - exclude/exclude-2.txt - - exclude/exclude-3.txt - - other/include-1.ext - - other/include-2.ext - - other/exclude-1.ext - - other/exclude-2.ext - - other/other-1.ext - - other/other-2.ext - -- name: Prepare - zip file - shell: zip -r {{remote_tmp_dir}}/unarchive-00.zip * chdir={{remote_tmp_dir}}/created/ - -- name: Prepare - tar file - shell: tar czvf {{remote_tmp_dir}}/unarchive-00.tar * chdir={{remote_tmp_dir}}/created/ - -- name: add a file with Windows permissions to zip file - shell: zip -k test-unarchive.zip FOO-UNAR.TXT chdir={{remote_tmp_dir}} - -- name: prep a subdirectory - file: path={{remote_tmp_dir}}/unarchive-dir state=directory - -- name: prep our file - copy: src=foo.txt dest={{remote_tmp_dir}}/unarchive-dir/foo-unarchive.txt - -- name: prep a tar.gz file with directory - shell: tar czvf test-unarchive-dir.tar.gz unarchive-dir chdir={{remote_tmp_dir}} - -- name: create our tar unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar state=directory - -- name: unarchive a tar file - unarchive: src={{remote_tmp_dir}}/test-unarchive.tar dest="{{remote_tmp_dir}}/test-unarchive-tar" remote_src=yes - register: unarchive01 - -- name: verify that the file was marked as changed - assert: - that: - - "unarchive01.changed == true" - -- name: verify that the file was unarchived - file: path={{remote_tmp_dir}}/test-unarchive-tar/foo-unarchive.txt state=file - -- name: remove our tar unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar state=absent - -- name: create our tar.gz unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive a tar.gz file - unarchive: src={{remote_tmp_dir}}/test-unarchive.tar.gz dest={{remote_tmp_dir}}/test-unarchive-tar-gz remote_src=yes - register: unarchive02 - -- name: verify that the file was marked as changed - assert: - that: - - "unarchive02.changed == true" - # Verify that no file list is generated - - "'files' not in unarchive02" - -- name: verify that the file was unarchived - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt state=file - -- name: remove our tar.gz unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=absent - -- name: create our tar.gz unarchive destination for creates - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive a tar.gz file with creates set - unarchive: src={{remote_tmp_dir}}/test-unarchive.tar.gz dest={{remote_tmp_dir}}/test-unarchive-tar-gz remote_src=yes creates={{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt - register: unarchive02b - -- name: verify that the file was marked as changed - assert: - that: - - "unarchive02b.changed == true" - -- name: verify that the file was unarchived - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt state=file - -- name: unarchive a tar.gz file with creates over an existing file - unarchive: src={{remote_tmp_dir}}/test-unarchive.tar.gz dest={{remote_tmp_dir}}/test-unarchive-tar-gz remote_src=yes creates={{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt - register: unarchive02c - -- name: verify that the file was not marked as changed - assert: - that: - - "unarchive02c.changed == false" - -- name: unarchive a tar.gz file with creates over an existing file using complex_args - unarchive: - src: "{{remote_tmp_dir}}/test-unarchive.tar.gz" - dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz" - remote_src: yes - creates: "{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt" - register: unarchive02d - -- name: verify that the file was not marked as changed - assert: - that: - - "unarchive02d.changed == false" - -- name: remove our tar.gz unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=absent - -- name: create our zip unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-zip state=directory - -- name: unarchive a zip file - unarchive: src={{remote_tmp_dir}}/test-unarchive.zip dest={{remote_tmp_dir}}/test-unarchive-zip remote_src=yes list_files=True - register: unarchive03 - -- name: verify that the file was marked as changed - assert: - that: - - "unarchive03.changed == true" - # Verify that file list is generated - - "'files' in unarchive03" - - "{{unarchive03['files']| length}} == 3" - - "'foo-unarchive.txt' in unarchive03['files']" - - "'foo-unarchive-777.txt' in unarchive03['files']" - - "'FOO-UNAR.TXT' in unarchive03['files']" - -- name: verify that the file was unarchived - file: path={{remote_tmp_dir}}/test-unarchive-zip/{{item}} state=file - with_items: - - foo-unarchive.txt - - foo-unarchive-777.txt - - FOO-UNAR.TXT - -- name: repeat the last request to verify no changes - unarchive: src={{remote_tmp_dir}}/test-unarchive.zip dest={{remote_tmp_dir}}/test-unarchive-zip remote_src=yes list_files=True - register: unarchive03b - -- name: verify that the task was not marked as changed - assert: - that: - - "unarchive03b.changed == false" - -- name: "Create {{ remote_tmp_dir }}/exclude directory" - file: - state: directory - path: "{{ remote_tmp_dir }}/exclude-{{item}}" - with_items: - - zip - - tar - -- name: Unpack archive file excluding regular and glob files. - unarchive: - src: "{{ remote_tmp_dir }}/unarchive-00.{{item}}" - dest: "{{ remote_tmp_dir }}/exclude-{{item}}" - remote_src: yes - exclude: - - "exclude/exclude-*.txt" - - "other/exclude-1.ext" - with_items: - - zip - - tar - -- name: verify that the file was unarchived - shell: find {{ remote_tmp_dir }}/exclude-{{item}} chdir={{ remote_tmp_dir }} - register: unarchive00 - with_items: - - zip - - tar - -- name: verify that archive extraction excluded the files - assert: - that: - - "'exclude/exclude-1.txt' not in item.stdout" - - "'other/exclude-1.ext' not in item.stdout" - with_items: - - "{{ unarchive00.results }}" - -- name: remove our zip unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-zip state=absent - -- name: remove our test files for the archive - file: path={{remote_tmp_dir}}/{{item}} state=absent - with_items: - - foo-unarchive.txt - - foo-unarchive-777.txt - - FOO-UNAR.TXT - -- name: check if /tmp/foo-unarchive.text exists - stat: path=/tmp/foo-unarchive.txt - ignore_errors: True - register: unarchive04 - -- name: fail if the proposed destination file exists for safey - fail: msg="/tmp/foo-unarchive.txt already exists, aborting" - when: unarchive04.stat.exists - -- name: try unarchiving to /tmp - unarchive: src={{remote_tmp_dir}}/test-unarchive.tar.gz dest=/tmp remote_src=yes - register: unarchive05 - -- name: verify that the file was marked as changed - assert: - that: - - "unarchive05.changed == true" - -- name: verify that the file was unarchived - file: path=/tmp/foo-unarchive.txt state=file - -- name: remove our unarchive destination - file: path=/tmp/foo-unarchive.txt state=absent - -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive and set mode to 0600, directories 0700 - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - remote_src: yes - mode: "u+rwX,g-rwx,o-rwx" - list_files: True - register: unarchive06 - -- name: Test that the file modes were changed - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" - register: unarchive06_stat - -- name: Test that the file modes were changed - assert: - that: - - "unarchive06.changed == true" - - "unarchive06_stat.stat.mode == '0600'" - # Verify that file list is generated - - "'files' in unarchive06" - - "{{unarchive06['files']| length}} == 1" - - "'foo-unarchive.txt' in unarchive06['files']" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent - -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive over existing extraction and set mode to 0644 - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - remote_src: yes - mode: "u+rwX,g-wx,o-wx,g+r,o+r" - register: unarchive06_2 - -- name: Test that the file modes were changed - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" - register: unarchive06_2_stat - -- debug: var=unarchive06_2_stat.stat.mode -- name: Test that the files were changed - assert: - that: - - "unarchive06_2.changed == true" - - "unarchive06_2_stat.stat.mode == '0644'" - -- name: Repeat the last request to verify no changes - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - remote_src: yes - mode: "u+rwX-x,g-wx,o-wx,g+r,o+r" - list_files: True - register: unarchive07 - -- name: Test that the files were not changed - assert: - that: - - "unarchive07.changed == false" - # Verify that file list is generated - - "'files' in unarchive07" - - "{{unarchive07['files']| length}} == 1" - - "'foo-unarchive.txt' in unarchive07['files']" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent - -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-zip state=directory - -- name: unarchive and set mode to 0601, directories 0700 - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.zip" - dest: "{{ remote_tmp_dir }}/test-unarchive-zip" - remote_src: yes - mode: "u+rwX-x,g-rwx,o=x" - list_files: True - register: unarchive08 - -- name: Test that the file modes were changed - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-zip/foo-unarchive.txt" - register: unarchive08_stat - -- name: Test that the file modes were changed - assert: - that: - - "unarchive08.changed == true" - - "unarchive08_stat.stat.mode == '0601'" - # Verify that file list is generated - - "'files' in unarchive08" - - "{{unarchive08['files']| length}} == 3" - - "'foo-unarchive.txt' in unarchive08['files']" - - "'foo-unarchive-777.txt' in unarchive08['files']" - - "'FOO-UNAR.TXT' in unarchive08['files']" - -- name: unarchive zipfile a second time and set mode to 0601, directories 0700 - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.zip" - dest: "{{ remote_tmp_dir }}/test-unarchive-zip" - remote_src: yes - mode: "u+rwX-x,g-rwx,o=x" - list_files: True - register: unarchive08 - -- name: Test that the file modes were not changed - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-zip/foo-unarchive.txt" - register: unarchive08_stat - -- debug: - var: unarchive08 - -- debug: - var: unarchive08_stat - -- name: Test that the files did not change - assert: - that: - - "unarchive08.changed == false" - - "unarchive08_stat.stat.mode == '0601'" - # Verify that file list is generated - - "'files' in unarchive08" - - "{{unarchive08['files']| length}} == 3" - - "'foo-unarchive.txt' in unarchive08['files']" - - "'foo-unarchive-777.txt' in unarchive08['files']" - - "'FOO-UNAR.TXT' in unarchive08['files']" - -- name: remove our zip unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-zip state=absent - -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: create a directory with quotable chars - file: path="{{ remote_tmp_dir }}/test-quotes~root" state=directory - -- name: unarchive into directory with quotable chars - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/test-quotes~root" - remote_src: yes - register: unarchive08 - -- name: Test that unarchive succeeded - assert: - that: - - "unarchive08.changed == true" - -- name: unarchive into directory with quotable chars a second time - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/test-quotes~root" - remote_src: yes - register: unarchive09 - -- name: Test that unarchive did nothing - assert: - that: - - "unarchive09.changed == false" - -- name: remove quotable chars test - file: path="{{ remote_tmp_dir }}/test-quotes~root" state=absent - -- name: create our unarchive destination - file: - path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" - state: directory - -- name: test that unarchive works with an archive that contains non-ascii filenames - unarchive: - # Both the filename of the tarball and the filename inside the tarball have - # nonascii chars - src: "test-unarchive-nonascii-くらとみ.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" - mode: "u+rwX,go+rX" - remote_src: no - register: nonascii_result0 - -- name: Check that file is really there - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz/storage/àâæçéèïîôœ(copy)!@#$%^&-().jpg" - register: nonascii_stat0 - -- name: Assert that nonascii tests succeeded - assert: - that: - - "nonascii_result0.changed == true" - - "nonascii_stat0.stat.exists == true" - -- name: remove nonascii test - file: path="{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" state=absent - -- name: test non-ascii with different LC_ALL - block: - - name: create our unarchive destination - file: - path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" - state: directory - - - name: test that unarchive works with an archive that contains non-ascii filenames - unarchive: - # Both the filename of the tarball and the filename inside the tarball have - # nonascii chars - src: "test-unarchive-nonascii-くらとみ.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" - mode: "u+rwX,go+rX" - remote_src: no - register: nonascii_result0 - - - name: Check that file is really there - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz/storage/àâæçéèïîôœ(copy)!@#$%^&-().jpg" - register: nonascii_stat0 - - - name: Assert that nonascii tests succeeded - assert: - that: - - "nonascii_result0.changed == true" - - "nonascii_stat0.stat.exists == true" - - - name: remove nonascii test - file: path="{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" state=absent - - environment: - LC_ALL: C - -# Test that unarchiving is performed if files are missing -# https://github.com/ansible/ansible-modules-core/issues/1064 -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive a tar that has directories - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive-dir.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - mode: "0700" - remote_src: yes - register: unarchive10 - -- name: Test that unarchive succeeded - assert: - that: - - "unarchive10.changed == true" - -- name: Change the mode of the toplevel dir - file: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/unarchive-dir" - mode: 0701 - -- name: Remove a file from the extraction point - file: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/unarchive-dir/foo-unarchive.txt" - state: absent - -- name: unarchive a tar that has directories - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive-dir.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - mode: "0700" - remote_src: yes - register: unarchive10_1 - -- name: Test that unarchive succeeded - assert: - that: - - "unarchive10_1.changed == true" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent - -# -# Symlink tests -# - -- name: Create a destination dir - file: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - state: directory - -- name: Create a symlink to the detination dir - file: - path: "{{ remote_tmp_dir }}/link-to-unarchive-dir" - src: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - state: "link" - -- name: test that unarchive works when dest is a symlink to a dir - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/link-to-unarchive-dir" - mode: "u+rwX,go+rX" - remote_src: yes - register: unarchive_11 - -- name: Check that file is really there - stat: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" - register: unarchive11_stat0 - -- name: Assert that unarchive when dest is a symlink to a dir worked - assert: - that: - - "unarchive_11.changed == true" - - "unarchive11_stat0.stat.exists == true" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent - -- name: Create a file - file: - path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - state: touch - -- name: Create a symlink to the file - file: - path: "{{ remote_tmp_dir }}/link-to-unarchive-file" - src: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - state: "link" - -- name: test that unarchive fails when dest is a link to a file - unarchive: - src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" - dest: "{{ remote_tmp_dir }}/link-to-unarchive-file" - mode: "u+rwX,go+rX" - remote_src: yes - ignore_errors: True - register: unarchive_12 - -- name: Assert that unarchive when dest is a file failed - assert: - that: - - "unarchive_12.failed == true" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent - -# Test downloading a file before unarchiving it -- name: create our unarchive destination - file: path={{remote_tmp_dir}}/test-unarchive-tar-gz state=directory - -- name: unarchive a tar from an URL - unarchive: - src: "https://releases.ansible.com/ansible/ansible-latest.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - mode: "0700" - remote_src: yes - register: unarchive13 - -- name: Test that unarchive succeeded - assert: - that: - - "unarchive13.changed == true" - -- name: remove our tar.gz unarchive destination - file: path={{ remote_tmp_dir }}/test-unarchive-tar-gz state=absent +- import_tasks: prepare_tests.yml +- import_tasks: test_tar.yml +- import_tasks: test_tar_gz.yml +- import_tasks: test_tar_gz_creates.yml +- import_tasks: test_tar_gz_owner_group.yml +- import_tasks: test_tar_gz_keep_newer.yml +- import_tasks: test_zip.yml +- import_tasks: test_exclude.yml +- import_tasks: test_parent_not_writeable.yml +- import_tasks: test_mode.yml +- import_tasks: test_quotable_characters.yml +- import_tasks: test_non_ascii_filename.yml +- import_tasks: test_missing_files.yml +- import_tasks: test_symlink.yml +- import_tasks: test_download.yml +- import_tasks: test_unprivileged_user.yml diff --git a/test/integration/targets/unarchive/tasks/prepare_tests.yml b/test/integration/targets/unarchive/tasks/prepare_tests.yml new file mode 100644 index 00000000000..783d77d3246 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/prepare_tests.yml @@ -0,0 +1,92 @@ +# Need unzip for unarchive module, and zip for archive creation. +- name: Ensure zip & unzip are present + package: + name: + - zip + - unzip + when: ansible_pkg_mgr in ('yum', 'dnf', 'apt', 'pkgng') + +- name: prep our file + copy: + src: foo.txt + dest: "{{remote_tmp_dir}}/foo-unarchive.txt" + mode: preserve + +- name: prep a tar file + shell: tar cvf test-unarchive.tar foo-unarchive.txt chdir={{remote_tmp_dir}} + +- name: prep a tar.gz file + shell: tar czvf test-unarchive.tar.gz foo-unarchive.txt chdir={{remote_tmp_dir}} + +- name: prep a chmodded file for zip + copy: + src: foo.txt + dest: '{{remote_tmp_dir}}/foo-unarchive-777.txt' + mode: '0777' + +- name: prep a windows permission file for our zip + copy: + src: foo.txt + dest: '{{remote_tmp_dir}}/FOO-UNAR.TXT' + mode: preserve + +# This gets around an unzip timestamp bug in some distributions +# Recent unzip on Ubuntu and BSD will randomly round some timestamps up. +# But that doesn't seem to happen when the timestamp has an even second. +- name: Bug work around + command: touch -t "201705111530.00" {{remote_tmp_dir}}/foo-unarchive.txt {{remote_tmp_dir}}/foo-unarchive-777.txt {{remote_tmp_dir}}/FOO-UNAR.TXT +# See Ubuntu bug 1691636: https://bugs.launchpad.net/ubuntu/+source/unzip/+bug/1691636 +# When these are fixed, this code should be removed. + +- name: prep a zip file + shell: zip test-unarchive.zip foo-unarchive.txt foo-unarchive-777.txt chdir={{remote_tmp_dir}} + +- name: Prepare - Create test dirs + file: + path: "{{remote_tmp_dir}}/{{item}}" + state: directory + with_items: + - created/include + - created/exclude + - created/other + +- name: Prepare - Create test files + file: + path: "{{remote_tmp_dir}}/created/{{item}}" + state: touch + with_items: + - include/include-1.txt + - include/include-2.txt + - include/include-3.txt + - exclude/exclude-1.txt + - exclude/exclude-2.txt + - exclude/exclude-3.txt + - other/include-1.ext + - other/include-2.ext + - other/exclude-1.ext + - other/exclude-2.ext + - other/other-1.ext + - other/other-2.ext + +- name: Prepare - zip file + shell: zip -r {{remote_tmp_dir}}/unarchive-00.zip * chdir={{remote_tmp_dir}}/created/ + +- name: Prepare - tar file + shell: tar czvf {{remote_tmp_dir}}/unarchive-00.tar * chdir={{remote_tmp_dir}}/created/ + +- name: add a file with Windows permissions to zip file + shell: zip -k test-unarchive.zip FOO-UNAR.TXT chdir={{remote_tmp_dir}} + +- name: prep a subdirectory + file: + path: '{{remote_tmp_dir}}/unarchive-dir' + state: directory + +- name: prep our file + copy: + src: foo.txt + dest: '{{remote_tmp_dir}}/unarchive-dir/foo-unarchive.txt' + mode: preserve + +- name: prep a tar.gz file with directory + shell: tar czvf test-unarchive-dir.tar.gz unarchive-dir chdir={{remote_tmp_dir}} diff --git a/test/integration/targets/unarchive/tasks/test_download.yml b/test/integration/targets/unarchive/tasks/test_download.yml new file mode 100644 index 00000000000..6b17449bf9f --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_download.yml @@ -0,0 +1,34 @@ +# Test downloading a file before unarchiving it +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: Install packages to make TLS connections work on CentOS 6 + pip: + name: + - urllib3==1.10.2 + - ndg_httpsclient==0.4.4 + - pyOpenSSL==16.2.0 + state: present + when: + - ansible_facts.distribution == 'CentOS' + - not ansible_facts.python.has_sslcontext + +- name: unarchive a tar from an URL + unarchive: + src: "https://releases.ansible.com/ansible/ansible-latest.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + mode: "0700" + remote_src: yes + register: unarchive13 + +- name: Test that unarchive succeeded + assert: + that: + - "unarchive13.changed == true" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_exclude.yml b/test/integration/targets/unarchive/tasks/test_exclude.yml new file mode 100644 index 00000000000..be24756c0ae --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_exclude.yml @@ -0,0 +1,48 @@ +- name: "Create {{ remote_tmp_dir }}/exclude directory" + file: + state: directory + path: "{{ remote_tmp_dir }}/exclude-{{item}}" + with_items: + - zip + - tar + +- name: Unpack archive file excluding regular and glob files. + unarchive: + src: "{{ remote_tmp_dir }}/unarchive-00.{{item}}" + dest: "{{ remote_tmp_dir }}/exclude-{{item}}" + remote_src: yes + exclude: + - "exclude/exclude-*.txt" + - "other/exclude-1.ext" + with_items: + - zip + - tar + +- name: verify that the file was unarchived + shell: find {{ remote_tmp_dir }}/exclude-{{item}} chdir={{ remote_tmp_dir }} + register: unarchive00 + with_items: + - zip + - tar + +- name: verify that archive extraction excluded the files + assert: + that: + - "'exclude/exclude-1.txt' not in item.stdout" + - "'other/exclude-1.ext' not in item.stdout" + with_items: + - "{{ unarchive00.results }}" + +- name: remove our zip unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-zip' + state: absent + +- name: remove our test files for the archive + file: + path: '{{remote_tmp_dir}}/{{item}}' + state: absent + with_items: + - foo-unarchive.txt + - foo-unarchive-777.txt + - FOO-UNAR.TXT diff --git a/test/integration/targets/unarchive/tasks/test_missing_files.yml b/test/integration/targets/unarchive/tasks/test_missing_files.yml new file mode 100644 index 00000000000..4f57e184869 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_missing_files.yml @@ -0,0 +1,47 @@ +# Test that unarchiving is performed if files are missing +# https://github.com/ansible/ansible-modules-core/issues/1064 +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: unarchive a tar that has directories + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive-dir.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + mode: "0700" + remote_src: yes + register: unarchive10 + +- name: Test that unarchive succeeded + assert: + that: + - "unarchive10.changed == true" + +- name: Change the mode of the toplevel dir + file: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/unarchive-dir" + mode: "0701" + +- name: Remove a file from the extraction point + file: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/unarchive-dir/foo-unarchive.txt" + state: absent + +- name: unarchive a tar that has directories + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive-dir.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + mode: "0700" + remote_src: yes + register: unarchive10_1 + +- name: Test that unarchive succeeded + assert: + that: + - "unarchive10_1.changed == true" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_mode.yml b/test/integration/targets/unarchive/tasks/test_mode.yml new file mode 100644 index 00000000000..c69e3bd2b23 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_mode.yml @@ -0,0 +1,151 @@ +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: unarchive and set mode to 0600, directories 0700 + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + remote_src: yes + mode: "u+rwX,g-rwx,o-rwx" + list_files: True + register: unarchive06 + +- name: Test that the file modes were changed + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" + register: unarchive06_stat + +- name: Test that the file modes were changed + assert: + that: + - "unarchive06.changed == true" + - "unarchive06_stat.stat.mode == '0600'" + # Verify that file list is generated + - "'files' in unarchive06" + - "{{unarchive06['files']| length}} == 1" + - "'foo-unarchive.txt' in unarchive06['files']" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent + +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: unarchive over existing extraction and set mode to 0644 + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + remote_src: yes + mode: "u+rwX,g-wx,o-wx,g+r,o+r" + register: unarchive06_2 + +- name: Test that the file modes were changed + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" + register: unarchive06_2_stat + +- debug: + var: unarchive06_2_stat.stat.mode + +- name: Test that the files were changed + assert: + that: + - "unarchive06_2.changed == true" + - "unarchive06_2_stat.stat.mode == '0644'" + +- name: Repeat the last request to verify no changes + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + remote_src: yes + mode: "u+rwX-x,g-wx,o-wx,g+r,o+r" + list_files: True + register: unarchive07 + +- name: Test that the files were not changed + assert: + that: + - "unarchive07.changed == false" + # Verify that file list is generated + - "'files' in unarchive07" + - "{{unarchive07['files']| length}} == 1" + - "'foo-unarchive.txt' in unarchive07['files']" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent + +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-zip' + state: directory + +- name: unarchive and set mode to 0601, directories 0700 + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.zip" + dest: "{{ remote_tmp_dir }}/test-unarchive-zip" + remote_src: yes + mode: "u+rwX-x,g-rwx,o=x" + list_files: True + register: unarchive08 + +- name: Test that the file modes were changed + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-zip/foo-unarchive.txt" + register: unarchive08_stat + +- name: Test that the file modes were changed + assert: + that: + - "unarchive08.changed == true" + - "unarchive08_stat.stat.mode == '0601'" + # Verify that file list is generated + - "'files' in unarchive08" + - "{{unarchive08['files']| length}} == 3" + - "'foo-unarchive.txt' in unarchive08['files']" + - "'foo-unarchive-777.txt' in unarchive08['files']" + - "'FOO-UNAR.TXT' in unarchive08['files']" + +- name: unarchive zipfile a second time and set mode to 0601, directories 0700 + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.zip" + dest: "{{ remote_tmp_dir }}/test-unarchive-zip" + remote_src: yes + mode: "u+rwX-x,g-rwx,o=x" + list_files: True + register: unarchive08 + +- name: Test that the file modes were not changed + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-zip/foo-unarchive.txt" + register: unarchive08_stat + +- debug: + var: unarchive08 + +- debug: + var: unarchive08_stat + +- name: Test that the files did not change + assert: + that: + - "unarchive08.changed == false" + - "unarchive08_stat.stat.mode == '0601'" + # Verify that file list is generated + - "'files' in unarchive08" + - "{{unarchive08['files']| length}} == 3" + - "'foo-unarchive.txt' in unarchive08['files']" + - "'foo-unarchive-777.txt' in unarchive08['files']" + - "'FOO-UNAR.TXT' in unarchive08['files']" + +- name: remove our zip unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-zip' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_non_ascii_filename.yml b/test/integration/targets/unarchive/tasks/test_non_ascii_filename.yml new file mode 100644 index 00000000000..c884f49a219 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_non_ascii_filename.yml @@ -0,0 +1,66 @@ +- name: create our unarchive destination + file: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + state: directory + +- name: test that unarchive works with an archive that contains non-ascii filenames + unarchive: + # Both the filename of the tarball and the filename inside the tarball have + # nonascii chars + src: "test-unarchive-nonascii-くらとみ.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + mode: "u+rwX,go+rX" + remote_src: no + register: nonascii_result0 + +- name: Check that file is really there + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz/storage/àâæçéèïîôœ(copy)!@#$%^&-().jpg" + register: nonascii_stat0 + +- name: Assert that nonascii tests succeeded + assert: + that: + - "nonascii_result0.changed == true" + - "nonascii_stat0.stat.exists == true" + +- name: remove nonascii test + file: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + state: absent + +- name: test non-ascii with different LC_ALL + block: + - name: create our unarchive destination + file: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + state: directory + + - name: test that unarchive works with an archive that contains non-ascii filenames + unarchive: + # Both the filename of the tarball and the filename inside the tarball have + # nonascii chars + src: "test-unarchive-nonascii-くらとみ.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + mode: "u+rwX,go+rX" + remote_src: no + register: nonascii_result0 + + - name: Check that file is really there + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz/storage/àâæçéèïîôœ(copy)!@#$%^&-().jpg" + register: nonascii_stat0 + + - name: Assert that nonascii tests succeeded + assert: + that: + - "nonascii_result0.changed == true" + - "nonascii_stat0.stat.exists == true" + + - name: remove nonascii test + file: + path: "{{ remote_tmp_dir }}/test-unarchive-nonascii-くらとみ-tar-gz" + state: absent + + environment: + LC_ALL: C diff --git a/test/integration/targets/unarchive/tasks/test_parent_not_writeable.yml b/test/integration/targets/unarchive/tasks/test_parent_not_writeable.yml new file mode 100644 index 00000000000..bfb082c6aa7 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_parent_not_writeable.yml @@ -0,0 +1,32 @@ +- name: check if /tmp/foo-unarchive.text exists + stat: + path: /tmp/foo-unarchive.txt + ignore_errors: True + register: unarchive04 + +- name: fail if the proposed destination file exists for safey + fail: + msg: /tmp/foo-unarchive.txt already exists, aborting + when: unarchive04.stat.exists + +- name: try unarchiving to /tmp + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.tar.gz' + dest: /tmp + remote_src: true + register: unarchive05 + +- name: verify that the file was marked as changed + assert: + that: + - "unarchive05.changed == true" + +- name: verify that the file was unarchived + file: + path: /tmp/foo-unarchive.txt + state: file + +- name: remove our unarchive destination + file: + path: /tmp/foo-unarchive.txt + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_quotable_characters.yml b/test/integration/targets/unarchive/tasks/test_quotable_characters.yml new file mode 100644 index 00000000000..0a3c2cc3403 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_quotable_characters.yml @@ -0,0 +1,38 @@ +- name: create our unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: create a directory with quotable chars + file: + path: '{{ remote_tmp_dir }}/test-quotes~root' + state: directory + +- name: unarchive into directory with quotable chars + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/test-quotes~root" + remote_src: yes + register: unarchive08 + +- name: Test that unarchive succeeded + assert: + that: + - "unarchive08.changed == true" + +- name: unarchive into directory with quotable chars a second time + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/test-quotes~root" + remote_src: yes + register: unarchive09 + +- name: Test that unarchive did nothing + assert: + that: + - "unarchive09.changed == false" + +- name: remove quotable chars test + file: + path: '{{ remote_tmp_dir }}/test-quotes~root' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_symlink.yml b/test/integration/targets/unarchive/tasks/test_symlink.yml new file mode 100644 index 00000000000..fcb728282bf --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_symlink.yml @@ -0,0 +1,64 @@ +- name: Create a destination dir + file: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + state: directory + +- name: Create a symlink to the detination dir + file: + path: "{{ remote_tmp_dir }}/link-to-unarchive-dir" + src: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + state: "link" + +- name: test that unarchive works when dest is a symlink to a dir + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/link-to-unarchive-dir" + mode: "u+rwX,go+rX" + remote_src: yes + register: unarchive_11 + +- name: Check that file is really there + stat: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz/foo-unarchive.txt" + register: unarchive11_stat0 + +- name: Assert that unarchive when dest is a symlink to a dir worked + assert: + that: + - "unarchive_11.changed == true" + - "unarchive11_stat0.stat.exists == true" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent + +- name: Create a file + file: + path: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + state: touch + +- name: Create a symlink to the file + file: + src: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + path: "{{ remote_tmp_dir }}/link-to-unarchive-file" + state: "link" + +- name: test that unarchive fails when dest is a link to a file + unarchive: + src: "{{ remote_tmp_dir }}/test-unarchive.tar.gz" + dest: "{{ remote_tmp_dir }}/link-to-unarchive-file" + mode: "u+rwX,go+rX" + remote_src: yes + ignore_errors: True + register: unarchive_12 + +- name: Assert that unarchive when dest is a file failed + assert: + that: + - "unarchive_12.failed == true" + +- name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_tar.yml b/test/integration/targets/unarchive/tasks/test_tar.yml new file mode 100644 index 00000000000..09105c600e8 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_tar.yml @@ -0,0 +1,26 @@ +- name: create our tar unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar' + state: directory + +- name: unarchive a tar file + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.tar' + dest: '{{remote_tmp_dir}}/test-unarchive-tar' + remote_src: yes + register: unarchive01 + +- name: verify that the file was marked as changed + assert: + that: + - "unarchive01.changed == true" + +- name: verify that the file was unarchived + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar/foo-unarchive.txt' + state: file + +- name: remove our tar unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_tar_gz.yml b/test/integration/targets/unarchive/tasks/test_tar_gz.yml new file mode 100644 index 00000000000..ac9e9a15499 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_tar_gz.yml @@ -0,0 +1,28 @@ +- name: create our tar.gz unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: unarchive a tar.gz file + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.tar.gz' + dest: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + remote_src: yes + register: unarchive02 + +- name: verify that the file was marked as changed + assert: + that: + - "unarchive02.changed == true" + # Verify that no file list is generated + - "'files' not in unarchive02" + +- name: verify that the file was unarchived + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt' + state: file + +- name: remove our tar.gz unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_tar_gz_creates.yml b/test/integration/targets/unarchive/tasks/test_tar_gz_creates.yml new file mode 100644 index 00000000000..fa3a23f8b86 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_tar_gz_creates.yml @@ -0,0 +1,53 @@ +- name: create our tar.gz unarchive destination for creates + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: directory + +- name: unarchive a tar.gz file with creates set + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.tar.gz' + dest: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + creates: '{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt' + remote_src: yes + register: unarchive02b + +- name: verify that the file was marked as changed + assert: + that: + - "unarchive02b.changed == true" + +- name: verify that the file was unarchived + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt' + state: file + +- name: unarchive a tar.gz file with creates over an existing file + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.tar.gz' + dest: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + creates: '{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt' + remote_src: yes + register: unarchive02c + +- name: verify that the file was not marked as changed + assert: + that: + - "unarchive02c.changed == false" + +- name: unarchive a tar.gz file with creates over an existing file using complex_args + unarchive: + src: "{{remote_tmp_dir}}/test-unarchive.tar.gz" + dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + remote_src: yes + creates: "{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt" + register: unarchive02d + +- name: verify that the file was not marked as changed + assert: + that: + - "unarchive02d.changed == false" + +- name: remove our tar.gz unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_tar_gz_keep_newer.yml b/test/integration/targets/unarchive/tasks/test_tar_gz_keep_newer.yml new file mode 100644 index 00000000000..aec94545631 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_tar_gz_keep_newer.yml @@ -0,0 +1,57 @@ +- name: create our tar.gz unarchive destination for keep-newer + file: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + state: directory + +- name: Create a newer file that we would replace + copy: + dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt" + content: boo + mode: preserve + +- name: unarchive a tar.gz file but avoid overwriting newer files (keep_newer=true) + unarchive: + src: "{{remote_tmp_dir}}/test-unarchive.tar.gz" + dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + remote_src: yes + keep_newer: true + register: unarchive02f + +- name: Make sure the file still contains 'boo' + shell: cat {{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt + register: unarchive02f_cat + +- name: remove our tar.gz unarchive destination + file: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + state: absent + +- name: create our tar.gz unarchive destination for keep-newer (take 2) + file: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + state: directory + +- name: unarchive a tar.gz file and overwrite newer files (keep_newer=false) + unarchive: + src: "{{remote_tmp_dir}}/test-unarchive.tar.gz" + dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + remote_src: yes + keep_newer: false + register: unarchive02g + +- name: Make sure the file still contains 'boo' + shell: cat {{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt + register: unarchive02g_cat + +- name: remove our tar.gz unarchive destination + file: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + state: absent + +- name: verify results + assert: + that: + - unarchive02f is changed + - unarchive02f_cat.stdout == 'boo' + - unarchive02g is changed + - unarchive02g_cat.stdout != 'boo' diff --git a/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml b/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml new file mode 100644 index 00000000000..257692e1b13 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml @@ -0,0 +1,48 @@ +- block: + - name: Create a group to chown to + group: + name: testgroup + + - name: Create a user to chown to + user: + name: testuser + groups: + - testgroup + + - name: create our tar.gz unarchive destination for chown + file: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + state: directory + + - name: unarchive a tar.gz file with owner and group set to the above user + unarchive: + src: "{{remote_tmp_dir}}/test-unarchive.tar.gz" + dest: "{{remote_tmp_dir}}/test-unarchive-tar-gz" + remote_src: yes + owner: testuser + group: testgroup + register: unarchive02e + + - name: Stat a file in the directory we unarchived to + stat: + path: "{{remote_tmp_dir}}/test-unarchive-tar-gz/foo-unarchive.txt" + register: unarchive02e_file_stat + + - name: verify results + assert: + that: + - unarchive02e is changed + - unarchive02e_file_stat.stat.exists + - unarchive02e_file_stat.stat.pw_name == 'testuser' + - unarchive02e_file_stat.stat.gr_name == 'testgroup' + + always: + - name: Remove testuser + user: + name: testuser + state: absent + + - name: Remove testgroup + group: + name: testgroup + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml b/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml new file mode 100644 index 00000000000..6181e3bd628 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml @@ -0,0 +1,86 @@ +- name: Create unarchivetest1 user + user: + name: unarchivetest1 + uid: 1002610001 + group: "{{ group_table[ansible_facts['distribution']] | default(omit) }}" + register: user + vars: + group_table: + MacOSX: staff + +- name: Test unarchiving twice as unprivileged user + become: yes + become_user: unarchivetest1 + block: + - name: prep our file + copy: + src: foo.txt + dest: "{{ user.home }}/foo-unarchive.txt" + mode: preserve + + - name: Prep a zip file as unarchivetest1 user + shell: zip unarchivetest1-unarchive.zip foo-unarchive.txt + args: + chdir: "{{ user.home }}" + creates: "{{ user.home }}/unarchivetest1-unarchive.zip" + + - name: create our zip unarchive destination as unarchivetest1 user + file: + path: "{{ user.home }}/unarchivetest1-unarchive-zip" + state: directory + + - name: unarchive a zip file as unarchivetest1 user + unarchive: + src: "{{ user.home }}/unarchivetest1-unarchive.zip" + dest: "{{ user.home }}/unarchivetest1-unarchive-zip" + remote_src: yes + list_files: True + register: unarchive10 + + - name: stat the unarchived file + stat: + path: "{{ user.home }}/unarchivetest1-unarchive-zip/foo-unarchive.txt" + register: archive_path + + - name: verify that the tasks performed as expected + assert: + that: + - unarchive10 is changed + # Verify that file list is generated + - "'files' in unarchive10" + - "{{unarchive10['files']| length}} == 1" + - "'foo-unarchive.txt' in unarchive10['files']" + - archive_path.stat.exists + + - name: repeat the last request to verify no changes + unarchive: + src: "{{ user.home }}/unarchivetest1-unarchive.zip" + dest: "{{ user.home }}/unarchivetest1-unarchive-zip" + remote_src: yes + list_files: True + register: unarchive10b + + # Due to a bug in the date calculation used to determine if a change + # was made or not, this check is unreliable. This seems to only happen on + # Ubuntu 1604. + # https://github.com/ansible/ansible/blob/58145dff9ca1a713f8ed295a0076779a91c41cba/lib/ansible/modules/unarchive.py#L472-L474 + - name: Check that unarchiving again reports no change + assert: + that: + - unarchive10b is not changed + ignore_errors: yes + + always: + - name: remove our unarchivetest1 user and files + user: + name: unarchivetest1 + state: absent + remove: yes + become: no + + - name: Remove user home directory on macOS + file: + path: /Users/unarchivetest1 + state: absent + become: no + when: ansible_facts.distribution == 'MacOSX' diff --git a/test/integration/targets/unarchive/tasks/test_zip.yml b/test/integration/targets/unarchive/tasks/test_zip.yml new file mode 100644 index 00000000000..aae57d8ec90 --- /dev/null +++ b/test/integration/targets/unarchive/tasks/test_zip.yml @@ -0,0 +1,45 @@ +- name: create our zip unarchive destination + file: + path: '{{remote_tmp_dir}}/test-unarchive-zip' + state: directory + +- name: unarchive a zip file + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.zip' + dest: '{{remote_tmp_dir}}/test-unarchive-zip' + list_files: True + remote_src: yes + register: unarchive03 + +- name: verify that the file was marked as changed + assert: + that: + - "unarchive03.changed == true" + # Verify that file list is generated + - "'files' in unarchive03" + - "{{unarchive03['files']| length}} == 3" + - "'foo-unarchive.txt' in unarchive03['files']" + - "'foo-unarchive-777.txt' in unarchive03['files']" + - "'FOO-UNAR.TXT' in unarchive03['files']" + +- name: verify that the file was unarchived + file: + path: '{{remote_tmp_dir}}/test-unarchive-zip/{{item}}' + state: file + with_items: + - foo-unarchive.txt + - foo-unarchive-777.txt + - FOO-UNAR.TXT + +- name: repeat the last request to verify no changes + unarchive: + src: '{{remote_tmp_dir}}/test-unarchive.zip' + dest: '{{remote_tmp_dir}}/test-unarchive-zip' + list_files: true + remote_src: true + register: unarchive03b + +- name: verify that the task was not marked as changed + assert: + that: + - "unarchive03b.changed == false"