Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 87d01c3

Browse files
authored
implement s3 native multipart (#8787)
1 parent 56b93e4 commit 87d01c3

File tree

5 files changed

+670
-18
lines changed

5 files changed

+670
-18
lines changed

‎localstack/aws/api/s3/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,29 @@ class BucketNotEmpty(ServiceException):
808808
BucketName: Optional[BucketName]
809809

810810

811+
ProposedSize = int
812+
MinSizeAllowed = int
813+
814+
815+
class EntityTooSmall(ServiceException):
816+
code: str = "EntityTooSmall"
817+
sender_fault: bool = False
818+
status_code: int = 400
819+
ETag: Optional[ETag]
820+
MinSizeAllowed: Optional[MinSizeAllowed]
821+
PartNumber: Optional[PartNumber]
822+
ProposedSize: Optional[ProposedSize]
823+
824+
825+
class InvalidPart(ServiceException):
826+
code: str = "InvalidPart"
827+
sender_fault: bool = False
828+
status_code: int = 400
829+
ETag: Optional[ETag]
830+
UploadId: Optional[MultipartUploadId]
831+
PartNumber: Optional[PartNumber]
832+
833+
811834
AbortDate = datetime
812835

813836

‎localstack/aws/spec-patches.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,63 @@
928928
"documentation": "<p>The bucket you tried to delete is not empty</p>",
929929
"exception": true
930930
}
931+
},
932+
{
933+
"op": "add",
934+
"path": "/shapes/MinSizeAllowed",
935+
"value": {
936+
"type": "long"
937+
}
938+
},
939+
{
940+
"op": "add",
941+
"path": "/shapes/ProposedSize",
942+
"value": {
943+
"type": "long"
944+
}
945+
},
946+
{
947+
"op": "add",
948+
"path": "/shapes/EntityTooSmall",
949+
"value": {
950+
"type": "structure",
951+
"members": {
952+
"ETag": {
953+
"shape": "ETag"
954+
},
955+
"MinSizeAllowed": {
956+
"shape": "MinSizeAllowed"
957+
},
958+
"PartNumber": {
959+
"shape": "PartNumber"
960+
},
961+
"ProposedSize": {
962+
"shape": "ProposedSize"
963+
}
964+
},
965+
"documentation": "<p>Your proposed upload is smaller than the minimum allowed object size. Each part must be at least 5 MB in size, except the last part.</p>",
966+
"exception": true
967+
}
968+
},
969+
{
970+
"op": "add",
971+
"path": "/shapes/InvalidPart",
972+
"value": {
973+
"type": "structure",
974+
"members": {
975+
"ETag": {
976+
"shape": "ETag"
977+
},
978+
"UploadId": {
979+
"shape": "MultipartUploadId"
980+
},
981+
"PartNumber": {
982+
"shape": "PartNumber"
983+
}
984+
},
985+
"documentation": "<p>One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag.</p>",
986+
"exception": true
987+
}
931988
}
932989
]
933990
}

‎localstack/services/s3/v3/models.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Literal, Optional, Union
77

88
from localstack import config
9-
from localstack.aws.api.s3 import ( # EntityTooSmall,; InvalidPart,
9+
from localstack.aws.api.s3 import (
1010
AccountId,
1111
AnalyticsConfiguration,
1212
AnalyticsId,
@@ -17,11 +17,13 @@
1717
ChecksumAlgorithm,
1818
CompletedPartList,
1919
CORSConfiguration,
20+
EntityTooSmall,
2021
ETag,
2122
Expiration,
2223
IntelligentTieringConfiguration,
2324
IntelligentTieringId,
2425
InvalidArgument,
26+
InvalidPart,
2527
LifecycleRules,
2628
LoggingEnabled,
2729
Metadata,
@@ -405,28 +407,26 @@ def complete_multipart(self, parts: CompletedPartList):
405407

406408
s3_part = self.parts.get(part_number)
407409
if not s3_part or s3_part.etag != part_etag:
408-
raise
409-
# raise InvalidPart(
410-
# "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.",
411-
# ETag=part_etag,
412-
# PartNumber=part_number,
413-
# UploadId=self.id,
414-
# )
410+
raise InvalidPart(
411+
"One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.",
412+
ETag=part_etag,
413+
PartNumber=part_number,
414+
UploadId=self.id,
415+
)
415416

416417
# TODO: this part is currently not implemented, time permitting
417418
# part_checksum = part.get(checksum_key) if self.object.checksum_algorithm else None
418419
# if part_checksum and part_checksum != s3_part.checksum_value:
419420
# raise Exception()
420421

421422
if index != last_part_index and s3_part.size < S3_UPLOAD_PART_MIN_SIZE:
422-
raise
423-
# raise EntityTooSmall(
424-
# "Your proposed upload is smaller than the minimum allowed size",
425-
# ETag=part_etag,
426-
# PartNumber=part_number,
427-
# MinSizeAllowed=S3_UPLOAD_PART_MIN_SIZE,
428-
# ProposedSize=s3_part.size,
429-
# )
423+
raise EntityTooSmall(
424+
"Your proposed upload is smaller than the minimum allowed size",
425+
ETag=part_etag,
426+
PartNumber=part_number,
427+
MinSizeAllowed=S3_UPLOAD_PART_MIN_SIZE,
428+
ProposedSize=s3_part.size,
429+
)
430430

431431
object_etag.update(bytes.fromhex(s3_part.etag))
432432
# TODO verify this, it seems wrong

0 commit comments

Comments
 (0)