|
|
@ -72,9 +72,22 @@ options:
|
|
|
|
- If a SHA-256 checksum is passed to this parameter, the digest of the
|
|
|
|
- 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
|
|
|
|
destination file will be calculated after it is downloaded to ensure
|
|
|
|
its integrity and verify that the transfer completed successfully.
|
|
|
|
its integrity and verify that the transfer completed successfully.
|
|
|
|
|
|
|
|
This option is deprecated. Use 'checksum'.
|
|
|
|
version_added: "1.3"
|
|
|
|
version_added: "1.3"
|
|
|
|
required: false
|
|
|
|
required: false
|
|
|
|
default: null
|
|
|
|
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: <algorithm>:<checksum>, 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:
|
|
|
|
use_proxy:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- if C(no), it will not use a proxy, even if one is defined in
|
|
|
|
- if C(no), it will not use a proxy, even if one is defined in
|
|
|
@ -136,24 +149,19 @@ EXAMPLES='''
|
|
|
|
- name: download foo.conf
|
|
|
|
- name: download foo.conf
|
|
|
|
get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf mode=0440
|
|
|
|
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
|
|
|
|
- name: download file and force basic auth
|
|
|
|
get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf force_basic_auth=yes
|
|
|
|
get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf force_basic_auth=yes
|
|
|
|
|
|
|
|
|
|
|
|
- name: download file with custom HTTP headers
|
|
|
|
- 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'
|
|
|
|
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
|
|
|
|
import urlparse
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
|
|
|
|
HAS_HASHLIB=True
|
|
|
|
|
|
|
|
except ImportError:
|
|
|
|
|
|
|
|
HAS_HASHLIB=False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
# ==============================================================
|
|
|
|
# url handling
|
|
|
|
# url handling
|
|
|
|
|
|
|
|
|
|
|
@ -209,6 +217,7 @@ def extract_filename_from_headers(headers):
|
|
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
# ==============================================================
|
|
|
|
# main
|
|
|
|
# main
|
|
|
|
|
|
|
|
|
|
|
@ -219,6 +228,7 @@ def main():
|
|
|
|
url = dict(required=True),
|
|
|
|
url = dict(required=True),
|
|
|
|
dest = dict(required=True),
|
|
|
|
dest = dict(required=True),
|
|
|
|
sha256sum = dict(default=''),
|
|
|
|
sha256sum = dict(default=''),
|
|
|
|
|
|
|
|
checksum = dict(default=''),
|
|
|
|
timeout = dict(required=False, type='int', default=10),
|
|
|
|
timeout = dict(required=False, type='int', default=10),
|
|
|
|
headers = dict(required=False, default=None),
|
|
|
|
headers = dict(required=False, default=None),
|
|
|
|
)
|
|
|
|
)
|
|
|
@ -233,6 +243,7 @@ def main():
|
|
|
|
dest = os.path.expanduser(module.params['dest'])
|
|
|
|
dest = os.path.expanduser(module.params['dest'])
|
|
|
|
force = module.params['force']
|
|
|
|
force = module.params['force']
|
|
|
|
sha256sum = module.params['sha256sum']
|
|
|
|
sha256sum = module.params['sha256sum']
|
|
|
|
|
|
|
|
checksum = module.params['checksum']
|
|
|
|
use_proxy = module.params['use_proxy']
|
|
|
|
use_proxy = module.params['use_proxy']
|
|
|
|
timeout = module.params['timeout']
|
|
|
|
timeout = module.params['timeout']
|
|
|
|
|
|
|
|
|
|
|
@ -248,28 +259,37 @@ def main():
|
|
|
|
dest_is_dir = os.path.isdir(dest)
|
|
|
|
dest_is_dir = os.path.isdir(dest)
|
|
|
|
last_mod_time = None
|
|
|
|
last_mod_time = None
|
|
|
|
|
|
|
|
|
|
|
|
# Remove any non-alphanumeric characters, including the infamous
|
|
|
|
# workaround for usage of deprecated sha256sum parameter
|
|
|
|
# Unicode zero-width space
|
|
|
|
if sha256sum != '':
|
|
|
|
stripped_sha256sum = re.sub(r'\W+', '', 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 <algorithm>:<checksum>")
|
|
|
|
|
|
|
|
|
|
|
|
# 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):
|
|
|
|
if not dest_is_dir and os.path.exists(dest):
|
|
|
|
checksum_mismatch = False
|
|
|
|
checksum_mismatch = False
|
|
|
|
|
|
|
|
|
|
|
|
# If the download is not forced and there is a checksum, allow
|
|
|
|
# If the download is not forced and there is a checksum, allow
|
|
|
|
# checksum match to skip the download.
|
|
|
|
# checksum match to skip the download.
|
|
|
|
if not force and sha256sum != '':
|
|
|
|
if not force and checksum != '':
|
|
|
|
destination_checksum = module.sha256(dest)
|
|
|
|
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)
|
|
|
|
module.exit_json(msg="file already exists", dest=dest, url=url, changed=False)
|
|
|
|
|
|
|
|
|
|
|
|
checksum_mismatch = True
|
|
|
|
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:
|
|
|
|
if not force and not checksum_mismatch:
|
|
|
|
module.exit_json(msg="file already exists", dest=dest, url=url, changed=False)
|
|
|
|
module.exit_json(msg="file already exists", dest=dest, url=url, changed=False)
|
|
|
|
|
|
|
|
|
|
|
@ -330,14 +350,12 @@ def main():
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
changed = False
|
|
|
|
changed = False
|
|
|
|
|
|
|
|
|
|
|
|
# Check the digest of the destination file and ensure that it matches the
|
|
|
|
if checksum != '':
|
|
|
|
# sha256sum parameter if it is present
|
|
|
|
destination_checksum = module.digest_from_file(dest, algorithm)
|
|
|
|
if sha256sum != '':
|
|
|
|
|
|
|
|
destination_checksum = module.sha256(dest)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if stripped_sha256sum.lower() != destination_checksum:
|
|
|
|
if checksum != destination_checksum:
|
|
|
|
os.remove(dest)
|
|
|
|
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)
|
|
|
|
os.remove(tmpsrc)
|
|
|
|
|
|
|
|
|
|
|
@ -354,9 +372,8 @@ def main():
|
|
|
|
md5sum = None
|
|
|
|
md5sum = None
|
|
|
|
|
|
|
|
|
|
|
|
# Mission complete
|
|
|
|
# Mission complete
|
|
|
|
|
|
|
|
module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum, checksum_src=checksum_src,
|
|
|
|
module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum, checksum=checksum_src,
|
|
|
|
checksum_dest=checksum_dest, changed=changed, msg=info.get('msg', ''))
|
|
|
|
sha256sum=sha256sum, changed=changed, msg=info.get('msg', ''))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# import module snippets
|
|
|
|
# import module snippets
|
|
|
|
from ansible.module_utils.basic import *
|
|
|
|
from ansible.module_utils.basic import *
|
|
|
|