Skip to content

Commit

Permalink
s3_bucket - fix transfer acceleration issue with AWS GovCloud (ansibl…
Browse files Browse the repository at this point in the history
…e-collections#2194)

SUMMARY

Closes ansible-collections#2180
Transfer acceleration is not available for AWS GovCloud region, this PR performs the following changes

GetBucketAccelerateConfiguration operation is performed only if the user has provided accelerate_enabled option
When GetBucketAccelerateConfiguration raises an UnsupportedArgument botocore exception, the module will display a warning message
accelerate_enabled is set in the output only if it was provided as input


ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

s3_bucket

Reviewed-by: Mike Graves <[email protected]>
Reviewed-by: Mandar Kulkarni <[email protected]>
Reviewed-by: Bikouo Aubin
Reviewed-by: Helen Bailey <[email protected]>
  • Loading branch information
abikouo authored Jul 23, 2024
1 parent e219e0c commit 7d6a5ef
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- s3_bucket - catch ``UnsupportedArgument`` when calling API ``GetBucketAccelerationConfig`` on region where it is not supported (https://github.com/ansible-collections/amazon.aws/issues/2180).
9 changes: 8 additions & 1 deletion plugins/modules/s3_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
description:
- Whether the bucket name should be validated to conform to AWS S3 naming rules.
- On by default, this may be disabled for S3 backends that do not enforce these rules.
- See https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
- See U(https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html).
type: bool
version_added: 3.1.0
default: true
Expand All @@ -169,6 +169,8 @@
accelerate_enabled:
description:
- Enables Amazon S3 Transfer Acceleration, sent data will be routed to Amazon S3 over an optimized network path.
- Transfer Acceleration is not available in AWS GovCloud (US).
- See U(https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-s3.html#govcloud-S3-diffs).
type: bool
default: false
version_added: 8.1.0
Expand Down Expand Up @@ -953,6 +955,11 @@ def handle_bucket_accelerate(s3_client, module: AnsibleAWSModule, name: str) ->
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("UnsupportedArgument") as e: # pylint: disable=duplicate-except
# -- Transfer Acceleration is not available in AWS GovCloud (US).
# -- https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-s3.html#govcloud-S3-diffs
module.warn("Tranfer acceleration is not available in S3 bucket region.")
accelerate_enabled_result = False
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")
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from unittest.mock import MagicMock
from unittest.mock import patch
from unittest.mock import sentinel

import botocore
import pytest

from ansible_collections.amazon.aws.plugins.modules.s3_bucket import handle_bucket_accelerate

module_name = "ansible_collections.amazon.aws.plugins.modules.s3_bucket"


def a_botocore_exception(message):
return botocore.exceptions.ClientError({"Error": {"Code": message}}, sentinel.BOTOCORE_ACTION)


@pytest.fixture
def ansible_module():
mock = MagicMock()
mock.params = {"accelerate_enabled": sentinel.ACCELERATE_ENABLED}
mock.fail_json_aws.side_effect = SystemExit(1)
return mock


@pytest.mark.parametrize(
"code,message",
[
("NotImplemented", "Fetching bucket transfer acceleration state is not supported"),
("XNotImplemented", "Fetching bucket transfer acceleration state is not supported"),
("AccessDenied", "Permission denied fetching transfer acceleration for bucket"),
(sentinel.BOTO_CLIENT_ERROR, "Failed to fetch bucket transfer acceleration state"),
],
)
@patch(module_name + ".get_bucket_accelerate_status")
def test_failure(m_get_bucket_accelerate_status, ansible_module, code, message):
bucket_name = sentinel.BUCKET_NAME
client = MagicMock()
exc = a_botocore_exception(code)
m_get_bucket_accelerate_status.side_effect = exc
with pytest.raises(SystemExit):
handle_bucket_accelerate(client, ansible_module, bucket_name)
ansible_module.fail_json_aws.assert_called_once_with(exc, msg=message)


@patch(module_name + ".get_bucket_accelerate_status")
def test_unsupported(m_get_bucket_accelerate_status, ansible_module):
bucket_name = sentinel.BUCKET_NAME
client = MagicMock()
m_get_bucket_accelerate_status.side_effect = a_botocore_exception("UnsupportedArgument")
changed, result = handle_bucket_accelerate(client, ansible_module, bucket_name)
assert changed is False
assert result is False
ansible_module.warn.assert_called_once()


@pytest.mark.parametrize("accelerate_enabled", [True, False])
@patch(module_name + ".delete_bucket_accelerate_configuration")
@patch(module_name + ".get_bucket_accelerate_status")
def test_delete(
m_get_bucket_accelerate_status, m_delete_bucket_accelerate_configuration, ansible_module, accelerate_enabled
):
bucket_name = sentinel.BUCKET_NAME
client = MagicMock()
ansible_module.params.update({"accelerate_enabled": accelerate_enabled})
m_get_bucket_accelerate_status.return_value = True
if not accelerate_enabled:
assert (True, False) == handle_bucket_accelerate(client, ansible_module, bucket_name)
m_delete_bucket_accelerate_configuration.assert_called_once_with(client, bucket_name)
else:
assert (False, True) == handle_bucket_accelerate(client, ansible_module, bucket_name)
m_delete_bucket_accelerate_configuration.assert_not_called()


@pytest.mark.parametrize("accelerate_enabled", [True, False])
@patch(module_name + ".put_bucket_accelerate_configuration")
@patch(module_name + ".get_bucket_accelerate_status")
def test_put(m_get_bucket_accelerate_status, m_put_bucket_accelerate_configuration, ansible_module, accelerate_enabled):
bucket_name = sentinel.BUCKET_NAME
client = MagicMock()
ansible_module.params.update({"accelerate_enabled": accelerate_enabled})
m_get_bucket_accelerate_status.return_value = False
if accelerate_enabled:
assert (True, True) == handle_bucket_accelerate(client, ansible_module, bucket_name)
m_put_bucket_accelerate_configuration.assert_called_once_with(client, bucket_name)
else:
assert (False, False) == handle_bucket_accelerate(client, ansible_module, bucket_name)
m_put_bucket_accelerate_configuration.assert_not_called()

0 comments on commit 7d6a5ef

Please sign in to comment.