mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Added SHA1 option to maven_artifact (#2662)
* Added SHA1 option * Add changelog fragment * Update plugins/modules/packaging/language/maven_artifact.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/packaging/language/maven_artifact.py Co-authored-by: Felix Fontein <felix@fontein.de> * Combined hash functions Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/packaging/language/maven_artifact.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/packaging/language/maven_artifact.py Co-authored-by: Felix Fontein <felix@fontein.de> * Removed unused functions (rolled into _local_checksum) * Update changelogs/fragments/2661-maven_artifact-add-sha1-option.yml Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
1ad85849af
commit
ca1506fb26
2 changed files with 46 additions and 28 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- maven_artifact - added ``checksum_alg`` option to support SHA1 checksums in order to support FIPS systems (https://github.com/ansible-collections/community.general/pull/2662).
|
|
@ -129,10 +129,10 @@ options:
|
||||||
verify_checksum:
|
verify_checksum:
|
||||||
type: str
|
type: str
|
||||||
description:
|
description:
|
||||||
- If C(never), the md5 checksum will never be downloaded and verified.
|
- If C(never), the MD5/SHA1 checksum will never be downloaded and verified.
|
||||||
- If C(download), the md5 checksum will be downloaded and verified only after artifact download. This is the default.
|
- If C(download), the MD5/SHA1 checksum will be downloaded and verified only after artifact download. This is the default.
|
||||||
- If C(change), the md5 checksum will be downloaded and verified if the destination already exist,
|
- If C(change), the MD5/SHA1 checksum will be downloaded and verified if the destination already exist,
|
||||||
to verify if they are identical. This was the behaviour before 2.6. Since it downloads the md5 before (maybe)
|
to verify if they are identical. This was the behaviour before 2.6. Since it downloads the checksum before (maybe)
|
||||||
downloading the artifact, and since some repository software, when acting as a proxy/cache, return a 404 error
|
downloading the artifact, and since some repository software, when acting as a proxy/cache, return a 404 error
|
||||||
if the artifact has not been cached yet, it may fail unexpectedly.
|
if the artifact has not been cached yet, it may fail unexpectedly.
|
||||||
If you still need it, you should consider using C(always) instead - if you deal with a checksum, it is better to
|
If you still need it, you should consider using C(always) instead - if you deal with a checksum, it is better to
|
||||||
|
@ -141,6 +141,15 @@ options:
|
||||||
required: false
|
required: false
|
||||||
default: 'download'
|
default: 'download'
|
||||||
choices: ['never', 'download', 'change', 'always']
|
choices: ['never', 'download', 'change', 'always']
|
||||||
|
checksum_alg:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- If C(md5), checksums will use the MD5 algorithm. This is the default.
|
||||||
|
- If C(sha1), checksums will use the SHA1 algorithm. This can be used on systems configured to use
|
||||||
|
FIPS-compliant algorithms, since MD5 will be blocked on such systems.
|
||||||
|
default: 'md5'
|
||||||
|
choices: ['md5', 'sha1']
|
||||||
|
version_added: 3.2.0
|
||||||
directory_mode:
|
directory_mode:
|
||||||
type: str
|
type: str
|
||||||
description:
|
description:
|
||||||
|
@ -507,7 +516,7 @@ class MavenDownloader:
|
||||||
raise ValueError(failmsg + " because of " + info['msg'] + "for URL " + url_to_use)
|
raise ValueError(failmsg + " because of " + info['msg'] + "for URL " + url_to_use)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def download(self, tmpdir, artifact, verify_download, filename=None):
|
def download(self, tmpdir, artifact, verify_download, filename=None, checksum_alg='md5'):
|
||||||
if (not artifact.version and not artifact.version_by_spec) or artifact.version == "latest":
|
if (not artifact.version and not artifact.version_by_spec) or artifact.version == "latest":
|
||||||
artifact = Artifact(artifact.group_id, artifact.artifact_id, self.find_latest_version_available(artifact), None,
|
artifact = Artifact(artifact.group_id, artifact.artifact_id, self.find_latest_version_available(artifact), None,
|
||||||
artifact.classifier, artifact.extension)
|
artifact.classifier, artifact.extension)
|
||||||
|
@ -528,11 +537,11 @@ class MavenDownloader:
|
||||||
shutil.copyfileobj(response, f)
|
shutil.copyfileobj(response, f)
|
||||||
|
|
||||||
if verify_download:
|
if verify_download:
|
||||||
invalid_md5 = self.is_invalid_md5(tempname, url)
|
invalid_checksum = self.is_invalid_checksum(tempname, url, checksum_alg)
|
||||||
if invalid_md5:
|
if invalid_checksum:
|
||||||
# if verify_change was set, the previous file would be deleted
|
# if verify_change was set, the previous file would be deleted
|
||||||
os.remove(tempname)
|
os.remove(tempname)
|
||||||
return invalid_md5
|
return invalid_checksum
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
os.remove(tempname)
|
os.remove(tempname)
|
||||||
raise e
|
raise e
|
||||||
|
@ -541,40 +550,45 @@ class MavenDownloader:
|
||||||
shutil.move(tempname, artifact.get_filename(filename))
|
shutil.move(tempname, artifact.get_filename(filename))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def is_invalid_md5(self, file, remote_url):
|
def is_invalid_checksum(self, file, remote_url, checksum_alg='md5'):
|
||||||
if os.path.exists(file):
|
if os.path.exists(file):
|
||||||
local_md5 = self._local_md5(file)
|
local_checksum = self._local_checksum(checksum_alg, file)
|
||||||
if self.local:
|
if self.local:
|
||||||
parsed_url = urlparse(remote_url)
|
parsed_url = urlparse(remote_url)
|
||||||
remote_md5 = self._local_md5(parsed_url.path)
|
remote_checksum = self._local_checksum(checksum_alg, parsed_url.path)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
remote_md5 = to_text(self._getContent(remote_url + '.md5', "Failed to retrieve MD5", False), errors='strict')
|
remote_checksum = to_text(self._getContent(remote_url + '.' + checksum_alg, "Failed to retrieve checksum", False), errors='strict')
|
||||||
except UnicodeError as e:
|
except UnicodeError as e:
|
||||||
return "Cannot retrieve a valid md5 from %s: %s" % (remote_url, to_native(e))
|
return "Cannot retrieve a valid %s checksum from %s: %s" % (checksum_alg, remote_url, to_native(e))
|
||||||
if(not remote_md5):
|
if not remote_checksum:
|
||||||
return "Cannot find md5 from " + remote_url
|
return "Cannot find %s checksum from %s" % (checksum_alg, remote_url)
|
||||||
try:
|
try:
|
||||||
# Check if remote md5 only contains md5 or md5 + filename
|
# Check if remote checksum only contains md5/sha1 or md5/sha1 + filename
|
||||||
_remote_md5 = remote_md5.split(None)[0]
|
_remote_checksum = remote_checksum.split(None)[0]
|
||||||
remote_md5 = _remote_md5
|
remote_checksum = _remote_checksum
|
||||||
# remote_md5 is empty so we continue and keep original md5 string
|
# remote_checksum is empty so we continue and keep original checksum string
|
||||||
# This should not happen since we check for remote_md5 before
|
# This should not happen since we check for remote_checksum before
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
if local_md5.lower() == remote_md5.lower():
|
if local_checksum.lower() == remote_checksum.lower():
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return "Checksum does not match: we computed " + local_md5 + " but the repository states " + remote_md5
|
return "Checksum does not match: we computed " + local_checksum + " but the repository states " + remote_checksum
|
||||||
|
|
||||||
return "Path does not exist: " + file
|
return "Path does not exist: " + file
|
||||||
|
|
||||||
def _local_md5(self, file):
|
def _local_checksum(self, checksum_alg, file):
|
||||||
md5 = hashlib.md5()
|
if checksum_alg.lower() == 'md5':
|
||||||
|
hash = hashlib.md5()
|
||||||
|
elif checksum_alg.lower() == 'sha1':
|
||||||
|
hash = hashlib.sha1()
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown checksum_alg %s" % checksum_alg)
|
||||||
with io.open(file, 'rb') as f:
|
with io.open(file, 'rb') as f:
|
||||||
for chunk in iter(lambda: f.read(8192), b''):
|
for chunk in iter(lambda: f.read(8192), b''):
|
||||||
md5.update(chunk)
|
hash.update(chunk)
|
||||||
return md5.hexdigest()
|
return hash.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -599,6 +613,7 @@ def main():
|
||||||
client_key=dict(type="path", required=False),
|
client_key=dict(type="path", required=False),
|
||||||
keep_name=dict(required=False, default=False, type='bool'),
|
keep_name=dict(required=False, default=False, type='bool'),
|
||||||
verify_checksum=dict(required=False, default='download', choices=['never', 'download', 'change', 'always']),
|
verify_checksum=dict(required=False, default='download', choices=['never', 'download', 'change', 'always']),
|
||||||
|
checksum_alg=dict(required=False, default='md5', choices=['md5', 'sha1']),
|
||||||
directory_mode=dict(type='str'),
|
directory_mode=dict(type='str'),
|
||||||
),
|
),
|
||||||
add_file_common_args=True,
|
add_file_common_args=True,
|
||||||
|
@ -639,6 +654,7 @@ def main():
|
||||||
verify_checksum = module.params["verify_checksum"]
|
verify_checksum = module.params["verify_checksum"]
|
||||||
verify_download = verify_checksum in ['download', 'always']
|
verify_download = verify_checksum in ['download', 'always']
|
||||||
verify_change = verify_checksum in ['change', 'always']
|
verify_change = verify_checksum in ['change', 'always']
|
||||||
|
checksum_alg = module.params["checksum_alg"]
|
||||||
|
|
||||||
downloader = MavenDownloader(module, repository_url, local, headers)
|
downloader = MavenDownloader(module, repository_url, local, headers)
|
||||||
|
|
||||||
|
@ -683,12 +699,12 @@ def main():
|
||||||
|
|
||||||
b_dest = to_bytes(dest, errors='surrogate_or_strict')
|
b_dest = to_bytes(dest, errors='surrogate_or_strict')
|
||||||
|
|
||||||
if os.path.lexists(b_dest) and ((not verify_change) or not downloader.is_invalid_md5(dest, downloader.find_uri_for_artifact(artifact))):
|
if os.path.lexists(b_dest) and ((not verify_change) or not downloader.is_invalid_checksum(dest, downloader.find_uri_for_artifact(artifact), checksum_alg)):
|
||||||
prev_state = "present"
|
prev_state = "present"
|
||||||
|
|
||||||
if prev_state == "absent":
|
if prev_state == "absent":
|
||||||
try:
|
try:
|
||||||
download_error = downloader.download(module.tmpdir, artifact, verify_download, b_dest)
|
download_error = downloader.download(module.tmpdir, artifact, verify_download, b_dest, checksum_alg)
|
||||||
if download_error is None:
|
if download_error is None:
|
||||||
changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in a new issue