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
8 changes: 8 additions & 0 deletions hadoop-hdds/common/src/main/resources/ozone-default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,14 @@
service principal. </description>
</property>

<property>
<name>ozone.s3g.readonly</name>
<value>false</value>
<tag>OZONE, S3GATEWAY</tag>
<description>Whether the S3Gateway blocks PUT/POST/DELETE methods or not.
Mostly used for system maintenance.</description>
</property>

<property>
<name>ozone.om.save.metrics.interval</name>
<value>5m</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,19 @@ public OzoneClient(ConfigurationSource conf, ClientProtocol proxy) {
@VisibleForTesting
protected OzoneClient(ObjectStore objectStore,
ClientProtocol clientProtocol) {
this(objectStore, clientProtocol, new OzoneConfiguration());
}

@VisibleForTesting
protected OzoneClient(ObjectStore objectStore,
ClientProtocol clientProtocol,
OzoneConfiguration conf) {
this.objectStore = objectStore;
this.proxy = clientProtocol;
// For the unit test
this.conf = new OzoneConfiguration();
this.conf = conf;
}

/**
* Returns the object store associated with the Ozone Cluster.
* @return ObjectStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import static org.apache.hadoop.ozone.conf.OzoneServiceConfig.DEFAULT_SHUTDOWN_HOOK_PRIORITY;
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_KERBEROS_KEYTAB_FILE_KEY;
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_KERBEROS_PRINCIPAL_KEY;
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_READONLY;

/**
* This class is used to start/stop S3 compatible rest server.
Expand Down Expand Up @@ -92,6 +93,8 @@ public void start() throws IOException {

LOG.info("Starting Ozone S3 gateway");
HddsServerUtil.initializeMetrics(ozoneConfiguration, "S3Gateway");
LOG.info("S3 Gateway Readonly mode: {}={}", OZONE_S3G_READONLY,
ozoneConfiguration.get(OZONE_S3G_READONLY));
httpServer.start();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public final class S3GatewayConfigKeys {
public static final String OZONE_S3G_KERBEROS_PRINCIPAL_KEY =
"ozone.s3g.kerberos.principal";


public static final String OZONE_S3G_READONLY = "ozone.s3g.readonly";
public static final boolean OZONE_S3G_READONLY_DEFAULT = false;
/**
* Never constructed.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.hadoop.ozone.s3.util.ContinueToken;
import org.apache.hadoop.ozone.s3.util.S3StorageType;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;

import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -64,6 +65,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
Expand Down Expand Up @@ -243,6 +245,12 @@ public Response put(@PathParam("bucket") String bucketName,
InputStream body) throws IOException, OS3Exception {
S3GAction s3GAction = S3GAction.CREATE_BUCKET;

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

try {
if (aclMarker != null) {
s3GAction = S3GAction.PUT_ACL;
Expand Down Expand Up @@ -347,6 +355,12 @@ public Response delete(@PathParam("bucket") String bucketName)
throws IOException, OS3Exception {
S3GAction s3GAction = S3GAction.DELETE_BUCKET;

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

try {
deleteS3Bucket(bucketName);
} catch (OMException ex) {
Expand Down Expand Up @@ -390,9 +404,18 @@ public MultiDeleteResponse multiDelete(@PathParam("bucket") String bucketName,
MultiDeleteRequest request)
throws OS3Exception, IOException {
S3GAction s3GAction = S3GAction.MULTI_DELETE;
MultiDeleteResponse result = new MultiDeleteResponse();

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
Response res = checkResult.get();
result.addError(new Error("", res.getStatusInfo().getReasonPhrase(),
"The S3Gateway is in read-only mode."));
}

OzoneBucket bucket = getBucket(bucketName);
MultiDeleteResponse result = new MultiDeleteResponse();

if (request.getObjects() != null) {
for (DeleteObject keyToDelete : request.getObjects()) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand All @@ -51,13 +52,15 @@
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
import org.apache.hadoop.ozone.om.protocol.S3Auth;
import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;

import com.google.common.annotations.VisibleForTesting;

import org.apache.hadoop.ozone.s3.metrics.S3GatewayMetrics;
import org.apache.hadoop.ozone.s3.util.AuditUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -380,4 +383,14 @@ protected boolean isAccessDenied(OMException ex) {
|| result == ResultCodes.INVALID_TOKEN;
}

protected Optional<Response> checkIfReadonly() {
// Check if the S3Gateway is in read-only mode or not.
if (getClient().getConfiguration().getBoolean(
S3GatewayConfigKeys.OZONE_S3G_READONLY,
S3GatewayConfigKeys.OZONE_S3G_READONLY_DEFAULT)) {
return Optional.of(Response.status(HttpStatus.SC_METHOD_NOT_ALLOWED).
header("Allow", "GET,HEAD").build());
}
return Optional.empty();
}
Comment on lines +386 to +395
Copy link
Member

Choose a reason for hiding this comment

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

nit: I think throwing newError() here is a more uniform way.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, we need to serve allowed methods because we use 405 error code here. I understand.

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;

import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -175,6 +176,12 @@ public Response put(
@QueryParam("uploadId") @DefaultValue("") String uploadID,
InputStream body) throws IOException, OS3Exception {

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

S3GAction s3GAction = S3GAction.CREATE_KEY;
boolean auditSuccess = true;

Expand Down Expand Up @@ -527,6 +534,12 @@ public Response delete(
@QueryParam("uploadId") @DefaultValue("") String uploadId) throws
IOException, OS3Exception {

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

S3GAction s3GAction = S3GAction.DELETE_KEY;

try {
Expand Down Expand Up @@ -591,6 +604,13 @@ public Response initializeMultipartUpload(
@PathParam("path") String key
)
throws IOException, OS3Exception {

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

S3GAction s3GAction = S3GAction.INIT_MULTIPART_UPLOAD;

try {
Expand Down Expand Up @@ -658,6 +678,13 @@ public Response completeMultipartUpload(@PathParam("bucket") String bucket,
@QueryParam("uploadId") @DefaultValue("") String uploadID,
CompleteMultipartUploadRequest multipartUploadRequest)
throws IOException, OS3Exception {

// Check if the S3Gateway status is readonly
Optional<Response> checkResult = checkIfReadonly();
if (checkResult.isPresent()) {
return checkResult.get();
}

S3GAction s3GAction = S3GAction.COMPLETE_MULTIPART_UPLOAD;
OzoneVolume volume = getVolume();
// Using LinkedHashMap to preserve ordering of parts list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
*/
package org.apache.hadoop.ozone.client;

import org.apache.hadoop.hdds.conf.OzoneConfiguration;

/**
* In-memory OzoneClient for testing.
*/
Expand All @@ -31,6 +33,11 @@ public OzoneClientStub(ObjectStoreStub objectStoreStub) {
super(objectStoreStub, new ClientProtocolStub(objectStoreStub));
}

public OzoneClientStub(ObjectStoreStub objectStoreStub,
OzoneConfiguration conf) {
super(objectStoreStub, new ClientProtocolStub(objectStoreStub), conf);
}

@Override
public void close() {
//NOOP.
Expand Down
Loading