This is an automated email from the ASF dual-hosted git repository.
sammichen pushed a commit to branch HDDS-8342
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-8342 by this push:
new 1fe66180880 HDDS-13548. Prevent OM startup failure from past lifecycle
expiration dates (#8953)
1fe66180880 is described below
commit 1fe661808805f2acf33cda6025148b3281cf3fe3
Author: XiChen <[email protected]>
AuthorDate: Wed Sep 3 12:55:05 2025 +0800
HDDS-13548. Prevent OM startup failure from past lifecycle expiration dates
(#8953)
---
.../apache/hadoop/ozone/om/helpers/OmLCAction.java | 3 +-
.../hadoop/ozone/om/helpers/OmLCExpiration.java | 21 ++++----
.../apache/hadoop/ozone/om/helpers/OmLCFilter.java | 10 +---
.../apache/hadoop/ozone/om/helpers/OmLCRule.java | 18 +++----
.../ozone/om/helpers/OmLifecycleConfiguration.java | 16 +++---
.../om/helpers/OmLifecycleRuleAndOperator.java | 9 +---
.../ozone/om/helpers/TestOmLCExpiration.java | 63 +++++++++++-----------
.../hadoop/ozone/om/helpers/TestOmLCFilter.java | 15 +++---
.../hadoop/ozone/om/helpers/TestOmLCRule.java | 22 +++++---
.../om/helpers/TestOmLifeCycleConfiguration.java | 48 +++++++++++++++--
.../om/helpers/TestOmLifecycleRuleAndOperator.java | 8 +--
.../src/main/proto/OmClientProtocol.proto | 2 +-
.../apache/hadoop/ozone/om/OMMetadataManager.java | 3 +-
.../hadoop/ozone/om/OmMetadataManagerImpl.java | 13 ++---
.../OMLifecycleConfigurationSetRequest.java | 3 +-
.../ozone/om/service/KeyLifecycleService.java | 17 +++++-
.../TestOMLifecycleConfigurationRequest.java | 1 +
.../ozone/om/service/TestKeyLifecycleService.java | 2 +-
.../hadoop/ozone/s3/endpoint/BucketEndpoint.java | 4 +-
.../s3/endpoint/S3LifecycleConfiguration.java | 2 +-
20 files changed, 168 insertions(+), 112 deletions(-)
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCAction.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCAction.java
index 427bf87908b..4db13e20743 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCAction.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCAction.java
@@ -36,9 +36,10 @@ public interface OmLCAction {
* Validates the action configuration.
* Each concrete action implementation must define its own validation logic.
*
+ * @param creationTime The creation time of the lifecycle configuration in
milliseconds since epoch
* @throws OMException if the validation fails
*/
- void valid() throws OMException;
+ void valid(long creationTime) throws OMException;
/**
* Returns the action type.
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCExpiration.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCExpiration.java
index bb15b447691..b5e78eb6241 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCExpiration.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCExpiration.java
@@ -87,10 +87,11 @@ public ActionType getActionType() {
* - The date value must be in the future
* - The date value must be at midnight UTC (00:00:00Z)
*
+ * @param creationTime The creation time of the lifecycle configuration in
milliseconds since epoch
* @throws OMException if the validation fails
*/
@Override
- public void valid() throws OMException {
+ public void valid(long creationTime) throws OMException {
boolean hasDays = days != null;
boolean hasDate = !StringUtils.isBlank(date);
@@ -106,7 +107,7 @@ public void valid() throws OMException {
daysInMilli = TimeUnit.DAYS.toMillis(days);
}
if (hasDate) {
- validateExpirationDate(date);
+ validateExpirationDate(date, creationTime);
}
}
@@ -118,19 +119,21 @@ public void valid() throws OMException {
* - Represents midnight UTC (00:00:00Z) when converted to UTC.
*
* @param expirationDate The date string to validate
+ * @param creationTime The creation time to compare against in milliseconds
since epoch
* @throws OMException if the date is invalid
*/
- private void validateExpirationDate(String expirationDate) throws
OMException {
+ private void validateExpirationDate(String expirationDate, long
creationTime) throws OMException {
try {
ZonedDateTime parsedDate = ZonedDateTime.parse(expirationDate,
DateTimeFormatter.ISO_DATE_TIME);
- ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
// Convert to UTC for validation
ZonedDateTime dateInUTC = parsedDate.withZoneSameInstant(ZoneOffset.UTC);
// The date value must conform to the ISO 8601 format, be in the future.
- if (dateInUTC.isBefore(now)) {
- throw new OMException("Invalid lifecycle configuration: 'Date' must be
in the future " + now + "," + dateInUTC,
- OMException.ResultCodes.INVALID_REQUEST);
+ ZonedDateTime createDate =
ZonedDateTime.ofInstant(Instant.ofEpochMilli(creationTime), ZoneOffset.UTC);
+ if (dateInUTC.isBefore(createDate)) {
+ throw new OMException("Invalid lifecycle configuration: 'Date' must be
in the future " + createDate + "," +
+ dateInUTC, OMException.ResultCodes.INVALID_REQUEST);
}
+
// Verify that the time is midnight UTC (00:00:00Z)
if (!test && (dateInUTC.getHour() != 0 ||
dateInUTC.getMinute() != 0 ||
@@ -202,9 +205,7 @@ public Builder setDate(String lcDate) {
}
public OmLCExpiration build() throws OMException {
- OmLCExpiration omLCExpiration = new OmLCExpiration(this);
- omLCExpiration.valid();
- return omLCExpiration;
+ return new OmLCExpiration(this);
}
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCFilter.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCFilter.java
index d6da6f45cd9..ff6f36b2cc5 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCFilter.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCFilter.java
@@ -205,7 +205,6 @@ public static class Builder {
private String tagKey = null;
private String tagValue = null;
private OmLifecycleRuleAndOperator andOperator = null;
- private BucketLayout bucketLayout;
public Builder setPrefix(String lcPrefix) {
this.prefix = lcPrefix;
@@ -223,15 +222,8 @@ public Builder setAndOperator(OmLifecycleRuleAndOperator
andOp) {
return this;
}
- public Builder setBucketLayout(BucketLayout layout) {
- this.bucketLayout = layout;
- return this;
- }
-
public OmLCFilter build() throws OMException {
- OmLCFilter omLCFilter = new OmLCFilter(this);
- omLCFilter.valid(bucketLayout);
- return omLCFilter;
+ return new OmLCFilter(this);
}
}
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCRule.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCRule.java
index b8a63865513..f22eec1beee 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCRule.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLCRule.java
@@ -152,9 +152,11 @@ public boolean isTagEnable() {
* - Filter must be valid
* - There must be at most one Expiration action per rule
*
+ * @param bucketLayout The bucket layout for validation
+ * @param creationTime The creation time of the lifecycle configuration in
milliseconds since epoch
* @throws OMException if the validation fails
*/
- public void valid(BucketLayout bucketLayout) throws OMException {
+ public void valid(BucketLayout bucketLayout, Long creationTime) throws
OMException {
if (id.length() > LC_ID_MAX_LENGTH) {
throw new OMException("ID length should not exceed allowed limit of " +
LC_ID_MAX_LENGTH,
OMException.ResultCodes.INVALID_REQUEST);
@@ -175,7 +177,7 @@ public void valid(BucketLayout bucketLayout) throws
OMException {
throw new OMException("A rule can have at most one Expiration action.",
OMException.ResultCodes.INVALID_REQUEST);
}
- action.valid();
+ action.valid(creationTime);
}
if (prefix != null && filter != null) {
@@ -304,7 +306,7 @@ public static OmLCRule getFromProtobuf(LifecycleRule
lifecycleRule, BucketLayout
builder.setFilter(OmLCFilter.getFromProtobuf(lifecycleRule.getFilter(),
layout));
}
- return builder.setBucketLayout(layout).build();
+ return builder.build();
}
@Override
@@ -329,7 +331,6 @@ public static class Builder {
private boolean enabled;
private List<OmLCAction> actions = new ArrayList<>();
private OmLCFilter filter;
- private BucketLayout bucketLayout;
public Builder setId(String lcId) {
this.id = lcId;
@@ -378,15 +379,8 @@ public OmLCFilter getFilter() {
return filter;
}
- public Builder setBucketLayout(BucketLayout layout) {
- this.bucketLayout = layout;
- return this;
- }
-
public OmLCRule build() throws OMException {
- OmLCRule omLCRule = new OmLCRule(this);
- omLCRule.valid(bucketLayout);
- return omLCRule;
+ return new OmLCRule(this);
}
}
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleConfiguration.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleConfiguration.java
index d711e3cb937..ad6d31d7cf1 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleConfiguration.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleConfiguration.java
@@ -130,7 +130,7 @@ public void valid() throws OMException {
}
for (OmLCRule rule : rules) {
- rule.valid(bucketLayout);
+ rule.valid(bucketLayout, creationTime);
}
}
@@ -213,9 +213,7 @@ public static OmLifecycleConfiguration getFromProtobuf(
.setBucketLayout(layout)
.setRules(rulesList);
- if (lifecycleConfiguration.hasCreationTime()) {
- builder.setCreationTime(lifecycleConfiguration.getCreationTime());
- }
+ builder.setCreationTime(lifecycleConfiguration.getCreationTime());
if (lifecycleConfiguration.hasObjectID()) {
builder.setObjectID(lifecycleConfiguration.getObjectID());
}
@@ -258,8 +256,8 @@ public Builder setBucketLayout(BucketLayout layout) {
return this;
}
- public Builder setCreationTime(long ctime) {
- this.creationTime = ctime;
+ public Builder setCreationTime(long creationTime) {
+ this.creationTime = creationTime;
return this;
}
@@ -286,7 +284,11 @@ public Builder setUpdateID(long uID) {
}
public OmLifecycleConfiguration build() throws OMException {
- OmLifecycleConfiguration omLifecycleConfiguration = new
OmLifecycleConfiguration(this);
+ return new OmLifecycleConfiguration(this);
+ }
+
+ public OmLifecycleConfiguration buildAndValid() throws OMException {
+ OmLifecycleConfiguration omLifecycleConfiguration = build();
omLifecycleConfiguration.valid();
return omLifecycleConfiguration;
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleRuleAndOperator.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleRuleAndOperator.java
index d28eaea1418..522fc6ca930 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleRuleAndOperator.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmLifecycleRuleAndOperator.java
@@ -138,7 +138,6 @@ public boolean match(OmKeyInfo omKeyInfo, String keyPath) {
public static class Builder {
private Map<String, String> tags = new HashMap<>();
private String prefix;
- private BucketLayout bucketLayout;
public Builder setPrefix(String lcPrefix) {
this.prefix = lcPrefix;
@@ -156,15 +155,9 @@ public Builder setTags(Map<String, String> lcTags) {
}
return this;
}
- public Builder setBucketLayout(BucketLayout layout) {
- this.bucketLayout = layout;
- return this;
- }
public OmLifecycleRuleAndOperator build() throws OMException {
- OmLifecycleRuleAndOperator omLifecycleRuleAndOperator = new
OmLifecycleRuleAndOperator(this);
- omLifecycleRuleAndOperator.valid(bucketLayout);
- return omLifecycleRuleAndOperator;
+ return new OmLifecycleRuleAndOperator(this);
}
}
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCExpiration.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCExpiration.java
index a2fe3951cb0..1aa3e2b5011 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCExpiration.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCExpiration.java
@@ -37,51 +37,52 @@ class TestOmLCExpiration {
public void testCreateValidOmLCExpiration() {
OmLCExpiration.Builder exp1 = new OmLCExpiration.Builder()
.setDays(30);
- assertDoesNotThrow(exp1::build);
+ long currentTime = System.currentTimeMillis();
+ assertDoesNotThrow(() -> exp1.build().valid(currentTime));
OmLCExpiration.Builder exp2 = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:00:00Z");
- assertDoesNotThrow(exp2::build);
+ assertDoesNotThrow(() -> exp2.build().valid(currentTime));
OmLCExpiration.Builder exp3 = new OmLCExpiration.Builder()
.setDays(1);
- assertDoesNotThrow(exp3::build);
+ assertDoesNotThrow(() -> exp3.build().valid(currentTime));
OmLCExpiration.Builder exp4 = new OmLCExpiration.Builder()
.setDate("2099-12-31T00:00:00Z");
- assertDoesNotThrow(exp4::build);
+ assertDoesNotThrow(() -> exp4.build().valid(currentTime));
OmLCExpiration.Builder exp5 = new OmLCExpiration.Builder()
.setDate("2099-02-15T00:00:00.000Z");
- assertDoesNotThrow(exp5::build);
+ assertDoesNotThrow(() -> exp5.build().valid(currentTime));
OmLCExpiration.Builder exp6 = new OmLCExpiration.Builder()
.setDate("2042-04-02T00:00:00Z");
- assertDoesNotThrow(exp6::build);
+ assertDoesNotThrow(() -> exp6.build().valid(currentTime));
OmLCExpiration.Builder exp7 = new OmLCExpiration.Builder()
.setDate("2042-04-02T00:00:00+00:00");
- assertDoesNotThrow(exp7::build);
+ assertDoesNotThrow(() -> exp7.build().valid(currentTime));
OmLCExpiration.Builder exp8 = new OmLCExpiration.Builder()
.setDate("2099-12-31T00:00:00+00:00");
- assertDoesNotThrow(exp8::build);
+ assertDoesNotThrow(() -> exp8.build().valid(currentTime));
OmLCExpiration.Builder exp9 = new OmLCExpiration.Builder()
.setDate("2099-12-31T23:00:00-01:00");
- assertDoesNotThrow(exp9::build);
+ assertDoesNotThrow(() -> exp9.build().valid(currentTime));
OmLCExpiration.Builder exp10 = new OmLCExpiration.Builder()
.setDate("2100-01-01T01:00:00+01:00");
- assertDoesNotThrow(exp10::build);
+ assertDoesNotThrow(() -> exp10.build().valid(currentTime));
OmLCExpiration.Builder exp11 = new OmLCExpiration.Builder()
.setDate("2099-12-31T12:00:00-12:00");
- assertDoesNotThrow(exp11::build);
+ assertDoesNotThrow(() -> exp11.build().valid(currentTime));
OmLCExpiration.Builder exp12 = new OmLCExpiration.Builder()
.setDate("2100-01-01T12:00:00+12:00");
- assertDoesNotThrow(exp12::build);
+ assertDoesNotThrow(() -> exp12.build().valid(currentTime));
}
@Test
@@ -89,84 +90,86 @@ public void testCreateInValidOmLCExpiration() {
OmLCExpiration.Builder exp1 = new OmLCExpiration.Builder()
.setDays(30)
.setDate(getFutureDateString(100));
- assertOMException(exp1::build, INVALID_REQUEST,
+ long currentTime = System.currentTimeMillis();
+ assertOMException(() -> exp1.build().valid(currentTime), INVALID_REQUEST,
"Either 'days' or 'date' should be specified, but not both or
neither.");
OmLCExpiration.Builder exp2 = new OmLCExpiration.Builder()
.setDays(-1);
- assertOMException(exp2::build, INVALID_REQUEST,
+ assertOMException(() -> exp2.build().valid(currentTime), INVALID_REQUEST,
"'Days' for Expiration action must be a positive integer");
OmLCExpiration.Builder exp3 = new OmLCExpiration.Builder()
.setDate(null);
- assertOMException(exp3::build, INVALID_REQUEST,
+ assertOMException(() -> exp3.build().valid(currentTime), INVALID_REQUEST,
"Either 'days' or 'date' should be specified, but not both or
neither.");
OmLCExpiration.Builder exp4 = new OmLCExpiration.Builder()
.setDate("");
- assertOMException(exp4::build, INVALID_REQUEST,
+ assertOMException(() -> exp4.build().valid(currentTime), INVALID_REQUEST,
"Either 'days' or 'date' should be specified, but not both or
neither.");
OmLCExpiration.Builder exp5 = new OmLCExpiration.Builder();
- assertOMException(exp5::build, INVALID_REQUEST,
+ assertOMException(() -> exp5.build().valid(currentTime), INVALID_REQUEST,
"Either 'days' or 'date' should be specified, but not both or
neither.");
OmLCExpiration.Builder exp6 = new OmLCExpiration.Builder()
.setDate("10-10-2099");
- assertOMException(exp6::build, INVALID_REQUEST,
+ assertOMException(() -> exp6.build().valid(currentTime), INVALID_REQUEST,
"'Date' must be in ISO 8601 format");
OmLCExpiration.Builder exp7 = new OmLCExpiration.Builder()
.setDate("2099-12-31T00:00:00");
- assertOMException(exp7::build, INVALID_REQUEST,
+ assertOMException(() -> exp7.build().valid(currentTime), INVALID_REQUEST,
"'Date' must be in ISO 8601 format");
- // Testing for date in the past
+ // Testing for date in the past with creation time
OmLCExpiration.Builder exp8 = new OmLCExpiration.Builder()
.setDate(getFutureDateString(-1));
- assertOMException(exp8::build, INVALID_REQUEST,
+ assertOMException(() -> exp8.build().valid(currentTime), INVALID_REQUEST,
"'Date' must be in the future");
OmLCExpiration.Builder exp9 = new OmLCExpiration.Builder()
.setDays(0);
- assertOMException(exp9::build, INVALID_REQUEST,
+ assertOMException(() -> exp9.build().valid(currentTime), INVALID_REQUEST,
"'Days' for Expiration action must be a positive integer");
- // 1 minute ago
+ // 1 minute ago with creation time
OmLCExpiration.Builder exp10 = new OmLCExpiration.Builder()
.setDate(getFutureDateString(0, 0, -1));
- assertOMException(exp10::build, INVALID_REQUEST,
+ assertOMException(() -> exp10.build().valid(currentTime), INVALID_REQUEST,
"'Date' must be in the future");
}
@Test
public void testDateMustBeAtMidnightUTC() {
// Acceptable date - midnight UTC
+ long currentTime = System.currentTimeMillis();
OmLCExpiration.Builder validExp = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:00:00Z");
- assertDoesNotThrow(validExp::build);
+ assertDoesNotThrow(() -> validExp.build().valid(currentTime));
// Non-midnight UTC dates should be rejected
OmLCExpiration.Builder exp1 = new OmLCExpiration.Builder()
.setDate("2099-10-10T10:00:00Z");
- assertOMException(exp1::build, INVALID_REQUEST, "'Date' must represent
midnight UTC");
+ assertOMException(() -> exp1.build().valid(currentTime), INVALID_REQUEST,
"'Date' must represent midnight UTC");
OmLCExpiration.Builder exp2 = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:30:00Z");
- assertOMException(exp2::build, INVALID_REQUEST, "'Date' must represent
midnight UTC");
+ assertOMException(() -> exp2.build().valid(currentTime), INVALID_REQUEST,
"'Date' must represent midnight UTC");
OmLCExpiration.Builder exp3 = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:00:30Z");
- assertOMException(exp3::build, INVALID_REQUEST, "'Date' must represent
midnight UTC");
+ assertOMException(() -> exp3.build().valid(currentTime), INVALID_REQUEST,
"'Date' must represent midnight UTC");
OmLCExpiration.Builder exp4 = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:00:00.123Z");
- assertOMException(exp4::build, INVALID_REQUEST, "'Date' must represent
midnight UTC");
+ assertOMException(() -> exp4.build().valid(currentTime), INVALID_REQUEST,
"'Date' must represent midnight UTC");
// Non-UTC timezone should be rejected
OmLCExpiration.Builder exp5 = new OmLCExpiration.Builder()
.setDate("2099-10-10T00:00:00+01:00");
- assertOMException(exp5::build, INVALID_REQUEST, "'Date' must represent
midnight UTC");
+ assertOMException(() -> exp5.build().valid(currentTime), INVALID_REQUEST,
"'Date' must represent midnight UTC");
}
@Test
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCFilter.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCFilter.java
index d073dad71d8..bd3809ba10a 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCFilter.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCFilter.java
@@ -42,11 +42,14 @@ class TestOmLCFilter {
@Test
public void testInValidOmLCRulePrefixFilterCoExist() throws OMException {
+ long currentTime = System.currentTimeMillis();
OmLCRule.Builder rule1 = getOmLCRuleBuilder("id", "prefix", true, 1,
VALID_OM_LC_FILTER);
- assertOMException(rule1::build, INVALID_REQUEST, "Filter and Prefix cannot
be used together");
+ assertOMException(() -> rule1.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
+ "Filter and Prefix cannot be used together");
OmLCRule.Builder rule2 = getOmLCRuleBuilder("id", "", true, 1,
VALID_OM_LC_FILTER);
- assertOMException(rule2::build, INVALID_REQUEST, "Filter and Prefix cannot
be used together");
+ assertOMException(() -> rule2.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
+ "Filter and Prefix cannot be used together");
}
@Test
@@ -70,19 +73,19 @@ public void testValidFilter() throws OMException {
@Test
public void testInValidFilter() {
OmLCFilter.Builder lcFilter1 = getOmLCFilterBuilder("prefix",
Pair.of("key", "value"), VALID_OM_LC_AND_OPERATOR);
- assertOMException(lcFilter1::build, INVALID_REQUEST,
+ assertOMException(() -> lcFilter1.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
"Only one of 'Prefix', 'Tag', or 'AndOperator' should be specified");
OmLCFilter.Builder lcFilter2 = getOmLCFilterBuilder("prefix",
Pair.of("key", "value"), null);
- assertOMException(lcFilter2::build, INVALID_REQUEST,
+ assertOMException(() -> lcFilter2.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
"Only one of 'Prefix', 'Tag', or 'AndOperator' should be specified");
OmLCFilter.Builder lcFilter3 = getOmLCFilterBuilder("prefix", null,
VALID_OM_LC_AND_OPERATOR);
- assertOMException(lcFilter3::build, INVALID_REQUEST,
+ assertOMException(() -> lcFilter3.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
"Only one of 'Prefix', 'Tag', or 'AndOperator' should be specified");
OmLCFilter.Builder lcFilter4 = getOmLCFilterBuilder(null, Pair.of("key",
"value"), VALID_OM_LC_AND_OPERATOR);
- assertOMException(lcFilter4::build, INVALID_REQUEST,
+ assertOMException(() -> lcFilter4.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
"Only one of 'Prefix', 'Tag', or 'AndOperator' should be specified");
}
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCRule.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCRule.java
index 4e4736c257e..0a17af7b3e7 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCRule.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLCRule.java
@@ -47,6 +47,7 @@ class TestOmLCRule {
@Test
public void testCreateValidOmLCRule() throws OMException {
+ long currentTime = System.currentTimeMillis();
OmLCExpiration exp = new OmLCExpiration.Builder()
.setDays(30)
.build();
@@ -56,13 +57,14 @@ public void testCreateValidOmLCRule() throws OMException {
.setEnabled(true)
.setPrefix("/spark/logs")
.setAction(exp);
- assertDoesNotThrow(r1::build);
+ assertDoesNotThrow(() -> r1.build().valid(BucketLayout.DEFAULT,
currentTime));
OmLCRule.Builder r2 = new OmLCRule.Builder()
.setEnabled(true)
.setPrefix("")
.setAction(exp);
OmLCRule omLCRule = assertDoesNotThrow(r2::build);
+ assertDoesNotThrow(() -> omLCRule.valid(BucketLayout.DEFAULT,
currentTime));
// Empty id should generate a 48 (default) bit one.
assertEquals(OmLCRule.LC_ID_LENGTH, omLCRule.getId().length(),
@@ -71,6 +73,7 @@ public void testCreateValidOmLCRule() throws OMException {
@Test
public void testCreateInValidOmLCRule() throws OMException {
+ long currentTime = System.currentTimeMillis();
OmLCExpiration exp = new OmLCExpiration.Builder()
.setDays(30)
.build();
@@ -81,26 +84,28 @@ public void testCreateInValidOmLCRule() throws OMException {
OmLCRule.Builder r1 = new OmLCRule.Builder()
.setId(new String(id))
.setAction(exp);
- assertOMException(r1::build, INVALID_REQUEST, "ID length should not exceed
allowed limit of 255");
+ assertOMException(() -> r1.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
+ "ID length should not exceed allowed limit of 255");
OmLCRule.Builder r2 = new OmLCRule.Builder()
.setId("remove Spark logs after 30 days")
.setEnabled(true)
.setPrefix("/spark/logs")
.setAction(null);
- assertOMException(r2::build, INVALID_REQUEST,
+ assertOMException(() -> r2.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
"At least one action needs to be specified in a rule");
OmLCRule.Builder r3 = new OmLCRule.Builder()
.setEnabled(true)
.setAction(exp);
- assertOMException(r3::build, INVALID_REQUEST,
+ assertOMException(() -> r3.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
"Filter and Prefix cannot both be null.");
}
@Test
public void testMultipleActionsInRule() throws OMException {
+ long currentTime = System.currentTimeMillis();
OmLCExpiration expiration1 = new OmLCExpiration.Builder()
.setDays(30)
.build();
@@ -118,11 +123,13 @@ public void testMultipleActionsInRule() throws
OMException {
OmLCRule.Builder rule = builder.setActions(actions);
- assertOMException(rule::build, INVALID_REQUEST, "A rule can have at most
one Expiration action");
+ assertOMException(() -> rule.build().valid(BucketLayout.DEFAULT,
currentTime), INVALID_REQUEST,
+ "A rule can have at most one Expiration action");
}
@Test
public void testRuleWithAndOperatorFilter() throws OMException {
+ long currentTime = System.currentTimeMillis();
Map<String, String> tags = ImmutableMap.of("app", "hadoop", "env", "test");
OmLifecycleRuleAndOperator andOperator =
getOmLCAndOperatorBuilder("/logs/", tags).build();
OmLCFilter filter = getOmLCFilterBuilder(null, null, andOperator).build();
@@ -134,12 +141,14 @@ public void testRuleWithAndOperatorFilter() throws
OMException {
.setAction(new OmLCExpiration.Builder().setDays(30).build());
OmLCRule rule = assertDoesNotThrow(builder::build);
+ assertDoesNotThrow(() -> rule.valid(BucketLayout.DEFAULT, currentTime));
assertTrue(rule.isPrefixEnable());
assertTrue(rule.isTagEnable());
}
@Test
public void testRuleWithTagFilter() throws OMException {
+ long currentTime = System.currentTimeMillis();
OmLCFilter filter = getOmLCFilterBuilder(null, Pair.of("app", "hadoop"),
null).build();
OmLCRule.Builder builder = new OmLCRule.Builder()
@@ -149,6 +158,7 @@ public void testRuleWithTagFilter() throws OMException {
.setAction(new OmLCExpiration.Builder().setDays(30).build());
OmLCRule rule = assertDoesNotThrow(builder::build);
+ assertDoesNotThrow(() -> rule.valid(BucketLayout.DEFAULT, currentTime));
assertFalse(rule.isPrefixEnable());
assertTrue(rule.isTagEnable());
}
@@ -174,7 +184,7 @@ public void testDuplicateRuleIDs() throws OMException {
.setBucket("bucket")
.setRules(rules);
- assertOMException(config::build, INVALID_REQUEST, "Duplicate rule IDs
found");
+ assertOMException(() -> config.build().valid(), INVALID_REQUEST,
"Duplicate rule IDs found");
}
@Test
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifeCycleConfiguration.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifeCycleConfiguration.java
index c05d4743223..3afb45e84db 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifeCycleConfiguration.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifeCycleConfiguration.java
@@ -30,6 +30,8 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.common.collect.ImmutableMap;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -71,14 +73,14 @@ public void testCreateInValidLCConfiguration() throws
OMException {
List<OmLCRule> rules = Collections.singletonList(rule);
OmLifecycleConfiguration.Builder lcc0 = getOmLifecycleConfiguration(null,
"bucket", rules);
- assertOMException(lcc0::build, INVALID_REQUEST, "Volume cannot be blank");
+ assertOMException(() -> lcc0.buildAndValid(), INVALID_REQUEST, "Volume
cannot be blank");
OmLifecycleConfiguration.Builder lcc1 =
getOmLifecycleConfiguration("volume", null, rules);
- assertOMException(lcc1::build, INVALID_REQUEST, "Bucket cannot be blank");
+ assertOMException(() -> lcc1.buildAndValid(), INVALID_REQUEST, "Bucket
cannot be blank");
OmLifecycleConfiguration.Builder lcc3 = getOmLifecycleConfiguration(
"volume", "bucket", Collections.emptyList());
- assertOMException(lcc3::build, INVALID_REQUEST,
+ assertOMException(() -> lcc3.buildAndValid(), INVALID_REQUEST,
"At least one rules needs to be specified in a lifecycle
configuration");
List<OmLCRule> rules4 = new ArrayList<>(
@@ -92,7 +94,7 @@ public void testCreateInValidLCConfiguration() throws
OMException {
rules4.add(r);
}
OmLifecycleConfiguration.Builder lcc4 =
getOmLifecycleConfiguration("volume", "bucket", rules4);
- assertOMException(lcc4::build, INVALID_REQUEST,
+ assertOMException(() -> lcc4.buildAndValid(), INVALID_REQUEST,
"The number of lifecycle rules must not exceed the allowed limit of");
}
@@ -193,7 +195,7 @@ public void testDisabledRule() throws OMException {
.build();
assertFalse(rule.isEnabled());
- assertDoesNotThrow(() -> rule.valid(BucketLayout.DEFAULT));
+ assertDoesNotThrow(() -> rule.valid(BucketLayout.DEFAULT,
System.currentTimeMillis()));
}
@Test
@@ -225,4 +227,40 @@ public void testProtobufConversion() throws OMException {
assertEquals(30, ruleFromProto.getExpiration().getDays());
}
+ @Test
+ public void testOMStartupWithPastExpirationDate() throws OMException {
+ // Simulate a lifecycle configuration with expiration date in the past
+ // This scenario can happen when OM restarts after some time has passed
+ // since the lifecycle configuration was created.
+
+ // Create a rule with expiration date that is in the past (simulating old
config)
+ String pastDate = getFutureDateString(-1); // A date clearly in the past
(1 day ago)
+ OmLCExpiration pastExpiration = new OmLCExpiration.Builder()
+ .setDate(pastDate)
+ .build();
+
+ OmLCRule ruleWithPastDate = new OmLCRule.Builder()
+ .setId("test-rule-past-date")
+ .setPrefix("/old-logs/")
+ .setEnabled(true)
+ .addAction(pastExpiration)
+ .build();
+
+ OmLifecycleConfiguration config = new OmLifecycleConfiguration.Builder()
+ .setVolume("test-volume")
+ .setBucket("test-bucket")
+ .setBucketLayout(BucketLayout.DEFAULT)
+ // An Expiration was created two days ago and expired 1 day ago,
should be valid
+
.setCreationTime(ZonedDateTime.now(ZoneOffset.UTC).minusDays(2).toInstant().toEpochMilli())
+ .addRule(ruleWithPastDate)
+ .setObjectID(123456L)
+ .setUpdateID(78910L)
+ .build();
+
+ LifecycleConfiguration proto = config.getProtobuf();
+ OmLifecycleConfiguration configFromProto = assertDoesNotThrow(() ->
+ OmLifecycleConfiguration.getFromProtobuf(proto));
+ assertDoesNotThrow(configFromProto::valid);
+ }
+
}
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifecycleRuleAndOperator.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifecycleRuleAndOperator.java
index 5b77a625980..43c7ffbc41b 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifecycleRuleAndOperator.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmLifecycleRuleAndOperator.java
@@ -59,15 +59,17 @@ public void testValidAndOperator() throws OMException {
@Test
public void testInValidAndOperator() {
OmLifecycleRuleAndOperator.Builder andOperator1 =
getOmLCAndOperatorBuilder("prefix", null);
- assertOMException(andOperator1::build, INVALID_REQUEST, "'Prefix' alone is
not allowed");
+ assertOMException(() -> andOperator1.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
+ "'Prefix' alone is not allowed");
OmLifecycleRuleAndOperator.Builder andOperator2 =
getOmLCAndOperatorBuilder(null, Collections.singletonMap("tag1",
"value1"));
- assertOMException(andOperator2::build, INVALID_REQUEST,
+ assertOMException(() -> andOperator2.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
"If 'Tags' are specified without 'Prefix', there should be more than
one tag");
OmLifecycleRuleAndOperator.Builder andOperator3 =
getOmLCAndOperatorBuilder(null, null);
- assertOMException(andOperator3::build, INVALID_REQUEST, "Either 'Tags' or
'Prefix' must be specified.");
+ assertOMException(() -> andOperator3.build().valid(BucketLayout.DEFAULT),
INVALID_REQUEST,
+ "Either 'Tags' or 'Prefix' must be specified.");
}
@Test
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 4823e81eaa0..1a83bf4ff58 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -2390,7 +2390,7 @@ message LifecycleConfiguration {
required string volume = 1;
required string bucket = 2;
required BucketLayoutProto bucketLayout = 3;
- optional uint64 creationTime = 4;
+ required uint64 creationTime = 4;
repeated LifecycleRule rules = 5;
optional uint64 objectID = 6;
optional uint64 updateID = 7;
diff --git
a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java
b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java
index e790d370f83..98299fb2ba4 100644
---
a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java
+++
b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java
@@ -35,6 +35,7 @@
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.common.BlockGroup;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
import org.apache.hadoop.ozone.om.helpers.ListOpenFilesResult;
@@ -474,7 +475,7 @@ String getMultipartKeyFSO(String volume, String bucket,
String key, String
/**
* @return list all LifecycleConfigurations.
*/
- List<OmLifecycleConfiguration> listLifecycleConfigurations();
+ List<OmLifecycleConfiguration> listLifecycleConfigurations() throws
OMException;
/**
* Fetches the lifecycle configuration by bucketName.
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
index e9b7dc84559..1dd6833df1f 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
@@ -2126,22 +2126,23 @@ public List<OmLifecycleConfiguration>
listLifecycleConfigurations() {
public OmLifecycleConfiguration getLifecycleConfiguration(String volumeName,
String bucketName) throws IOException {
Preconditions.checkNotNull(bucketName);
+ OmLifecycleConfiguration value = null;
try {
String bucketKey = getBucketKey(volumeName, bucketName);
- OmLifecycleConfiguration value =
getLifecycleConfigurationTable().get(bucketKey);
-
+ value = getLifecycleConfigurationTable().get(bucketKey);
if (value == null) {
LOG.debug("lifecycle configuration of bucket /{}/{} not found.",
volumeName, bucketName);
throw new OMException("Lifecycle configuration not found",
LIFECYCLE_CONFIGURATION_NOT_FOUND);
}
+ value.valid();
return value;
} catch (IOException ex) {
- if (!(ex instanceof OMException)) {
- LOG.error("Exception while getting lifecycle configuration for " +
- "bucket: /{}/{}", volumeName, bucketName, ex);
- }
+ LOG.error("Exception while getting lifecycle configuration for " +
+ "bucket: /{}/{}, LifecycleConfiguration {}", volumeName, bucketName,
+ value != null ? value.getProtobuf() : "", ex);
+
throw ex;
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/lifecycle/OMLifecycleConfigurationSetRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/lifecycle/OMLifecycleConfigurationSetRequest.java
index 91f4567dcce..da395fa30c1 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/lifecycle/OMLifecycleConfigurationSetRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/lifecycle/OMLifecycleConfigurationSetRequest.java
@@ -47,7 +47,6 @@
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UserInfo;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
-import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -100,7 +99,7 @@ public OMRequest preExecute(OzoneManager ozoneManager)
throws IOException {
.setVolume(resolvedBucket.realVolume())
.setBucket(resolvedBucket.realBucket());
- newLifecycleConfiguration.setCreationTime(Time.now());
+ newLifecycleConfiguration.setCreationTime(System.currentTimeMillis());
newCreateRequest.setLifecycleConfiguration(newLifecycleConfiguration);
return omRequest.toBuilder().setUserInfo(getUserInfo())
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyLifecycleService.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyLifecycleService.java
index f707979746b..80d267cc84f 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyLifecycleService.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyLifecycleService.java
@@ -128,9 +128,22 @@ public BackgroundTaskQueue getTasks() {
return queue;
}
- List<OmLifecycleConfiguration> lifecycleConfigurationList =
- omMetadataManager.listLifecycleConfigurations();
+ List<OmLifecycleConfiguration> lifecycleConfigurationList = null;
+ try {
+ lifecycleConfigurationList =
omMetadataManager.listLifecycleConfigurations();
+ } catch (OMException e) {
+ LOG.error("Failed to list lifecycle configurations", e);
+ return queue;
+ }
for (OmLifecycleConfiguration lifecycleConfiguration :
lifecycleConfigurationList) {
+ try {
+ lifecycleConfiguration.valid();
+ } catch (OMException e) {
+ LOG.error("Skip invalid lifecycle configuration for {}/{}:
LifecycleConfiguration:\n {}",
+ lifecycleConfiguration.getVolume(),
lifecycleConfiguration.getBucket(),
+ lifecycleConfiguration.getProtobuf(), e);
+ continue;
+ }
String bucketKey =
omMetadataManager.getBucketKey(lifecycleConfiguration.getVolume(),
lifecycleConfiguration.getBucket());
if (lifecycleConfiguration.getRules().stream().anyMatch(r ->
r.isEnabled())) {
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/lifecycle/TestOMLifecycleConfigurationRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/lifecycle/TestOMLifecycleConfigurationRequest.java
index 03075091b94..5f54c24a064 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/lifecycle/TestOMLifecycleConfigurationRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/lifecycle/TestOMLifecycleConfigurationRequest.java
@@ -123,6 +123,7 @@ public OMRequest setLifecycleConfigurationRequest(String
volumeName,
String prefix = "prefix/";
LifecycleConfiguration.Builder builder =
LifecycleConfiguration.newBuilder()
.setBucketLayout(BucketLayoutProto.OBJECT_STORE)
+ .setCreationTime(System.currentTimeMillis())
.setVolume(volumeName)
.setBucket(bucketName);
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyLifecycleService.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyLifecycleService.java
index 26b82c0c5fa..7df7e244b76 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyLifecycleService.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyLifecycleService.java
@@ -1504,7 +1504,6 @@ private void createLifecyclePolicy(String volume, String
bucket, BucketLayout la
.setEnabled(enabled)
.setPrefix(prefix)
.setFilter(filter)
- .setBucketLayout(layout)
.setAction(new OmLCExpiration.Builder()
.setDate(date)
.build())
@@ -1513,6 +1512,7 @@ private void createLifecyclePolicy(String volume, String
bucket, BucketLayout la
String key = "/" + volume + "/" + bucket;
LifecycleConfiguration lcProto = lcc.getProtobuf();
OmLifecycleConfiguration canonicalLcc =
OmLifecycleConfiguration.getFromProtobuf(lcProto);
+ canonicalLcc.valid();
metadataManager.getLifecycleConfigurationTable().put(key, lcc);
metadataManager.getLifecycleConfigurationTable().addCacheEntry(
new CacheKey<>(key), CacheValue.get(1L, canonicalLcc));
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 cb9b79c858f..b2b90cc3a2b 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
@@ -813,7 +813,9 @@ public Response putBucketLifecycleConfiguration(
if (ex.getResult() == ResultCodes.ACCESS_DENIED) {
throw S3ErrorTable.newError(S3ErrorTable.ACCESS_DENIED, bucketName);
} else if (ex.getResult() == ResultCodes.INVALID_REQUEST) {
- throw S3ErrorTable.newError(S3ErrorTable.INVALID_REQUEST, bucketName);
+ OS3Exception invalidException = S3ErrorTable.INVALID_REQUEST;
+ invalidException.setErrorMessage(ex.getMessage());
+ throw S3ErrorTable.newError(invalidException, bucketName);
}
}
return Response.ok().build();
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
index 54009f28491..8aa3e52f433 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
@@ -263,7 +263,7 @@ public OmLifecycleConfiguration
toOmLifecycleConfiguration(OzoneBucket ozoneBuck
builder.addRule(convertToOmRule(rule));
}
- return builder.build();
+ return builder.buildAndValid();
} catch (Exception ex) {
if (ex instanceof IllegalStateException) {
throw S3ErrorTable.newError(S3ErrorTable.INVALID_REQUEST,
ozoneBucket.getName(), ex);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]