Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

s3_object: Add parameter acl_disabled to handle uploading files to buckets with ACL disabled. #921

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- s3_object - updated module to add support for handling file upload to a bucket with ACL disabled (https://github.com/ansible-collections/amazon.aws/pull/921).
45 changes: 30 additions & 15 deletions plugins/modules/s3_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ def option_in_extra_args(option):
return allowed_extra_args[temp_option]


def upload_s3file(module, s3, bucket, obj, expiry, metadata, encrypt, headers, src=None, content=None):
def upload_s3file(module, s3, bucket, obj, expiry, metadata, encrypt, headers, src=None, content=None, acl_disabled=False):
if module.check_mode:
module.exit_json(msg="PUT operation skipped - running in check mode", changed=True)
try:
Expand Down Expand Up @@ -677,13 +677,14 @@ def upload_s3file(module, s3, bucket, obj, expiry, metadata, encrypt, headers, s
s3.upload_fileobj(Fileobj=f, Bucket=bucket, Key=obj, ExtraArgs=extra)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to complete PUT operation.")
try:
for acl in module.params.get('permission'):
s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
except is_boto3_error_code(IGNORE_S3_DROP_IN_EXCEPTIONS):
module.warn("PutObjectAcl is not implemented by your storage provider. Set the permission parameters to the empty list to avoid this warning")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Unable to set object ACL")
if not acl_disabled:
try:
for acl in module.params.get('permission'):
s3.put_object_acl(ACL=acl, Bucket=bucket, Key=obj)
except is_boto3_error_code(IGNORE_S3_DROP_IN_EXCEPTIONS):
module.warn("PutObjectAcl is not implemented by your storage provider. Set the permission parameters to the empty list to avoid this warning")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Unable to set object ACL")

# Tags
tags, changed = ensure_tags(s3, module, bucket, obj)
Expand Down Expand Up @@ -1056,12 +1057,25 @@ def main():

validate = not ignore_nonexistent_bucket

# check if bucket exists, if yes, check if ACL is disabled
acl_disabled = False
exists = bucket_check(module, s3, bucket)
if exists:
try:
object_ownership = s3.get_bucket_ownership_controls(Bucket=bucket)['OwnershipControls']['Rules'][0]['ObjectOwnership']
if object_ownership == 'BucketOwnerEnforced':
acl_disabled = True
# if bucket ownership controls are not found
except botocore.exceptions.ClientError as e:
pass

# separate types of ACLs
bucket_acl = [acl for acl in module.params.get('permission') if acl in bucket_canned_acl]
object_acl = [acl for acl in module.params.get('permission') if acl in object_canned_acl]
error_acl = [acl for acl in module.params.get('permission') if acl not in bucket_canned_acl and acl not in object_canned_acl]
if error_acl:
module.fail_json(msg='Unknown permission specified: %s' % error_acl)
if not acl_disabled:
bucket_acl = [acl for acl in module.params.get('permission') if acl in bucket_canned_acl]
object_acl = [acl for acl in module.params.get('permission') if acl in object_canned_acl]
error_acl = [acl for acl in module.params.get('permission') if acl not in bucket_canned_acl and acl not in object_canned_acl]
if error_acl:
module.fail_json(msg='Unknown permission specified: %s' % error_acl)

# First, we check to see if the bucket exists, we get "bucket" returned.
bucketrtn = bucket_check(module, s3, bucket, validate=validate)
Expand Down Expand Up @@ -1124,8 +1138,9 @@ def main():
get_download_url(module, s3, bucket, obj, expiry, tags, changed=tags_update)

# only use valid object acls for the upload_s3file function
module.params['permission'] = object_acl
upload_s3file(module, s3, bucket, obj, expiry, metadata, encrypt, headers, src=src, content=bincontent)
if not acl_disabled:
module.params['permission'] = object_acl
upload_s3file(module, s3, bucket, obj, expiry, metadata, encrypt, headers, src=src, content=bincontent, acl_disabled=acl_disabled)

# Delete an object from a bucket, not the entire bucket
if mode == 'delobj':
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/targets/s3_object/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
- name: test copying objects to bucket with ACL disabled
block:
- name: Create a bucket with ACL disabled for the test
s3_bucket:
name: "{{ bucket_name }}-acl-disabled"
object_ownership: BucketOwnerEnforced
state: present
register: create_result

- name: Ensure bucket creation
assert:
that:
- create_result is changed
- create_result is not failed
- create_result.object_ownership == "BucketOwnerEnforced"

- name: Create content
set_fact:
content: "{{ lookup('password', '/dev/null chars=ascii_letters,digits,hexdigits,punctuation') }}"

- name: Create local acl_disabled_upload_test.txt
copy:
content: "{{ content }}"
dest: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"

- name: Upload a file to the bucket (check_mode)
amazon.aws.s3_object:
bucket: "{{ bucket_name }}-acl-disabled"
src: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"
object: "acl_disabled_upload_test.txt"
mode: put
check_mode: true
register: upload_file_result

- assert:
that:
- upload_file_result is changed
- upload_file_result is not failed
- upload_file_result.msg == "PUT operation skipped - running in check mode"
- '"s3:PutObject" not in upload_file_result.resource_actions'

- name: Upload a file to the bucket
amazon.aws.s3_object:
bucket: "{{ bucket_name }}-acl-disabled"
src: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"
object: "acl_disabled_upload_test.txt"
mode: put
register: upload_file_result

- assert:
that:
- upload_file_result is changed
- upload_file_result is not failed
- upload_file_result.msg == "PUT operation complete"
- '"s3:PutObject" in upload_file_result.resource_actions'

- name: Upload a file to the bucket (check_mode - idempotency)
amazon.aws.s3_object:
bucket: "{{ bucket_name }}-acl-disabled"
src: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"
object: "acl_disabled_upload_test.txt"
mode: put
check_mode: true
register: upload_file_result

- assert:
that:
- upload_file_result is not changed
- upload_file_result is not failed
- upload_file_result.msg != "PUT operation complete"
- '"s3:PutObject" not in upload_file_result.resource_actions'

- name: Upload a file to the bucket (idempotency)
amazon.aws.s3_object:
bucket: "{{ bucket_name }}-acl-disabled"
src: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"
object: "acl_disabled_upload_test.txt"
mode: put
register: upload_file_result

- assert:
that:
- upload_file_result is not changed
- upload_file_result is not failed
- upload_file_result.msg != "PUT operation complete"
- '"s3:PutObject" not in upload_file_result.resource_actions'

always:

- name: Delete the file in the bucket
amazon.aws.s3_object:
bucket: "{{ bucket_name }}-acl-disabled"
src: "{{ remote_tmp_dir }}/acl_disabled_upload_test.txt"
object: "acl_disabled_upload_test.txt"
mode: delobj
retries: 3
delay: 3
ignore_errors: true

- name: Delete bucket created in this test
s3_bucket:
name: "{{ bucket_name }}-acl-disabled"
object_ownership: BucketOwnerEnforced
state: absent
register: delete_result

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you should also remove the temp dir you created.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

- name: Ensure bucket deletion
assert:
that:
- delete_result is changed
- delete_result is not failed
Loading