diff --git a/changelogs/fragments/unarchive.yml b/changelogs/fragments/unarchive.yml new file mode 100644 index 00000000000..421497236d6 --- /dev/null +++ b/changelogs/fragments/unarchive.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - unarchive - force unarchive if symlink target changes (https://github.com/ansible/ansible/issues/30420). diff --git a/lib/ansible/modules/unarchive.py b/lib/ansible/modules/unarchive.py index 7d83b9fbb2a..82137d261f3 100644 --- a/lib/ansible/modules/unarchive.py +++ b/lib/ansible/modules/unarchive.py @@ -282,6 +282,7 @@ MISSING_FILE_RE = re.compile(r': Warning: Cannot stat: No such file or directory ZIP_FILE_MODE_RE = re.compile(r'([r-][w-][SsTtx-]){3}') INVALID_OWNER_RE = re.compile(r': Invalid owner') INVALID_GROUP_RE = re.compile(r': Invalid group') +SYMLINK_DIFF_RE = re.compile(r': Symlink differs$') def crc32(path, buffer_size): @@ -879,6 +880,8 @@ class TgzArchive(object): out += line + '\n' if INVALID_GROUP_RE.search(line): out += line + '\n' + if SYMLINK_DIFF_RE.search(line): + out += line + '\n' if out: unarchived = False return dict(unarchived=unarchived, rc=rc, out=out, err=err, cmd=cmd) diff --git a/test/integration/targets/unarchive/tasks/test_symlink.yml b/test/integration/targets/unarchive/tasks/test_symlink.yml index fcb728282bf..a511ddde823 100644 --- a/test/integration/targets/unarchive/tasks/test_symlink.yml +++ b/test/integration/targets/unarchive/tasks/test_symlink.yml @@ -62,3 +62,65 @@ file: path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' state: absent + +- name: Create a destination dir + file: + path: "{{ remote_tmp_dir }}/test-symlink" + state: directory + +- name: Create files + file: + path: "{{ remote_tmp_dir }}/test-symlink/{{ item }}" + state: touch + loop: + - file1 + - file2 + +- name: Create a symlink to the file + file: + path: "{{ remote_tmp_dir }}/test-symlink/link1" + src: "{{ remote_tmp_dir }}/test-symlink/file1" + state: link + +- name: Create archive of symlink + shell: tar czvf {{ remote_tmp_dir }}/link1.tar.gz link1 chdir={{ remote_tmp_dir }}/test-symlink + +- name: Change target of symlink + file: + path: "{{ remote_tmp_dir }}/test-symlink/link1" + src: "{{ remote_tmp_dir }}/test-symlink/file2" + state: link + +- name: Unarchive when symlink differs + unarchive: + src: "{{ remote_tmp_dir }}/link1.tar.gz" + dest: "{{ remote_tmp_dir }}/test-symlink" + remote_src: yes + register: unarchive_13 + +- name: Assert that unarchive was performed + assert: + that: + - unarchive_13.changed == true + +- name: Unarchive when symlink is the same + unarchive: + src: "{{ remote_tmp_dir }}/link1.tar.gz" + dest: "{{ remote_tmp_dir }}/test-symlink" + remote_src: yes + register: unarchive_13 + +- name: Assert that unarchive was not performed + assert: + that: + - "unarchive_13.changed == false" + +- name: Remove files + file: + path: "{{ remote_tmp_dir }}/test-symlink/{{ item }}" + state: absent + with_items: + - file1 + - file2 + - link1 + - link1.tar.gz