88from abc import ABCMeta , abstractmethod
99from datetime import datetime
1010from enum import Enum
11+ from typing import Optional
1112
1213import boto3
1314from boto3 .s3 .transfer import TransferConfig
14-
15+ from botocore . config import Config
1516# pylint: disable=unused-import
1617from botocore .exceptions import ClientError as CloudFileNotFoundError
1718from pydantic .v1 import BaseModel , Field
@@ -110,12 +111,14 @@ class _UserCredential(BaseModel):
110111 expiration : datetime
111112 secret_access_key : str = Field (alias = "secretAccessKey" )
112113 session_token : str = Field (alias = "sessionToken" )
114+ storage_provider : Optional [str ] = Field (alias = "storageProvider" , default = None )
113115
114116
115117class _S3STSToken (BaseModel ):
116118 cloud_path_prefix : str = Field (alias = "cloudpathPrefix" )
117119 cloud_path : str = Field (alias = "cloudpath" )
118120 user_credential : _UserCredential = Field (alias = "userCredentials" )
121+ endpoint : Optional [str ] = Field (alias = "endpoint" , default = None )
119122
120123 def get_bucket (self ):
121124 """
@@ -138,14 +141,28 @@ def get_client(self):
138141 Get s3 client.
139142 :return:
140143 """
144+ customize_boto3_config = None
145+ if (self .user_credential is not None
146+ and self .user_credential .storage_provider is not None
147+ and self .user_credential .storage_provider == "OSS" ):
148+ # OSS does not support aws integrity check
149+ customize_boto3_config = Config (request_checksum_calculation = "when_required" ,
150+ response_checksum_validation = "when_required" ,
151+ s3 = {
152+ "addressing_style" : "virtual"
153+ })
141154 # pylint: disable=no-member
142155 kwargs = {
143156 "region_name" : Env .current .aws_region ,
144157 "aws_access_key_id" : self .user_credential .access_key_id ,
145158 "aws_secret_access_key" : self .user_credential .secret_access_key ,
146159 "aws_session_token" : self .user_credential .session_token ,
160+ "config" : customize_boto3_config
147161 }
148162
163+ if self .endpoint is not None :
164+ kwargs ["endpoint_url" ] = self .endpoint
165+
149166 if Env .current .s3_endpoint_url is not None :
150167 kwargs ["endpoint_url" ] = Env .current .s3_endpoint_url
151168
@@ -158,8 +175,8 @@ def is_expired(self):
158175 """
159176 # pylint: disable=no-member
160177 return (
161- self .user_credential .expiration
162- - datetime .now (tz = self .user_credential .expiration .tzinfo )
178+ self .user_credential .expiration
179+ - datetime .now (tz = self .user_credential .expiration .tzinfo )
163180 ).total_seconds () < 300
164181
165182
@@ -203,9 +220,9 @@ def get_cloud_path_prefix(self, resource_id, file_name):
203220 return base_path
204221
205222 def create_multipart_upload (
206- self ,
207- resource_id : str ,
208- remote_file_name : str ,
223+ self ,
224+ resource_id : str ,
225+ remote_file_name : str ,
209226 ):
210227 """
211228 Creates a multipart upload for the specified resource ID and remote file name.
@@ -226,12 +243,12 @@ def create_multipart_upload(
226243
227244 # pylint: disable=too-many-arguments
228245 def upload_part (
229- self ,
230- resource_id : str ,
231- remote_file_name : str ,
232- upload_id : str ,
233- part_number : int ,
234- compressed_chunk ,
246+ self ,
247+ resource_id : str ,
248+ remote_file_name : str ,
249+ upload_id : str ,
250+ part_number : int ,
251+ compressed_chunk ,
235252 ):
236253 """
237254 Uploads a part of the file as part of a multipart upload.
@@ -260,7 +277,7 @@ def upload_part(
260277 return {"ETag" : response ["ETag" ], "PartNumber" : part_number }
261278
262279 def complete_multipart_upload (
263- self , resource_id : str , remote_file_name : str , upload_id : str , uploaded_parts : dict
280+ self , resource_id : str , remote_file_name : str , upload_id : str , uploaded_parts : dict
264281 ):
265282 """
266283 Completes a multipart upload for the specified resource ID, remote file name, upload ID, e_tag, and part number.
@@ -285,7 +302,7 @@ def complete_multipart_upload(
285302 )
286303
287304 def upload_file (
288- self , resource_id : str , remote_file_name : str , file_name : str , progress_callback = None
305+ self , resource_id : str , remote_file_name : str , file_name : str , progress_callback = None
289306 ):
290307 """
291308 Upload a file to s3.
@@ -328,15 +345,15 @@ def _call_back(bytes_in_chunk):
328345
329346 # pylint: disable=too-many-arguments
330347 def download_file (
331- self ,
332- resource_id : str ,
333- remote_file_name : str ,
334- to_file : str = None ,
335- to_folder : str = "." ,
336- overwrite : bool = True ,
337- progress_callback = None ,
338- log_error = True ,
339- verbose = True ,
348+ self ,
349+ resource_id : str ,
350+ remote_file_name : str ,
351+ to_file : str = None ,
352+ to_folder : str = "." ,
353+ overwrite : bool = True ,
354+ progress_callback = None ,
355+ log_error = True ,
356+ verbose = True ,
340357 ):
341358 """
342359 Download a file from s3.
0 commit comments