This is an automated email from the ASF dual-hosted git repository.
chungen0126 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new c8fa8dafd5c HDDS-16101. Extract bucket lifecycle operations into
dedicated handler (#10969)
c8fa8dafd5c is described below
commit c8fa8dafd5cd42e729ef7b9ae1f581a6765a336c
Author: YANG-SYUAN CHOU <[email protected]>
AuthorDate: Mon Aug 10 14:15:40 2026 +0800
HDDS-16101. Extract bucket lifecycle operations into dedicated handler
(#10969)
---
.../ozone/s3/endpoint/BucketCrudHandler.java | 126 +--------------------
.../hadoop/ozone/s3/endpoint/BucketEndpoint.java | 1 +
...rudHandler.java => BucketLifecycleHandler.java} | 97 +++-------------
3 files changed, 21 insertions(+), 203 deletions(-)
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
index 6b716993ef0..3d4cc4d6ad5 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
@@ -17,25 +17,15 @@
package org.apache.hadoop.ozone.s3.endpoint;
-import static
org.apache.hadoop.ozone.s3.util.S3Consts.EXPECTED_BUCKET_OWNER_HEADER;
-
import java.io.IOException;
import java.io.InputStream;
-import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.hadoop.ozone.audit.S3GAction;
import org.apache.hadoop.ozone.client.OzoneBucket;
-import org.apache.hadoop.ozone.client.OzoneLifecycleConfiguration;
-import org.apache.hadoop.ozone.om.exceptions.OMException;
-import org.apache.hadoop.ozone.om.helpers.OmLifecycleConfiguration;
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
-import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
import org.apache.http.HttpStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Handler for default bucket CRUD operations.
@@ -50,7 +40,6 @@
* (configuration, headers, request context, audit logging, metrics, etc.).
*/
public class BucketCrudHandler extends BucketOperationHandler {
- private static final Logger LOG =
LoggerFactory.getLogger(BucketCrudHandler.class);
/**
* Handle only plain PUT bucket (create bucket), not subresources.
@@ -59,22 +48,8 @@ private boolean shouldHandle() {
return queryParams().get(QueryParams.ACL) == null
&& queryParams().get(QueryParams.UPLOADS) == null
&& queryParams().get(QueryParams.DELETE) == null
- && queryParams().get(QueryParams.TAGGING) == null;
- }
-
- /**
- * Handle GET /{bucket} for bucket LIFECYCLE configuration.
- */
- @Override
- Response handleGetRequest(S3RequestContext context, String bucketName)
- throws IOException, OS3Exception {
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
-
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.GET_BUCKET_LIFECYCLE);
- return getBucketLifecycleConfiguration(context, bucketName);
- }
- return null;
+ && queryParams().get(QueryParams.TAGGING) == null
+ && queryParams().get(QueryParams.LIFECYCLE) == null;
}
/**
@@ -84,12 +59,6 @@ Response handleGetRequest(S3RequestContext context, String
bucketName)
Response handlePutRequest(S3RequestContext context, String bucketName,
InputStream body)
throws IOException, OS3Exception {
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.PUT_BUCKET_LIFECYCLE);
- return putBucketLifecycleConfiguration(context, bucketName, body);
- }
-
if (!shouldHandle()) {
return null;
}
@@ -115,12 +84,6 @@ Response handlePutRequest(S3RequestContext context, String
bucketName, InputStre
Response handleDeleteRequest(S3RequestContext context, String bucketName)
throws IOException, OS3Exception {
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.DELETE_BUCKET_LIFECYCLE);
- return deleteBucketLifecycleConfiguration(context, bucketName);
- }
-
if (!shouldHandle()) {
return null;
}
@@ -143,89 +106,4 @@ Response handleDeleteRequest(S3RequestContext context,
String bucketName)
.status(HttpStatus.SC_NO_CONTENT)
.build();
}
-
- public Response deleteBucketLifecycleConfiguration(S3RequestContext context,
String bucketName)
- throws IOException, OS3Exception {
- verifyBucketOwner(context, bucketName);
- deleteLifecycleConfiguration(context, bucketName);
- return Response.noContent().build();
- }
-
- protected void deleteLifecycleConfiguration(S3RequestContext context, String
bucketName)
- throws IOException, OS3Exception {
- try {
- context.getVolume().getBucket(bucketName).deleteLifecycleConfiguration();
- } catch (OMException ex) {
- // DeleteBucketLifecycle is idempotent: deleting a missing config
- // must still return 204, not 404 — same as normal key deletion.
- if (ex.getResult() !=
OMException.ResultCodes.LIFECYCLE_CONFIGURATION_NOT_FOUND) {
- throw S3ErrorTable.newError(bucketName, ex);
- }
- }
- }
-
- private void verifyBucketOwner(S3RequestContext context, String bucketName)
throws OS3Exception {
- HttpHeaders httpHeaders = getHeaders();
- if (httpHeaders == null) {
- return;
- }
- String expectedBucketOwner =
httpHeaders.getHeaderString(EXPECTED_BUCKET_OWNER_HEADER);
- if (expectedBucketOwner == null || expectedBucketOwner.isEmpty()) {
- return;
- }
-
- try {
- String actualOwner =
context.getVolume().getBucket(bucketName).getOwner();
- if (actualOwner != null && !actualOwner.equals(expectedBucketOwner)) {
- LOG.debug("Bucket: {}, ExpectedBucketOwner: {}, ActualBucketOwner: {}",
- bucketName, expectedBucketOwner, actualOwner);
- throw S3ErrorTable.newError(S3ErrorTable.ACCESS_DENIED, bucketName);
- }
- } catch (Exception ex) {
- LOG.error("Owner verification failed for bucket: {}", bucketName, ex);
- throw S3ErrorTable.newError(S3ErrorTable.ACCESS_DENIED, bucketName);
- }
- }
-
- public Response putBucketLifecycleConfiguration(S3RequestContext context,
String bucketName, InputStream body)
- throws IOException, OS3Exception {
- verifyBucketOwner(context, bucketName);
- S3LifecycleConfiguration s3LifecycleConfiguration;
- OzoneBucket ozoneBucket = context.getVolume().getBucket(bucketName);
- try {
- s3LifecycleConfiguration = new
PutBucketLifecycleConfigurationUnmarshaller().readFrom(null,
- null, null, null, null, body);
- OmLifecycleConfiguration lcc =
- s3LifecycleConfiguration.toOmLifecycleConfiguration(ozoneBucket);
- ozoneBucket.setLifecycleConfiguration(lcc);
- } catch (WebApplicationException ex) {
- throw S3ErrorTable.newError(S3ErrorTable.MALFORMED_XML, bucketName);
- } catch (OMException ex) {
- throw S3ErrorTable.newError(bucketName, ex);
- }
- return Response.ok().build();
- }
-
- public Response getBucketLifecycleConfiguration(S3RequestContext context,
String bucketName)
- throws IOException, OS3Exception {
- verifyBucketOwner(context, bucketName);
- OzoneLifecycleConfiguration ozoneLifecycleConfiguration =
- getLifecycleConfiguration(context, bucketName);
- return
Response.ok(S3LifecycleConfiguration.fromOzoneLifecycleConfiguration(
- ozoneLifecycleConfiguration), MediaType.APPLICATION_XML_TYPE).build();
- }
-
- protected OzoneLifecycleConfiguration getLifecycleConfiguration(
- S3RequestContext context, String bucketName) throws IOException,
OS3Exception {
- try {
- OzoneBucket ozoneBucket = context.getVolume().getBucket(bucketName);
- return ozoneBucket.getLifecycleConfiguration();
- } catch (OMException ex) {
- if (ex.getResult() ==
OMException.ResultCodes.LIFECYCLE_CONFIGURATION_NOT_FOUND) {
- throw S3ErrorTable.newError(
- S3ErrorTable.NO_SUCH_LIFECYCLE_CONFIGURATION, bucketName);
- }
- throw ex;
- }
- }
}
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
index 7840f195d0f..aac2c392064 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
@@ -435,6 +435,7 @@ protected void init() {
.add(new BucketAclHandler())
.add(new ListMultipartUploadsHandler())
.add(new BucketTaggingHandler())
+ .add(new BucketLifecycleHandler())
.add(new BucketCrudHandler())
.add(this)
.build();
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
similarity index 65%
copy from
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
copy to
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
index 6b716993ef0..61191196c0d 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
@@ -33,115 +33,54 @@
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
-import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Handler for default bucket CRUD operations.
- * Implements PUT (create bucket) and DELETE operations when no
- * subresource query parameters are present.
- *
- * This handler processes bucket-level requests that do not target
- * specific subresources (such as {@code ?acl}, {@code ?uploads},
- * {@code ?delete} or {@code ?tagging}), which are handled by dedicated
handlers.
- *
- * This handler extends EndpointBase to inherit all required functionality
- * (configuration, headers, request context, audit logging, metrics, etc.).
+ * Handler for S3 bucket lifecycle configuration operations.
*/
-public class BucketCrudHandler extends BucketOperationHandler {
- private static final Logger LOG =
LoggerFactory.getLogger(BucketCrudHandler.class);
- /**
- * Handle only plain PUT bucket (create bucket), not subresources.
- */
+public class BucketLifecycleHandler extends BucketOperationHandler {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(BucketLifecycleHandler.class);
+
private boolean shouldHandle() {
- return queryParams().get(QueryParams.ACL) == null
- && queryParams().get(QueryParams.UPLOADS) == null
- && queryParams().get(QueryParams.DELETE) == null
- && queryParams().get(QueryParams.TAGGING) == null;
+ return queryParams().get(QueryParams.LIFECYCLE) != null;
}
- /**
- * Handle GET /{bucket} for bucket LIFECYCLE configuration.
- */
@Override
Response handleGetRequest(S3RequestContext context, String bucketName)
throws IOException, OS3Exception {
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
-
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.GET_BUCKET_LIFECYCLE);
- return getBucketLifecycleConfiguration(context, bucketName);
+ if (!shouldHandle()) {
+ return null;
}
- return null;
+
+ context.setAction(S3GAction.GET_BUCKET_LIFECYCLE);
+ return getBucketLifecycleConfiguration(context, bucketName);
}
- /**
- * Handle PUT /{bucket} for bucket creation.
- */
@Override
- Response handlePutRequest(S3RequestContext context, String bucketName,
InputStream body)
+ Response handlePutRequest(
+ S3RequestContext context, String bucketName, InputStream body)
throws IOException, OS3Exception {
-
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.PUT_BUCKET_LIFECYCLE);
- return putBucketLifecycleConfiguration(context, bucketName, body);
- }
-
if (!shouldHandle()) {
return null;
}
- context.setAction(S3GAction.CREATE_BUCKET);
-
- try {
- getClient().getObjectStore().createS3Bucket(bucketName);
- getMetrics().updateCreateBucketSuccessStats(context.getStartNanos());
- return Response.status(HttpStatus.SC_OK)
- .header(HttpHeaders.LOCATION, "/" + bucketName)
- .build();
- } catch (Exception e) {
- getMetrics().updateCreateBucketFailureStats(context.getStartNanos());
- throw e;
- }
+ context.setAction(S3GAction.PUT_BUCKET_LIFECYCLE);
+ return putBucketLifecycleConfiguration(context, bucketName, body);
}
- /**
- * Handle DELETE /{bucket} for bucket deletion.
- */
@Override
Response handleDeleteRequest(S3RequestContext context, String bucketName)
throws IOException, OS3Exception {
-
- final String lifecycleMarker = queryParams().get(QueryParams.LIFECYCLE);
- if (lifecycleMarker != null) {
- context.setAction(S3GAction.DELETE_BUCKET_LIFECYCLE);
- return deleteBucketLifecycleConfiguration(context, bucketName);
- }
-
if (!shouldHandle()) {
return null;
}
- context.setAction(S3GAction.DELETE_BUCKET);
-
- try {
- if (S3Owner.hasBucketOwnershipVerificationConditions(getHeaders())) {
- OzoneBucket bucket = context.getVolume().getBucket(bucketName);
- S3Owner.verifyBucketOwnerCondition(getHeaders(), bucketName,
bucket.getOwner());
- }
- context.getVolume().deleteBucket(bucketName);
- } catch (Exception ex) {
- getMetrics().updateDeleteBucketFailureStats(context.getStartNanos());
- throw ex;
- }
-
- getMetrics().updateDeleteBucketSuccessStats(context.getStartNanos());
- return Response
- .status(HttpStatus.SC_NO_CONTENT)
- .build();
+ context.setAction(S3GAction.DELETE_BUCKET_LIFECYCLE);
+ return deleteBucketLifecycleConfiguration(context, bucketName);
}
public Response deleteBucketLifecycleConfiguration(S3RequestContext context,
String bucketName)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]