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_bucket transfer accleration #2046

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/s3_bucket-accelerate_option.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- s3_bucket - Add support for enabling Amazon S3 Transfer Acceleration by setting the ``accelerate_enabled`` option (https://github.com/ansible-collections/amazon.aws/pull/2046).
107 changes: 107 additions & 0 deletions plugins/modules/s3_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@
type: bool
default: false
version_added: 6.0.0
accelerate_enabled:
description:
- Enables Amazon S3 Transfer Acceleration, sent data will be routed to Amazon S3 over an optimized network path.
type: bool
default: false
version_added: 8.1.0

extends_documentation_fragment:
- amazon.aws.common.modules
Expand Down Expand Up @@ -286,6 +292,12 @@
name: mys3bucket
state: present
acl: public-read

# Enable transfer acceleration
- amazon.aws.s3_bucket:
name: mys3bucket
state: present
accelerate_enabled: true
"""

RETURN = r"""
hakbailey marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -391,6 +403,11 @@
RestrictPublicBuckets:
description: Specifies whether Amazon S3 should restrict public bucket policies for this bucket.
type: bool
accelerate_enabled:
description: S3 bucket acceleration status.
type: bool
returned: O(state=present)
sample: true
"""

import json
Expand Down Expand Up @@ -874,6 +891,49 @@ def handle_bucket_object_lock(s3_client, module: AnsibleAWSModule, name: str) ->
return object_lock_result


def handle_bucket_accelerate(s3_client, module: AnsibleAWSModule, name: str) -> tuple[bool, bool]:
"""
Manage transfer accelerate for an S3 bucket.
Parameters:
s3_client (boto3.client): The Boto3 S3 client object.
module (AnsibleAWSModule): The Ansible module object.
name (str): The name of the bucket to handle transfer accelerate for.
Returns:
A tuple containing a boolean indicating whether transfer accelerate setting was changed
and a boolean indicating the transfer accelerate status.
"""
accelerate_enabled = module.params.get("accelerate_enabled")
accelerate_enabled_result = False
accelerate_enabled_changed = False
try:
accelerate_status = get_bucket_accelerate_status(s3_client, name)
accelerate_enabled_result = accelerate_status
except is_boto3_error_code(["NotImplemented", "XNotImplemented"]) as e:
if accelerate_enabled is not None:
module.fail_json_aws(e, msg="Fetching bucket transfer acceleration state is not supported")
except is_boto3_error_code("AccessDenied") as e: # pylint: disable=duplicate-except
if accelerate_enabled is not None:
module.fail_json_aws(e, msg="Permission denied fetching transfer acceleration for bucket")
except (
botocore.exceptions.BotoCoreError,
botocore.exceptions.ClientError,
) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to fetch bucket transfer acceleration state")
else:
try:
if not accelerate_enabled and accelerate_status:
delete_bucket_accelerate_configuration(s3_client, name)
accelerate_enabled_changed = True
accelerate_enabled_result = False
if accelerate_enabled and not accelerate_status:
put_bucket_accelerate_configuration(s3_client, name)
accelerate_enabled_changed = True
accelerate_enabled_result = True
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to update bucket transfer acceleration")
return accelerate_enabled_changed, accelerate_enabled_result


def create_or_update_bucket(s3_client, module: AnsibleAWSModule):
"""
Create or update an S3 bucket along with its associated configurations.
Expand Down Expand Up @@ -950,6 +1010,10 @@ def create_or_update_bucket(s3_client, module: AnsibleAWSModule):
bucket_object_lock_result = handle_bucket_object_lock(s3_client, module, name)
result["object_lock_enabled"] = bucket_object_lock_result

# -- Transfer Acceleration
bucket_accelerate_changed, bucket_accelerate_result = handle_bucket_accelerate(s3_client, module, name)
result["accelerate_enabled"] = bucket_accelerate_result

# Module exit
changed = (
changed
Expand All @@ -961,6 +1025,7 @@ def create_or_update_bucket(s3_client, module: AnsibleAWSModule):
or encryption_changed
or bucket_ownership_changed
or bucket_acl_changed
or bucket_accelerate_changed
)
module.exit_json(changed=changed, name=name, **result)

Expand Down Expand Up @@ -1015,6 +1080,47 @@ def create_bucket(s3_client, bucket_name: str, location: str, object_lock_enable
return False


@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=["NoSuchBucket", "OperationAborted"])
def put_bucket_accelerate_configuration(s3_client, bucket_name):
"""
Enable transfer accelerate for the S3 bucket.
Parameters:
s3_client (boto3.client): The Boto3 S3 client object.
bucket_name (str): The name of the S3 bucket.
Returns:
None
"""
s3_client.put_bucket_accelerate_configuration(Bucket=bucket_name, AccelerateConfiguration={"Status": "Enabled"})


@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=["NoSuchBucket", "OperationAborted"])
def delete_bucket_accelerate_configuration(s3_client, bucket_name):
"""
Disable transfer accelerate for the S3 bucket.
Parameters:
s3_client (boto3.client): The Boto3 S3 client object.
bucket_name (str): The name of the S3 bucket.
Returns:
None
"""

s3_client.put_bucket_accelerate_configuration(Bucket=bucket_name, AccelerateConfiguration={"Status": "Suspended"})


