Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public static class Rule {
@XmlElement(name = "Filter")
private Filter filter;

// Ozone does not support lifecycle Transition actions. This is bound only so a Transition
// element is detected and rejected instead of being silently dropped by JAXB.
@XmlElement(name = "Transition")
private List<Transition> transitions;

public String getId() {
return id;
}
Expand Down Expand Up @@ -130,6 +135,14 @@ public Filter getFilter() {
public void setFilter(Filter filter) {
this.filter = filter;
}

public List<Transition> getTransitions() {
return transitions;
}

public void setTransitions(List<Transition> transitions) {
this.transitions = transitions;
}
}

/**
Expand Down Expand Up @@ -181,6 +194,48 @@ public void setDaysAfterInitiation(Integer daysAfterInitiation) {
}
}

/**
* Transition entity for lifecycle rule. Ozone does not support lifecycle transition actions
* for any storage class; this is modeled only so a Transition element in the request is
* detected and rejected during conversion instead of being silently ignored.
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Transition")
public static class Transition {
@XmlElement(name = "Days")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could we omit Days and Date and their accessors? Transition actions are always rejected, so only StorageClass is needed for the error message.

private String days;

@XmlElement(name = "Date")
private String date;

@XmlElement(name = "StorageClass")
private String storageClass;

public Integer getDays() {
return parseDays(days);
}

public void setDays(Integer days) {
this.days = days == null ? null : days.toString();
}

public String getDate() {
return date;
}

public void setDate(String date) {
this.date = date;
}

public String getStorageClass() {
return storageClass;
}

public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
}

/**
* Parses a lifecycle day-count element, rejecting a value that does not fit in an int instead
* of silently overflowing it the way JAXB's built-in Integer converter would.
Expand Down Expand Up @@ -343,6 +398,14 @@ private OmLCRule convertToOmRule(Rule rule) throws OMException, OS3Exception {
if (!STATUS_ENABLED.equals(status) && !STATUS_DISABLED.equals(status)) {
throw S3ErrorTable.newError(S3ErrorTable.MALFORMED_XML);
}
if (rule.getTransitions() != null && !rule.getTransitions().isEmpty()) {
String storageClass = rule.getTransitions().get(0).getStorageClass();
String message = StringUtils.isNotEmpty(storageClass)
? "Invalid lifecycle configuration: storage class '" + storageClass
+ "' is not supported for lifecycle transitions"
: "Invalid lifecycle configuration: Transition actions are not supported";
throw S3ErrorTable.newError(S3ErrorTable.NOT_IMPLEMENTED, rule.getId()).withMessage(message);
}

OmLCRule.Builder builder = new OmLCRule.Builder()
.setEnabled(STATUS_ENABLED.equals(status))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.apache.hadoop.ozone.s3.endpoint.EndpointTestUtils.assertErrorResponse;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.ACCESS_DENIED;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.INTERNAL_ERROR;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.INVALID_ARGUMENT;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.INVALID_REQUEST;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.MALFORMED_XML;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.NOT_IMPLEMENTED;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.NO_SUCH_BUCKET;
import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.QUOTA_EXCEEDED;
import static org.apache.hadoop.ozone.s3.util.S3Consts.EXPECTED_BUCKET_OWNER_HEADER;
Expand Down Expand Up @@ -350,6 +352,17 @@ public void testPutLifecycleConfigurationWithAbortDaysAfterInitiationOverflow()
HTTP_BAD_REQUEST, INVALID_ARGUMENT.getCode());
}

@Test
public void testPutLifecycleConfigurationRejectsTransition() throws Exception {
// Ozone does not support lifecycle Transition actions. A rule containing one must be
// rejected instead of returning HTTP 200 for a rule Ozone can never enforce.
OS3Exception ex = assertThrows(OS3Exception.class,
() -> bucketEndpoint.put("bucket1", withTransition()));
assertEquals(HTTP_NOT_IMPLEMENTED, ex.getHttpCode());
assertEquals(NOT_IMPLEMENTED.getCode(), ex.getCode());
assertTrue(ex.getErrorMessage().contains("EC"));
}

private static InputStream onePrefix() {
String xml = ("<LifecycleConfiguration xmlns=\"http://s3.amazonaws" +
".com/doc/2006-03-01/\">" +
Expand Down Expand Up @@ -817,6 +830,20 @@ private static InputStream withExpirationDaysOverflow() {
return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
}

private static InputStream withTransition() {
String xml = "<LifecycleConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" +
"<Rule>" +
"<ID>unsupported-transition</ID>" +
"<Prefix></Prefix>" +
"<Status>Enabled</Status>" +
"<Expiration><Date>2044-01-19T00:00:00Z</Date></Expiration>" +
"<Transition><Days>1</Days><StorageClass>EC</StorageClass></Transition>" +
"</Rule>" +
"</LifecycleConfiguration>";

return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
}

private static InputStream withAbortDaysAfterInitiationOverflow() {
String xml = "<LifecycleConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" +
"<Rule>" +
Expand Down
Loading