From 78c77d3ed808637ba53c295d3abf6730b5255b2a Mon Sep 17 00:00:00 2001 From: NickDevOps Date: Wed, 29 Jul 2026 01:59:00 +0800 Subject: [PATCH 1/4] HDDS-16005. Make DeleteBucketLifecycle idempotent on missing config --- .../hadoop/ozone/s3/endpoint/BucketCrudHandler.java | 8 ++++---- .../s3/endpoint/TestS3LifecycleConfigurationDelete.java | 6 +++++- 2 files changed, 9 insertions(+), 5 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 23c4da2cfa22..cc465fcbc792 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 @@ -156,11 +156,11 @@ protected void deleteLifecycleConfiguration(S3RequestContext context, String buc try { context.getVolume().getBucket(bucketName).deleteLifecycleConfiguration(); } catch (OMException ex) { - if (ex.getResult() == OMException.ResultCodes.LIFECYCLE_CONFIGURATION_NOT_FOUND) { - throw S3ErrorTable.newError( - S3ErrorTable.NO_SUCH_LIFECYCLE_CONFIGURATION, bucketName); + // 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 ex; } - throw ex; } } diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java index 5022320fb226..0b023434f930 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java @@ -55,8 +55,12 @@ public void setup() throws Exception { @Test public void testDeleteNonExistentLifecycleConfiguration() throws Exception { + String bucketName = "bucket1"; + Response r = bucketEndpoint.delete(bucketName); + assertEquals(HTTP_NO_CONTENT, r.getStatus()); + try { - bucketEndpoint.delete("bucket1"); + bucketEndpoint.get(bucketName); fail(); } catch (OS3Exception ex) { assertEquals(HTTP_NOT_FOUND, ex.getHttpCode()); From 07d48047ea646f5befe58e1792999379d7e2fa2e Mon Sep 17 00:00:00 2001 From: NickJavaDev88 <202322731+NickJavaDev88@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:51:18 +0800 Subject: [PATCH 2/4] HDDS-16005. Update tests for idempotent DeleteBucketLifecycle: integration test and robot test case --- .../dist/src/main/smoketest/s3/bucketlifecycle.robot | 8 ++++++++ .../hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot b/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot index c82e066dab58..70210b0e1353 100644 --- a/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot +++ b/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot @@ -55,3 +55,11 @@ Delete bucket lifecycle configuration Should Be Empty ${result} ${result} = Execute AWSS3APICli and checkrc get-bucket-lifecycle-configuration --bucket ${bucket} 255 Should contain ${result} NoSuchLifecycleConfiguration + +Delete bucket non-lifecycle configuration + [tags] no-bucket-type + ${bucket} = Create bucket + ${result} = Execute AWSS3APICli delete-bucket-lifecycle --bucket ${bucket} + Should Be Empty ${result} + ${result} = Execute AWSS3APICli and checkrc get-bucket-lifecycle-configuration --bucket ${bucket} 255 + Should contain ${result} NoSuchLifecycleConfiguration diff --git a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java index 7dc5c8c5ad2e..3e35cf62e8a9 100644 --- a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java +++ b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java @@ -2136,8 +2136,8 @@ public void testS3LifecycleConfigurationDelete() { // Test delete lifecycle for a bucket, while doesn't have lifecycle assertNull(s3Client.getBucketLifecycleConfiguration(bucketName)); - assertThrows(AmazonServiceException.class, - () -> s3Client.deleteBucketLifecycleConfiguration(bucketName)); + // Idempotent delete: no exception expected even without an existing config + s3Client.deleteBucketLifecycleConfiguration(bucketName); // First create a lifecycle configuration BucketLifecycleConfiguration configuration = new BucketLifecycleConfiguration(); From 42e321bc752956589b715166ccff2472e17e003b Mon Sep 17 00:00:00 2001 From: NickJavaDev88 Date: Wed, 29 Jul 2026 17:31:24 +0800 Subject: [PATCH 3/4] HDDS-16005. Remove redundant assertions in idempotent DeleteBucketLifecycle tests --- .../src/main/smoketest/s3/bucketlifecycle.robot | 4 +--- .../TestS3LifecycleConfigurationDelete.java | 14 +++----------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot b/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot index 70210b0e1353..02e9f1fd22c5 100644 --- a/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot +++ b/hadoop-ozone/dist/src/main/smoketest/s3/bucketlifecycle.robot @@ -56,10 +56,8 @@ Delete bucket lifecycle configuration ${result} = Execute AWSS3APICli and checkrc get-bucket-lifecycle-configuration --bucket ${bucket} 255 Should contain ${result} NoSuchLifecycleConfiguration -Delete bucket non-lifecycle configuration +Delete bucket lifecycle configuration when none exists [tags] no-bucket-type ${bucket} = Create bucket ${result} = Execute AWSS3APICli delete-bucket-lifecycle --bucket ${bucket} Should Be Empty ${result} - ${result} = Execute AWSS3APICli and checkrc get-bucket-lifecycle-configuration --bucket ${bucket} 255 - Should contain ${result} NoSuchLifecycleConfiguration diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java index 0b023434f930..5080f192b9c4 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationDelete.java @@ -55,18 +55,10 @@ public void setup() throws Exception { @Test public void testDeleteNonExistentLifecycleConfiguration() throws Exception { - String bucketName = "bucket1"; - Response r = bucketEndpoint.delete(bucketName); + // DeleteBucketLifecycle is idempotent: deleting a non-existent + // configuration must succeed with 204, not fail with 404. + Response r = bucketEndpoint.delete("bucket1"); assertEquals(HTTP_NO_CONTENT, r.getStatus()); - - try { - bucketEndpoint.get(bucketName); - fail(); - } catch (OS3Exception ex) { - assertEquals(HTTP_NOT_FOUND, ex.getHttpCode()); - assertEquals(NO_SUCH_LIFECYCLE_CONFIGURATION.getCode(), - ex.getCode()); - } } @Test From 79de373beaaeafcd42b2f349c4098a45cd906b45 Mon Sep 17 00:00:00 2001 From: NickJavaDev Date: Thu, 30 Jul 2026 23:12:54 +0800 Subject: [PATCH 4/4] Update hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java Co-authored-by: Priyesh Karatha <35779060+priyeshkaratha@users.noreply.github.com> --- .../org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cc465fcbc792..6b716993ef0b 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 @@ -159,7 +159,7 @@ protected void deleteLifecycleConfiguration(S3RequestContext context, String buc // 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 ex; + throw S3ErrorTable.newError(bucketName, ex); } } }