diff --git a/network/basics/get_url.py b/network/basics/get_url.py index 5e39887df7f..f5c14812b29 100644 --- a/network/basics/get_url.py +++ b/network/basics/get_url.py @@ -72,9 +72,22 @@ options: - If a SHA-256 checksum is passed to this parameter, the digest of the destination file will be calculated after it is downloaded to ensure its integrity and verify that the transfer completed successfully. + This option is deprecated. Use 'checksum'. version_added: "1.3" required: false default: null + checksum: + description: + - If a checksum is passed to this parameter, the digest of the + destination file will be calculated after it is downloaded to ensure + its integrity and verify that the transfer completed successfully. + Format: :, e.g.: checksum="sha256:d98291acbedd510e3dbd36dbfdd83cbca8415220af43b327c0a0c574b6dc7b97" + If you worry about portability, only the sha1 algorithm is available + on all platforms and python versions. The third party hashlib + library can be installed for access to additional algorithms. + version_added: "2.0" + required: false + default: null use_proxy: description: - if C(no), it will not use a proxy, even if one is defined in @@ -136,24 +149,19 @@ EXAMPLES=''' - name: download foo.conf get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf mode=0440 -- name: download file with sha256 check - get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c - - name: download file and force basic auth get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf force_basic_auth=yes - name: download file with custom HTTP headers get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf headers: 'key:value,key:value' + +- name: download file with check + get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf checksum=sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c + get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf checksum=md5:66dffb5228a211e61d6d7ef4a86f5758 ''' import urlparse -try: - import hashlib - HAS_HASHLIB=True -except ImportError: - HAS_HASHLIB=False - # ============================================================== # url handling @@ -209,6 +217,7 @@ def extract_filename_from_headers(headers): return res + # ============================================================== # main @@ -219,6 +228,7 @@ def main(): url = dict(required=True), dest = dict(required=True), sha256sum = dict(default=''), + checksum = dict(default=''), timeout = dict(required=False, type='int', default=10), headers = dict(required=False, default=None), ) @@ -233,6 +243,7 @@ def main(): dest = os.path.expanduser(module.params['dest']) force = module.params['force'] sha256sum = module.params['sha256sum'] + checksum = module.params['checksum'] use_proxy = module.params['use_proxy'] timeout = module.params['timeout'] @@ -248,28 +259,37 @@ def main(): dest_is_dir = os.path.isdir(dest) last_mod_time = None - # Remove any non-alphanumeric characters, including the infamous - # Unicode zero-width space - stripped_sha256sum = re.sub(r'\W+', '', sha256sum) + # workaround for usage of deprecated sha256sum parameter + if sha256sum != '': + checksum = 'sha256:%s' % (sha256sum) + + # checksum specified, parse for algorithm and checksum + if checksum != '': + try: + algorithm, checksum = checksum.rsplit(':', 1) + # Remove any non-alphanumeric characters, including the infamous + # Unicode zero-width space + checksum = re.sub(r'\W+', '', checksum).lower() + # Ensure the checksum portion is a hexdigest + int(checksum, 16) + except ValueError: + module.fail_json(msg="The checksum parameter has to be in format :") - # Fail early if sha256 is not supported - if sha256sum != '' and not HAS_HASHLIB: - module.fail_json(msg="The sha256sum parameter requires hashlib, which is available in Python 2.5 and higher") if not dest_is_dir and os.path.exists(dest): checksum_mismatch = False # If the download is not forced and there is a checksum, allow # checksum match to skip the download. - if not force and sha256sum != '': - destination_checksum = module.sha256(dest) + if not force and checksum != '': + destination_checksum = module.digest_from_file(dest, algorithm) - if stripped_sha256sum.lower() == destination_checksum: + if checksum == destination_checksum: module.exit_json(msg="file already exists", dest=dest, url=url, changed=False) checksum_mismatch = True - # Not forcing redownload, unless sha256sum has already failed + # Not forcing redownload, unless checksum does not match if not force and not checksum_mismatch: module.exit_json(msg="file already exists", dest=dest, url=url, changed=False) @@ -330,14 +350,12 @@ def main(): else: changed = False - # Check the digest of the destination file and ensure that it matches the - # sha256sum parameter if it is present - if sha256sum != '': - destination_checksum = module.sha256(dest) + if checksum != '': + destination_checksum = module.digest_from_file(dest, algorithm) - if stripped_sha256sum.lower() != destination_checksum: + if checksum != destination_checksum: os.remove(dest) - module.fail_json(msg="The SHA-256 checksum for %s did not match %s; it was %s." % (dest, sha256sum, destination_checksum)) + module.fail_json(msg="The checksum for %s did not match %s; it was %s." % (dest, checksum, destination_checksum)) os.remove(tmpsrc) @@ -354,9 +372,8 @@ def main(): md5sum = None # Mission complete - - module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum, checksum=checksum_src, - sha256sum=sha256sum, changed=changed, msg=info.get('msg', '')) + module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum, checksum_src=checksum_src, + checksum_dest=checksum_dest, changed=changed, msg=info.get('msg', '')) # import module snippets from ansible.module_utils.basic import *