Skip to content

Commit 7bdad10

Browse files
authored
aws_s3 - fix issue when copy missing key from bucket (ansible-collections#603)
aws_s3 - fix issue when copy missing key from bucket SUMMARY ansible-collections#602 ISSUE TYPE Bugfix Pull Request COMPONENT NAME aws_s3 ADDITIONAL INFORMATION Reviewed-by: Alina Buzachis <None> Reviewed-by: None <None>
1 parent b27f516 commit 7bdad10

File tree

3 files changed

+59
-35
lines changed

3 files changed

+59
-35
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bugfixes:
2+
- aws_s3 - fix exception raised when using module to copy from source to destination and key is missing from source (https://github.com/ansible-collections/amazon.aws/issues/602).

plugins/modules/aws_s3.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,16 @@ def etag_compare(module, s3, bucket, obj, version=None, local_file=None, content
412412

413413

414414
def get_etag(s3, bucket, obj, version=None):
415-
if version:
416-
key_check = s3.head_object(Bucket=bucket, Key=obj, VersionId=version)
417-
else:
418-
key_check = s3.head_object(Bucket=bucket, Key=obj)
419-
if not key_check:
415+
try:
416+
if version:
417+
key_check = s3.head_object(Bucket=bucket, Key=obj, VersionId=version)
418+
else:
419+
key_check = s3.head_object(Bucket=bucket, Key=obj)
420+
if not key_check:
421+
return None
422+
return key_check['ETag']
423+
except is_boto3_error_code('404'):
420424
return None
421-
return key_check['ETag']
422425

423426

424427
def bucket_check(module, s3, bucket, validate=True):
@@ -721,40 +724,43 @@ def copy_object_to_bucket(module, s3, bucket, obj, encrypt, metadata, validate,
721724
if module.params['copy_src'].get('version_id') is not None:
722725
version = module.params['copy_src'].get('version_id')
723726
bucketsrc.update({'VersionId': version})
724-
keyrtn = key_check(module, s3, bucketsrc['Bucket'], bucketsrc['Key'], version=version, validate=validate)
725-
if keyrtn:
726-
s_etag = get_etag(s3, bucketsrc['Bucket'], bucketsrc['Key'], version=version)
727-
if s_etag == d_etag:
728-
# Tags
729-
tags, changed = ensure_tags(s3, module, bucket, obj)
730-
if not changed:
731-
module.exit_json(msg="ETag from source and destination are the same", changed=False)
727+
if not key_check(module, s3, bucketsrc['Bucket'], bucketsrc['Key'], version=version, validate=validate):
728+
# Key does not exist in source bucket
729+
module.exit_json(msg="Key %s does not exist in bucket %s." % (bucketsrc['Key'], bucketsrc['Bucket']), changed=False)
730+
731+
s_etag = get_etag(s3, bucketsrc['Bucket'], bucketsrc['Key'], version=version)
732+
if s_etag == d_etag:
733+
# Tags
734+
tags, changed = ensure_tags(s3, module, bucket, obj)
735+
if not changed:
736+
module.exit_json(msg="ETag from source and destination are the same", changed=False)
732737
else:
733-
params.update({'CopySource': bucketsrc})
734-
if encrypt:
735-
params['ServerSideEncryption'] = module.params['encryption_mode']
736-
if module.params['encryption_kms_key_id'] and module.params['encryption_mode'] == 'aws:kms':
737-
params['SSEKMSKeyId'] = module.params['encryption_kms_key_id']
738-
if metadata:
739-
params['Metadata'] = {}
740-
# determine object metadata and extra arguments
741-
for option in metadata:
742-
extra_args_option = option_in_extra_args(option)
743-
if extra_args_option is not None:
744-
params[extra_args_option] = metadata[option]
745-
else:
746-
params['Metadata'][option] = metadata[option]
747-
748-
copy_result = s3.copy_object(**params)
749-
for acl in module.params.get('permission'):
750-
s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
751-
# Tags
752-
tags, changed = ensure_tags(s3, module, bucket, obj)
738+
module.exit_json(msg="tags successfully updated.", changed=changed, tags=tags)
739+
else:
740+
params.update({'CopySource': bucketsrc})
741+
if encrypt:
742+
params['ServerSideEncryption'] = module.params['encryption_mode']
743+
if module.params['encryption_kms_key_id'] and module.params['encryption_mode'] == 'aws:kms':
744+
params['SSEKMSKeyId'] = module.params['encryption_kms_key_id']
745+
if metadata:
746+
params['Metadata'] = {}
747+
# determine object metadata and extra arguments
748+
for option in metadata:
749+
extra_args_option = option_in_extra_args(option)
750+
if extra_args_option is not None:
751+
params[extra_args_option] = metadata[option]
752+
else:
753+
params['Metadata'][option] = metadata[option]
754+
copy_result = s3.copy_object(**params)
755+
for acl in module.params.get('permission'):
756+
s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
757+
# Tags
758+
tags, changed = ensure_tags(s3, module, bucket, obj)
759+
module.exit_json(msg="Object copied from bucket %s to bucket %s." % (bucketsrc['Bucket'], bucket), tags=tags, changed=True)
753760
except is_boto3_error_code(IGNORE_S3_DROP_IN_EXCEPTIONS):
754761
module.warn("PutObjectAcl is not implemented by your storage provider. Set the permissions parameters to the empty list to avoid this warning")
755762
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
756763
module.fail_json_aws(e, msg="Failed while copying object %s from bucket %s." % (obj, module.params['copy_src'].get('Bucket')))
757-
module.exit_json(msg="Object copied from bucket %s to bucket %s." % (bucketsrc['Bucket'], bucket), tags=tags, changed=True)
758764

759765

760766
def is_fakes3(s3_url):

tests/integration/targets/aws_s3/tasks/copy_object.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@
112112
that:
113113
- copy_result is not changed
114114

115+
- name: Copy from unexisting key should not succeed
116+
aws_s3:
117+
bucket: "{{ copy_bucket.dst }}"
118+
mode: copy
119+
object: missing_key.txt
120+
copy_src:
121+
bucket: "{{ copy_bucket.src }}"
122+
object: this_key_does_not_exist.txt
123+
register: result
124+
125+
- name: Validate result when copying missing key
126+
assert:
127+
that:
128+
- result is not changed
129+
- 'result.msg == "Key this_key_does_not_exist.txt does not exist in bucket {{ copy_bucket.src }}."'
130+
115131
always:
116132
- include_tasks: delete_bucket.yml
117133
with_items:

0 commit comments

Comments
 (0)