@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=["NoSuchBucket", "OperationAborted"])
def get_bucket_accelerate_status(s3_client, bucket_name) -> bool:
"""
Get transfer accelerate status of the S3 bucket.
Parameters:
s3_client (boto3.client): The Boto3 S3 client object.
bucket_name (str): The name of the S3 bucket.
Returns:
Transfer accelerate status of the S3 bucket.
"""
accelerate_configuration = s3_client.get_bucket_accelerate_configuration(Bucket=bucket_name)
return accelerate_configuration.get("Status") == "Enabled"


@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=["NoSuchBucket", "OperationAborted"])
def put_bucket_tagging(s3_client, bucket_name: str, tags: dict):
"""
Expand Down Expand Up @@ -1774,6 +1880,7 @@ def main():
acl=dict(type="str", choices=["private", "public-read", "public-read-write", "authenticated-read"]),
validate_bucket_name=dict(type="bool", default=True),
dualstack=dict(default=False, type="bool"),
accelerate_enabled=dict(default=False, type="bool"),
object_lock_enabled=dict(type="bool"),
)

Expand Down
1 change: 1 addition & 0 deletions tests/integration/targets/s3_bucket/inventory
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ encryption_sse
public_access
acl
object_lock
accelerate

[all:vars]
ansible_connection=local
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
---
- module_defaults:
group/aws:
access_key: "{{ aws_access_key }}"
secret_key: "{{ aws_secret_key }}"
session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- ansible.builtin.set_fact:
local_bucket_name: "{{ bucket_name | hash('md5')}}-accelerate"

# ============================================================

- name: Create a simple bucket
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: present
register: output

- ansible.builtin.assert:
that:
- output.changed
- not output.accelerate_enabled

- name: Re-disable transfer acceleration (idempotency)
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: present
accelerate_enabled: false
register: output

- ansible.builtin.assert:
that:
- not output.changed
- not output.accelerate_enabled

- name: Enable transfer acceleration
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: present
accelerate_enabled: true
register: output
ignore_errors: false

- ansible.builtin.assert:
that:
- output.changed
- output.accelerate_enabled
hakbailey marked this conversation as resolved.
Show resolved Hide resolved

- name: Assert transfer acceleration enabled
amazon.aws.s3_bucket_info:
name: "{{ local_bucket_name }}"
bucket_facts:
bucket_accelerate_configuration: true
register: output

- ansible.builtin.assert:
that:
- item.bucket_accelerate_configuration["Status"] == "Enabled"
loop: "{{ output.buckets }}"
loop_control:
label: "{{ item.name }}"

- name: Re-Enable transfer acceleration (idempotency)
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: present
accelerate_enabled: true
register: output

- ansible.builtin.assert:
that:
- not output.changed
- output.accelerate_enabled

- name: Assert transfer acceleration enabled
amazon.aws.s3_bucket_info:
name: "{{ local_bucket_name }}"
bucket_facts:
bucket_accelerate_configuration: true
register: output

- ansible.builtin.assert:
that:
- item.bucket_accelerate_configuration["Status"] == "Enabled"
loop: "{{ output.buckets }}"
loop_control:
label: "{{ item.name }}"

- name: Delete test s3 bucket
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: absent
register: output

- ansible.builtin.assert:
that:
- output.changed

# ============================================================

- name: Create a bucket with transfer accelerate enabled
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: present
accelerate_enabled: true
register: output

- ansible.builtin.assert:
that:
- output.changed
- output.accelerate_enabled

- name: Assert transfer acceleration enabled
amazon.aws.s3_bucket_info:
name: "{{ local_bucket_name }}"
bucket_facts:
bucket_accelerate_configuration: true
register: output

- ansible.builtin.assert:
that:
- item.bucket_accelerate_configuration["Status"] == "Enabled"
loop: "{{ output.buckets }}"
loop_control:
label: "{{ item.name }}"

- name: Disable transfer accelerate
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: present
accelerate_enabled: false
register: output
ignore_errors: false

- ansible.builtin.assert:
that:
- output.changed
- not output.accelerate_enabled

- name: Assert transfer acceleration disabled
amazon.aws.s3_bucket_info:
name: "{{ local_bucket_name }}"
bucket_facts:
bucket_accelerate_configuration: true
register: output

- ansible.builtin.assert:
that:
- item.bucket_accelerate_configuration["Status"] == "Disabled"
loop: "{{ output.buckets }}"
loop_control:
label: "{{ item.name }}"

- name: Re-Enable transfer accelerate (idempotency)
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: present
accelerate_enabled: true
register: output

- ansible.builtin.assert:
that:
- output.changed
- output.accelerate_enabled

- name: Assert transfer acceleration enabled
amazon.aws.s3_bucket_info:
name: "{{ local_bucket_name }}"
bucket_facts:
bucket_accelerate_configuration: true
register: output

- ansible.builtin.assert:
that:
- item.bucket_accelerate_configuration["Status"] == "Enabled"
loop: "{{ output.buckets }}"
loop_control:
label: "{{ item.name }}"

- name: Touch bucket with transfer accelerate enabled (idempotency)
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: present
accelerate_enabled: true
register: output

- ansible.builtin.assert:
that:
- not output.changed
- output.accelerate_enabled

- name: Delete test s3 bucket
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: absent
register: output

- ansible.builtin.assert:
that:
- output.changed

# ============================================================
always:
- name: Ensure all buckets are deleted
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}"
state: absent
ignore_errors: true

- name: Ensure all buckets are deleted
amazon.aws.s3_bucket:
name: "{{ local_bucket_name }}-2"
state: absent
ignore_errors: true
Loading