* Added a sha256 method to module_common
* Added a sha256sum parameter to the get_url module to enable cryptographic verification of downloaded files * Fixed a few typos in the documentation
This commit is contained in:
parent
0b6570eef8
commit
2ce7f136b2
2 changed files with 58 additions and 12 deletions
|
@ -86,11 +86,18 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
HAVE_HASHLIB=False
|
||||||
try:
|
try:
|
||||||
from hashlib import md5 as _md5
|
from hashlib import md5 as _md5
|
||||||
|
HAVE_HASHLIB=True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from md5 import md5 as _md5
|
from md5 import md5 as _md5
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hashlib import sha256 as _sha256
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from systemd import journal
|
from systemd import journal
|
||||||
has_journal = True
|
has_journal = True
|
||||||
|
@ -787,13 +794,13 @@ class AnsibleModule(object):
|
||||||
or stat.S_IXGRP & os.stat(path)[stat.ST_MODE]
|
or stat.S_IXGRP & os.stat(path)[stat.ST_MODE]
|
||||||
or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
|
or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
|
||||||
|
|
||||||
def md5(self, filename):
|
def digest_from_file(self, filename, digest_method):
|
||||||
''' Return MD5 hex digest of local file, or None if file is not present. '''
|
''' Return hex digest of local file for a given digest_method, or None if file is not present. '''
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
return None
|
return None
|
||||||
if os.path.isdir(filename):
|
if os.path.isdir(filename):
|
||||||
self.fail_json(msg="attempted to take md5sum of directory: %s" % filename)
|
self.fail_json(msg="attempted to take checksum of directory: %s" % filename)
|
||||||
digest = _md5()
|
digest = digest_method
|
||||||
blocksize = 64 * 1024
|
blocksize = 64 * 1024
|
||||||
infile = open(filename, 'rb')
|
infile = open(filename, 'rb')
|
||||||
block = infile.read(blocksize)
|
block = infile.read(blocksize)
|
||||||
|
@ -803,6 +810,16 @@ class AnsibleModule(object):
|
||||||
infile.close()
|
infile.close()
|
||||||
return digest.hexdigest()
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
def md5(self, filename):
|
||||||
|
''' Return MD5 hex digest of local file using digest_from_file(). '''
|
||||||
|
return self.digest_from_file(filename, _md5())
|
||||||
|
|
||||||
|
def sha256(self, filename):
|
||||||
|
''' Return SHA-256 hex digest of local file using digest_from_file(). '''
|
||||||
|
if not HAVE_HASHLIB:
|
||||||
|
self.fail_json(msg="SHA-256 checksums require hashlib, which is available in Python 2.5 and higher")
|
||||||
|
return self.digest_from_file(filename, _sha256())
|
||||||
|
|
||||||
def backup_local(self, fn):
|
def backup_local(self, fn):
|
||||||
'''make a date-marked backup of the specified file, return True or False on success or failure'''
|
'''make a date-marked backup of the specified file, return True or False on success or failure'''
|
||||||
# backups named basename-YYYY-MM-DD@HH:MM~
|
# backups named basename-YYYY-MM-DD@HH:MM~
|
||||||
|
|
|
@ -33,7 +33,7 @@ description:
|
||||||
server I(must) have direct access to the remote resource.
|
server I(must) have direct access to the remote resource.
|
||||||
- By default, if an environment variable C(<protocol>_proxy) is set on
|
- By default, if an environment variable C(<protocol>_proxy) is set on
|
||||||
the target host, requests will be sent through that proxy. This
|
the target host, requests will be sent through that proxy. This
|
||||||
behaviour can be overriden by setting a variable for this task
|
behaviour can be overridden by setting a variable for this task
|
||||||
(see `setting the environment
|
(see `setting the environment
|
||||||
<http://ansible.cc/docs/playbooks2.html#setting-the-environment-and-working-with-proxies>`_),
|
<http://ansible.cc/docs/playbooks2.html#setting-the-environment-and-working-with-proxies>`_),
|
||||||
or by using the use_proxy option.
|
or by using the use_proxy option.
|
||||||
|
@ -53,19 +53,26 @@ options:
|
||||||
default: null
|
default: null
|
||||||
force:
|
force:
|
||||||
description:
|
description:
|
||||||
- if C(yes), will download the file every time and replace the
|
- If C(yes), will download the file every time and replace the
|
||||||
file if the contents change. If C(no), the file will only be downloaded if
|
file if the contents change. If C(no), the file will only be downloaded if
|
||||||
the destination does not exist. Generally should be C(yes) only for small
|
the destination does not exist. Generally should be C(yes) only for small
|
||||||
local files. prior to 0.6, acts if C(yes) by default.
|
local files. Prior to 0.6, this module behaved as if C(yes) was the default.
|
||||||
version_added: "0.7"
|
version_added: "0.7"
|
||||||
required: false
|
required: false
|
||||||
choices: [ "yes", "no" ]
|
choices: [ "yes", "no" ]
|
||||||
default: "no"
|
default: "no"
|
||||||
aliases: [ "thirsty" ]
|
aliases: [ "thirsty" ]
|
||||||
|
sha256sum:
|
||||||
|
description:
|
||||||
|
- 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.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
use_proxy:
|
use_proxy:
|
||||||
description:
|
description:
|
||||||
- if C(no), it will not use a proxy, even if one is defined by
|
- if C(no), it will not use a proxy, even if one is defined in
|
||||||
in an environment variable on the target hosts.
|
an environment variable on the target hosts.
|
||||||
required: false
|
required: false
|
||||||
default: 'yes'
|
default: 'yes'
|
||||||
choices: ['yes', 'no']
|
choices: ['yes', 'no']
|
||||||
|
@ -81,20 +88,30 @@ author: Jan-Piet Mens
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES='''
|
EXAMPLES='''
|
||||||
|
# Download file.conf to /etc/foo.conf with read permissions set for the user and group
|
||||||
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
|
||||||
|
|
||||||
|
# Download file.conf to /etc/foo.conf and ensure that it matches the specified SHA-256 checksum
|
||||||
|
get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
HAS_URLLIB2 = True
|
try:
|
||||||
|
import hashlib
|
||||||
|
HAS_HASHLIB=True
|
||||||
|
except ImportError:
|
||||||
|
HAS_HASHLIB=False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import urllib2
|
import urllib2
|
||||||
|
HAS_URLLIB2 = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_URLLIB2 = False
|
HAS_URLLIB2 = False
|
||||||
HAS_URLPARSE = True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import urlparse
|
import urlparse
|
||||||
import socket
|
import socket
|
||||||
|
HAS_URLPARSE = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_URLPARSE=False
|
HAS_URLPARSE=False
|
||||||
|
|
||||||
|
@ -217,6 +234,7 @@ def main():
|
||||||
url = dict(required=True),
|
url = dict(required=True),
|
||||||
dest = dict(required=True),
|
dest = dict(required=True),
|
||||||
force = dict(default='no', aliases=['thirsty'], type='bool'),
|
force = dict(default='no', aliases=['thirsty'], type='bool'),
|
||||||
|
sha256sum = dict(default=''),
|
||||||
use_proxy = dict(default='yes', type='bool')
|
use_proxy = dict(default='yes', type='bool')
|
||||||
),
|
),
|
||||||
add_file_common_args=True
|
add_file_common_args=True
|
||||||
|
@ -225,6 +243,7 @@ def main():
|
||||||
url = module.params['url']
|
url = module.params['url']
|
||||||
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']
|
||||||
use_proxy = module.params['use_proxy']
|
use_proxy = module.params['use_proxy']
|
||||||
|
|
||||||
if os.path.isdir(dest):
|
if os.path.isdir(dest):
|
||||||
|
@ -273,6 +292,16 @@ def main():
|
||||||
else:
|
else:
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
|
# Check the digest of the destination file and ensure that it matches the
|
||||||
|
# sha256sum parameter if it is present
|
||||||
|
if sha256sum != '':
|
||||||
|
if not HAS_HASHLIB:
|
||||||
|
os.remove(dest)
|
||||||
|
module.fail_json(msg="The sha256sum parameter requires hashlib, which is available in Python 2.5 and higher")
|
||||||
|
if sha256sum != module.sha256(dest):
|
||||||
|
os.remove(dest)
|
||||||
|
module.fail_json(msg="The SHA-256 checksum for %s did not match %s" % (dest, sha256sum))
|
||||||
|
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
|
|
||||||
# allow file attribute changes
|
# allow file attribute changes
|
||||||
|
@ -283,7 +312,7 @@ def main():
|
||||||
|
|
||||||
# Mission complete
|
# Mission complete
|
||||||
module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum_src,
|
module.exit_json(url=url, dest=dest, src=tmpsrc, md5sum=md5sum_src,
|
||||||
changed=changed, msg=info.get('msg', ''))
|
sha256sum=sha256sum, changed=changed, msg=info.get('msg', ''))
|
||||||
|
|
||||||
# this is magic, see lib/ansible/module_common.py
|
# this is magic, see lib/ansible/module_common.py
|
||||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
|
Loading…
Reference in a new issue