Skip to content

Commit 9530600

Browse files
[DPE-5908] Support old bucket endpoints format (#603)
1 parent 5507e95 commit 9530600

File tree

2 files changed

+69
-15
lines changed

2 files changed

+69
-15
lines changed

lib/charms/mysql/v0/s3_helpers.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from typing import Dict, List, Tuple
2222

2323
import boto3
24+
import botocore
2425

2526
logger = logging.getLogger(__name__)
2627

@@ -32,13 +33,36 @@
3233

3334
# Increment this PATCH version before using `charmcraft publish-lib` or reset
3435
# to 0 if you are raising the major API version
35-
LIBPATCH = 9
36+
LIBPATCH = 10
3637

3738
# botocore/urllib3 clutter the logs when on debug
3839
logging.getLogger("botocore").setLevel(logging.WARNING)
3940
logging.getLogger("urllib3").setLevel(logging.WARNING)
4041

4142

43+
def _construct_endpoint(s3_parameters: dict) -> str:
44+
"""Construct the S3 service endpoint using the region.
45+
46+
This is needed when the provided endpoint is from AWS, and it doesn't contain the region.
47+
"""
48+
# Use the provided endpoint if a region is not needed.
49+
endpoint = s3_parameters["endpoint"]
50+
51+
# Load endpoints data.
52+
loader = botocore.loaders.create_loader()
53+
data = loader.load_data("endpoints")
54+
55+
# Construct the endpoint using the region.
56+
resolver = botocore.regions.EndpointResolver(data)
57+
endpoint_data = resolver.construct_endpoint("s3", s3_parameters["region"])
58+
59+
# Use the built endpoint if it is an AWS endpoint.
60+
if endpoint_data and endpoint.endswith(endpoint_data["dnsSuffix"]):
61+
endpoint = f"{endpoint.split('://')[0]}://{endpoint_data['hostname']}"
62+
63+
return endpoint
64+
65+
4266
def upload_content_to_s3(content: str, content_path: str, s3_parameters: Dict) -> bool:
4367
"""Uploads the provided contents to the provided S3 bucket.
4468
@@ -67,11 +91,7 @@ def upload_content_to_s3(content: str, content_path: str, s3_parameters: Dict) -
6791
ca_file.flush()
6892
verif = ca_file.name
6993

70-
s3 = session.resource(
71-
"s3",
72-
endpoint_url=s3_parameters["endpoint"],
73-
verify=verif,
74-
)
94+
s3 = session.resource("s3", endpoint_url=_construct_endpoint(s3_parameters), verify=verif)
7595

7696
bucket = s3.Bucket(s3_parameters["bucket"])
7797

tests/unit/test_s3_helpers.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def setUp(self) -> None:
1212
self.s3_parameters = {
1313
"access-key": "AK",
1414
"secret-key": "SK",
15-
"region": "AS-1",
15+
"region": "us-east-1",
1616
"bucket": "balde",
1717
"endpoint": "http://localhost:9000",
1818
}
@@ -44,16 +44,50 @@ def test_upload_content_with_ca_chain(self, mock_boto):
4444
mock_session.resource.return_value = mock_resource
4545
mock_resource.Bucket.return_value = mock_bucket
4646

47-
s3_parameters = {
48-
"access-key": "AK",
49-
"secret-key": "SK",
50-
"region": "AS-1",
51-
"bucket": "balde",
52-
"endpoint": "http://localhost:9000",
53-
"tls-ca-chain": ["Zm9vYmFy"],
54-
}
47+
s3_parameters = self.s3_parameters
48+
s3_parameters["tls-ca-chain"] = ["Zm9vYmFy"]
5549

5650
upload_content_to_s3("content", "key", s3_parameters)
5751

5852
mock_bucket.upload_file.assert_called_once()
5953
mock_session.resource.assert_called_once()
54+
55+
@patch("lib.charms.mysql.v0.s3_helpers.boto3")
56+
def test_upload_content_with_new_bucket_endpoint(self, mock_boto):
57+
mock_session = MagicMock()
58+
mock_resource = MagicMock()
59+
mock_bucket = MagicMock()
60+
61+
mock_boto.session.Session.return_value = mock_session
62+
mock_session.resource.return_value = mock_resource
63+
mock_resource.Bucket.return_value = mock_bucket
64+
65+
s3_parameters = self.s3_parameters
66+
s3_parameters["endpoint"] = "https://s3.us-east-1.amazonaws.com"
67+
68+
upload_content_to_s3("content", "key", s3_parameters)
69+
70+
mock_bucket.upload_file.assert_called_once()
71+
mock_session.resource.assert_called_with(
72+
"s3", endpoint_url="https://s3.us-east-1.amazonaws.com", verify=True
73+
)
74+
75+
@patch("lib.charms.mysql.v0.s3_helpers.boto3")
76+
def test_upload_content_with_old_bucket_endpoint(self, mock_boto):
77+
mock_session = MagicMock()
78+
mock_resource = MagicMock()
79+
mock_bucket = MagicMock()
80+
81+
mock_boto.session.Session.return_value = mock_session
82+
mock_session.resource.return_value = mock_resource
83+
mock_resource.Bucket.return_value = mock_bucket
84+
85+
s3_parameters = self.s3_parameters
86+
s3_parameters["endpoint"] = "https://s3.amazonaws.com"
87+
88+
upload_content_to_s3("content", "key", s3_parameters)
89+
90+
mock_bucket.upload_file.assert_called_once()
91+
mock_session.resource.assert_called_with(
92+
"s3", endpoint_url="https://s3.us-east-1.amazonaws.com", verify=True
93+
)

0 commit comments

Comments
 (0)