diff options
Diffstat (limited to 'lib/ansible/modules/unarchive.py')
-rw-r--r-- | lib/ansible/modules/unarchive.py | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/lib/ansible/modules/unarchive.py b/lib/ansible/modules/unarchive.py index 26890b5..ec15a57 100644 --- a/lib/ansible/modules/unarchive.py +++ b/lib/ansible/modules/unarchive.py @@ -17,17 +17,17 @@ module: unarchive version_added: '1.4' short_description: Unpacks an archive after (optionally) copying it from the local machine description: - - The C(unarchive) module unpacks an archive. It will not unpack a compressed file that does not contain an archive. + - The M(ansible.builtin.unarchive) module unpacks an archive. It will not unpack a compressed file that does not contain an archive. - By default, it will copy the source file from the local system to the target before unpacking. - - Set C(remote_src=yes) to unpack an archive which already exists on the target. - - If checksum validation is desired, use M(ansible.builtin.get_url) or M(ansible.builtin.uri) instead to fetch the file and set C(remote_src=yes). + - Set O(remote_src=yes) to unpack an archive which already exists on the target. + - If checksum validation is desired, use M(ansible.builtin.get_url) or M(ansible.builtin.uri) instead to fetch the file and set O(remote_src=yes). - For Windows targets, use the M(community.windows.win_unzip) module instead. options: src: description: - - If C(remote_src=no) (default), local path to archive file to copy to the target server; can be absolute or relative. If C(remote_src=yes), path on the + - If O(remote_src=no) (default), local path to archive file to copy to the target server; can be absolute or relative. If O(remote_src=yes), path on the target server to existing archive file to unpack. - - If C(remote_src=yes) and C(src) contains C(://), the remote machine will download the file from the URL first. (version_added 2.0). This is only for + - If O(remote_src=yes) and O(src) contains V(://), the remote machine will download the file from the URL first. (version_added 2.0). This is only for simple cases, for full download support use the M(ansible.builtin.get_url) module. type: path required: true @@ -40,14 +40,14 @@ options: copy: description: - If true, the file is copied from local controller to the managed (remote) node, otherwise, the plugin will look for src archive on the managed machine. - - This option has been deprecated in favor of C(remote_src). - - This option is mutually exclusive with C(remote_src). + - This option has been deprecated in favor of O(remote_src). + - This option is mutually exclusive with O(remote_src). type: bool default: yes creates: description: - If the specified absolute path (file or directory) already exists, this step will B(not) be run. - - The specified absolute path (file or directory) must be below the base path given with C(dest:). + - The specified absolute path (file or directory) must be below the base path given with O(dest). type: path version_added: "1.6" io_buffer_size: @@ -65,16 +65,16 @@ options: exclude: description: - List the directory and file entries that you would like to exclude from the unarchive action. - - Mutually exclusive with C(include). + - Mutually exclusive with O(include). type: list default: [] elements: str version_added: "2.1" include: description: - - List of directory and file entries that you would like to extract from the archive. If C(include) + - List of directory and file entries that you would like to extract from the archive. If O(include) is not empty, only files listed here will be extracted. - - Mutually exclusive with C(exclude). + - Mutually exclusive with O(exclude). type: list default: [] elements: str @@ -92,20 +92,20 @@ options: - Command-line options with multiple elements must use multiple lines in the array, one for each element. type: list elements: str - default: "" + default: [] version_added: "2.1" remote_src: description: - - Set to C(true) to indicate the archived file is already on the remote system and not local to the Ansible controller. - - This option is mutually exclusive with C(copy). + - Set to V(true) to indicate the archived file is already on the remote system and not local to the Ansible controller. + - This option is mutually exclusive with O(copy). type: bool default: no version_added: "2.2" validate_certs: description: - This only applies if using a https URL as the source of the file. - - This should only set to C(false) used on personally controlled sites using self-signed certificate. - - Prior to 2.2 the code worked as if this was set to C(true). + - This should only set to V(false) used on personally controlled sites using self-signed certificate. + - Prior to 2.2 the code worked as if this was set to V(true). type: bool default: yes version_added: "2.2" @@ -188,7 +188,7 @@ dest: sample: /opt/software files: description: List of all the files in the archive. - returned: When I(list_files) is True + returned: When O(list_files) is V(True) type: list sample: '["file1", "file2"]' gid: @@ -224,7 +224,7 @@ size: src: description: - The source archive's path. - - If I(src) was a remote web URL, or from the local ansible controller, this shows the temporary location where the download was stored. + - If O(src) was a remote web URL, or from the local ansible controller, this shows the temporary location where the download was stored. returned: always type: str sample: "/home/paul/test.tar.gz" @@ -253,9 +253,9 @@ import stat import time import traceback from functools import partial -from zipfile import ZipFile, BadZipfile +from zipfile import ZipFile -from ansible.module_utils._text import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.locale import get_best_parsable_locale @@ -266,6 +266,11 @@ try: # python 3.3+ except ImportError: # older python from pipes import quote +try: # python 3.2+ + from zipfile import BadZipFile # type: ignore[attr-defined] +except ImportError: # older python + from zipfile import BadZipfile as BadZipFile + # String from tar that shows the tar contents are different from the # filesystem OWNER_DIFF_RE = re.compile(r': Uid differs$') @@ -337,6 +342,7 @@ class ZipArchive(object): def _legacy_file_list(self): rc, out, err = self.module.run_command([self.cmd_path, '-v', self.src]) if rc: + self.module.debug(err) raise UnarchiveError('Neither python zipfile nor unzip can read %s' % self.src) for line in out.splitlines()[3:-2]: @@ -350,7 +356,7 @@ class ZipArchive(object): try: archive = ZipFile(self.src) - except BadZipfile as e: + except BadZipFile as e: if e.args[0].lower().startswith('bad magic number'): # Python2.4 can't handle zipfiles with > 64K files. Try using # /usr/bin/unzip instead @@ -375,7 +381,7 @@ class ZipArchive(object): self._files_in_archive = [] try: archive = ZipFile(self.src) - except BadZipfile as e: + except BadZipFile as e: if e.args[0].lower().startswith('bad magic number'): # Python2.4 can't handle zipfiles with > 64K files. Try using # /usr/bin/unzip instead @@ -417,6 +423,7 @@ class ZipArchive(object): if self.include_files: cmd.extend(self.include_files) rc, out, err = self.module.run_command(cmd) + self.module.debug(err) old_out = out diff = '' @@ -745,6 +752,9 @@ class ZipArchive(object): rc, out, err = self.module.run_command(cmd) if rc == 0: return True, None + + self.module.debug(err) + return False, 'Command "%s" could not handle archive: %s' % (self.cmd_path, err) @@ -794,6 +804,7 @@ class TgzArchive(object): locale = get_best_parsable_locale(self.module) rc, out, err = self.module.run_command(cmd, cwd=self.b_dest, environ_update=dict(LANG=locale, LC_ALL=locale, LC_MESSAGES=locale, LANGUAGE=locale)) if rc != 0: + self.module.debug(err) raise UnarchiveError('Unable to list files in the archive: %s' % err) for filename in out.splitlines(): @@ -1022,7 +1033,12 @@ def main(): src = module.params['src'] dest = module.params['dest'] - b_dest = to_bytes(dest, errors='surrogate_or_strict') + abs_dest = os.path.abspath(dest) + b_dest = to_bytes(abs_dest, errors='surrogate_or_strict') + + if not os.path.isabs(dest): + module.warn("Relative destination path '{dest}' was resolved to absolute path '{abs_dest}'.".format(dest=dest, abs_dest=abs_dest)) + remote_src = module.params['remote_src'] file_args = module.load_file_common_arguments(module.params) @@ -1038,6 +1054,9 @@ def main(): if not os.access(src, os.R_OK): module.fail_json(msg="Source '%s' not readable" % src) + # ensure src is an absolute path before picking handlers + src = os.path.abspath(src) + # skip working with 0 size archives try: if os.path.getsize(src) == 0: |