HDDS-948. MultipartUpload: S3 API for Abort Multipart Upload. Contributed by Bharat Viswanadham.
This commit is contained in:
parent
3c7d700b65
commit
4e0aa2ceac
|
@ -145,6 +145,17 @@ Test Multipart Upload Complete Invalid part
|
|||
${result} = Execute AWSS3APICli and checkrc complete-multipart-upload --upload-id ${uploadID} --bucket ${BUCKET} --key multipartKey3 --multipart-upload 'Parts=[{ETag=etag1,PartNumber=1},{ETag=etag2,PartNumber=2}]' 255
|
||||
Should contain ${result} InvalidPart
|
||||
|
||||
Test abort Multipart upload
|
||||
${result} = Execute AWSS3APICli create-multipart-upload --bucket ${BUCKET} --key multipartKey4 --storage-class REDUCED_REDUNDANCY
|
||||
${uploadID} = Execute and checkrc echo '${result}' | jq -r '.UploadId' 0
|
||||
Should contain ${result} ${BUCKET}
|
||||
Should contain ${result} multipartKey
|
||||
Should contain ${result} UploadId
|
||||
|
||||
${result} = Execute AWSS3APICli and checkrc abort-multipart-upload --bucket ${BUCKET} --key multipartKey4 --upload-id ${uploadID} 0
|
||||
|
||||
Test abort Multipart upload with invalid uploadId
|
||||
${result} = Execute AWSS3APICli and checkrc abort-multipart-upload --bucket ${BUCKET} --key multipartKey5 --upload-id "random" 255
|
||||
|
||||
Upload part with Incorrect uploadID
|
||||
Execute echo "Multipart upload" > /tmp/testfile
|
||||
|
|
|
@ -1016,7 +1016,7 @@ public class KeyManagerImpl implements KeyManager {
|
|||
LOG.error("Abort Multipart Upload Failed: volume: " + volumeName +
|
||||
"bucket: " + bucketName + "key: " + keyName, ex);
|
||||
throw new OMException(ex.getMessage(), ResultCodes
|
||||
.COMPLETE_MULTIPART_UPLOAD_FAILED);
|
||||
.ABORT_MULTIPART_UPLOAD_FAILED);
|
||||
} finally {
|
||||
metadataManager.getLock().releaseBucketLock(volumeName, bucketName);
|
||||
}
|
||||
|
|
|
@ -332,17 +332,50 @@ public class ObjectEndpoint extends EndpointBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete a specific object from a bucket.
|
||||
* Abort multipart upload request.
|
||||
* @param bucket
|
||||
* @param key
|
||||
* @param uploadId
|
||||
* @return Response
|
||||
* @throws IOException
|
||||
* @throws OS3Exception
|
||||
*/
|
||||
private Response abortMultipartUpload(String bucket, String key, String
|
||||
uploadId) throws IOException, OS3Exception {
|
||||
try {
|
||||
OzoneBucket ozoneBucket = getBucket(bucket);
|
||||
ozoneBucket.abortMultipartUpload(key, uploadId);
|
||||
} catch (IOException ex) {
|
||||
if (ex.getMessage().contains("NO_SUCH_MULTIPART_UPLOAD")) {
|
||||
throw S3ErrorTable.newError(S3ErrorTable.NO_SUCH_UPLOAD, uploadId);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
return Response
|
||||
.status(Status.NO_CONTENT)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a specific object from a bucket, if query param uploadId is
|
||||
* specified, this request is for abort multipart upload.
|
||||
* <p>
|
||||
* See: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html
|
||||
* https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadAbort.html
|
||||
* for more details.
|
||||
*/
|
||||
@DELETE
|
||||
public Response delete(
|
||||
@PathParam("bucket") String bucketName,
|
||||
@PathParam("path") String keyPath) throws IOException, OS3Exception {
|
||||
@PathParam("path") String keyPath,
|
||||
@QueryParam("uploadId") @DefaultValue("") String uploadId) throws
|
||||
IOException, OS3Exception {
|
||||
|
||||
try {
|
||||
if (uploadId != null && !uploadId.equals("")) {
|
||||
return abortMultipartUpload(bucketName, keyPath, uploadId);
|
||||
}
|
||||
OzoneBucket bucket = getBucket(bucketName);
|
||||
bucket.getKey(keyPath);
|
||||
bucket.deleteKey(keyPath);
|
||||
|
|
|
@ -223,6 +223,16 @@ public class OzoneBucketStub extends OzoneBucket {
|
|||
DigestUtils.sha256Hex(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abortMultipartUpload(String keyName, String uploadID) throws
|
||||
IOException {
|
||||
if (multipartUploadIdMap.get(keyName) == null) {
|
||||
throw new IOException("NO_SUCH_MULTIPART_UPLOAD");
|
||||
} else {
|
||||
multipartUploadIdMap.remove(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to hold part information in a upload part request.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package org.apache.hadoop.ozone.s3.endpoint;
|
||||
|
||||
import org.apache.hadoop.ozone.client.OzoneClientStub;
|
||||
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
|
||||
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
|
||||
import static org.apache.hadoop.ozone.s3.util.S3Consts.STORAGE_CLASS_HEADER;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* This class tests abort multipart upload request.
|
||||
*/
|
||||
public class TestAbortMultipartUpload {
|
||||
|
||||
|
||||
@Test
|
||||
public void testAbortMultipartUpload() throws Exception {
|
||||
|
||||
String bucket = "s3bucket";
|
||||
String key = "key1";
|
||||
OzoneClientStub client = new OzoneClientStub();
|
||||
client.getObjectStore().createS3Bucket("ozone", bucket);
|
||||
|
||||
HttpHeaders headers = Mockito.mock(HttpHeaders.class);
|
||||
when(headers.getHeaderString(STORAGE_CLASS_HEADER)).thenReturn(
|
||||
"STANDARD");
|
||||
|
||||
ObjectEndpoint rest = new ObjectEndpoint();
|
||||
rest.setHeaders(headers);
|
||||
rest.setClient(client);
|
||||
|
||||
Response response = rest.multipartUpload(bucket, key, "", "", null);
|
||||
|
||||
assertEquals(response.getStatus(), 200);
|
||||
MultipartUploadInitiateResponse multipartUploadInitiateResponse =
|
||||
(MultipartUploadInitiateResponse) response.getEntity();
|
||||
assertNotNull(multipartUploadInitiateResponse.getUploadID());
|
||||
String uploadID = multipartUploadInitiateResponse.getUploadID();
|
||||
|
||||
|
||||
// Abort multipart upload
|
||||
response = rest.delete(bucket, key, uploadID);
|
||||
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
// test with unknown upload Id.
|
||||
try {
|
||||
rest.delete(bucket, key, "random");
|
||||
} catch (OS3Exception ex) {
|
||||
assertEquals(S3ErrorTable.NO_SUCH_UPLOAD.getCode(), ex.getCode());
|
||||
assertEquals(S3ErrorTable.NO_SUCH_UPLOAD.getErrorMessage(),
|
||||
ex.getErrorMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ public class TestObjectDelete {
|
|||
rest.setClient(client);
|
||||
|
||||
//WHEN
|
||||
rest.delete("b1", "key1");
|
||||
rest.delete("b1", "key1", null);
|
||||
|
||||
//THEN
|
||||
Assert.assertFalse("Bucket Should not contain any key after delete",
|
||||
|
|
Loading…
Reference in New Issue