Skip to content

Commit e0f155f

Browse files
kuenishik5342
authored andcommitted
Readonly mode (#9)
(cherry picked from commit 1ad9c8f) Tweak tests
1 parent 7df85ff commit e0f155f

File tree

9 files changed

+297
-5
lines changed

9 files changed

+297
-5
lines changed

hadoop-hdds/common/src/main/resources/ozone-default.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,13 @@
19331933
will be used for http authentication.
19341934
</description>
19351935
</property>
1936+
<property>
1937+
<name>ozone.s3g.readonly</name>
1938+
<value>false</value>
1939+
<tag>OZONE, S3GATEWAY</tag>
1940+
<description>Whether the S3Gateway blocks PUT/POST/DELETE methods or not.
1941+
Mostly used for system maintenance.</description>
1942+
</property>
19361943

19371944
<property>
19381945
<name>ozone.om.save.metrics.interval</name>

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneClient.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,19 @@ public OzoneClient(ConfigurationSource conf, ClientProtocol proxy) {
9292
@VisibleForTesting
9393
protected OzoneClient(ObjectStore objectStore,
9494
ClientProtocol clientProtocol) {
95+
this(objectStore, clientProtocol, new OzoneConfiguration());
96+
}
97+
98+
@VisibleForTesting
99+
protected OzoneClient(ObjectStore objectStore,
100+
ClientProtocol clientProtocol,
101+
OzoneConfiguration conf) {
95102
this.objectStore = objectStore;
96103
this.proxy = clientProtocol;
97104
// For the unit test
98-
this.conf = new OzoneConfiguration();
105+
this.conf = conf;
99106
}
107+
100108
/**
101109
* Returns the object store associated with the Ozone Cluster.
102110
* @return ObjectStore

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static org.apache.hadoop.ozone.conf.OzoneServiceConfig.DEFAULT_SHUTDOWN_HOOK_PRIORITY;
4545
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_KERBEROS_KEYTAB_FILE_KEY;
4646
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_KERBEROS_PRINCIPAL_KEY;
47+
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_READONLY;
4748

4849
/**
4950
* This class is used to start/stop S3 compatible rest server.
@@ -101,6 +102,8 @@ public void start() throws IOException {
101102
LOG.info("Starting Ozone S3 gateway");
102103
HddsServerUtil.initializeMetrics(ozoneConfiguration, "S3Gateway");
103104
jvmPauseMonitor.start();
105+
LOG.info("S3 Gateway Readonly mode: {}={}", OZONE_S3G_READONLY,
106+
ozoneConfiguration.get(OZONE_S3G_READONLY));
104107
httpServer.start();
105108
}
106109

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayConfigKeys.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ public final class S3GatewayConfigKeys {
8181
public static final boolean OZONE_S3G_LIST_KEYS_SHALLOW_ENABLED_DEFAULT =
8282
true;
8383

84+
public static final String OZONE_S3G_READONLY = "ozone.s3g.readonly";
85+
public static final boolean OZONE_S3G_READONLY_DEFAULT = false;
8486
/**
8587
* Never constructed.
8688
*/

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import java.util.Iterator;
7070
import java.util.List;
7171
import java.util.Map;
72+
import java.util.Optional;
7273
import java.util.Set;
7374

7475
import static org.apache.hadoop.ozone.OzoneConsts.ETAG;
@@ -294,6 +295,12 @@ public Response put(@PathParam("bucket") String bucketName,
294295
long startNanos = Time.monotonicNowNanos();
295296
S3GAction s3GAction = S3GAction.CREATE_BUCKET;
296297

298+
// Check if the S3Gateway status is readonly
299+
Optional<Response> checkResult = checkIfReadonly();
300+
if (checkResult.isPresent()) {
301+
return checkResult.get();
302+
}
303+
297304
try {
298305
if (aclMarker != null) {
299306
s3GAction = S3GAction.PUT_ACL;
@@ -401,6 +408,12 @@ public Response delete(@PathParam("bucket") String bucketName)
401408
long startNanos = Time.monotonicNowNanos();
402409
S3GAction s3GAction = S3GAction.DELETE_BUCKET;
403410

411+
// Check if the S3Gateway status is readonly
412+
Optional<Response> checkResult = checkIfReadonly();
413+
if (checkResult.isPresent()) {
414+
return checkResult.get();
415+
}
416+
404417
try {
405418
deleteS3Bucket(bucketName);
406419
} catch (OMException ex) {
@@ -444,6 +457,15 @@ public MultiDeleteResponse multiDelete(@PathParam("bucket") String bucketName,
444457
MultiDeleteRequest request)
445458
throws OS3Exception, IOException {
446459
S3GAction s3GAction = S3GAction.MULTI_DELETE;
460+
MultiDeleteResponse result = new MultiDeleteResponse();
461+
462+
// Check if the S3Gateway status is readonly
463+
Optional<Response> checkResult = checkIfReadonly();
464+
if (checkResult.isPresent()) {
465+
Response res = checkResult.get();
466+
result.addError(new Error("", res.getStatusInfo().getReasonPhrase(),
467+
"The S3Gateway is in read-only mode."));
468+
}
447469

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

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@
2525
import javax.ws.rs.container.ContainerRequestContext;
2626
import javax.ws.rs.core.Context;
2727
import java.io.IOException;
28-
import java.util.Set;
29-
import java.util.HashSet;
3028
import java.util.Arrays;
31-
import java.util.Map;
29+
import java.util.Collections;
3230
import java.util.HashMap;
31+
import java.util.HashSet;
3332
import java.util.Iterator;
3433
import java.util.List;
35-
import java.util.Collections;
34+
import java.util.Map;
35+
import java.util.Optional;
36+
import java.util.Set;
3637
import java.util.function.Function;
3738
import java.util.stream.Collectors;
3839

@@ -53,6 +54,7 @@
5354
import org.apache.hadoop.ozone.om.exceptions.OMException;
5455
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
5556
import org.apache.hadoop.ozone.om.protocol.S3Auth;
57+
import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
5658
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
5759
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
5860

@@ -62,6 +64,7 @@
6264
import org.apache.hadoop.ozone.s3.signature.SignatureInfo;
6365
import org.apache.hadoop.ozone.s3.util.AuditUtils;
6466
import org.apache.hadoop.util.Time;
67+
import org.apache.http.HttpStatus;
6568
import org.slf4j.Logger;
6669
import org.slf4j.LoggerFactory;
6770

@@ -425,4 +428,14 @@ protected boolean isAccessDenied(OMException ex) {
425428
|| result == ResultCodes.INVALID_TOKEN;
426429
}
427430

431+
protected Optional<Response> checkIfReadonly() {
432+
// Check if the S3Gateway is in read-only mode or not.
433+
if (getClient().getConfiguration().getBoolean(
434+
S3GatewayConfigKeys.OZONE_S3G_READONLY,
435+
S3GatewayConfigKeys.OZONE_S3G_READONLY_DEFAULT)) {
436+
return Optional.of(Response.status(HttpStatus.SC_METHOD_NOT_ALLOWED).
437+
header("Allow", "GET,HEAD").build());
438+
}
439+
return Optional.empty();
440+
}
428441
}

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@
4444
import javax.ws.rs.core.StreamingOutput;
4545
import javax.xml.bind.DatatypeConverter;
4646
import org.apache.commons.io.IOUtils;
47+
import java.io.EOFException;
48+
import java.io.IOException;
49+
import java.io.InputStream;
50+
import java.io.UnsupportedEncodingException;
51+
import java.text.ParseException;
52+
import java.time.Instant;
53+
import java.time.ZoneId;
54+
import java.time.ZonedDateTime;
55+
import java.util.LinkedHashMap;
56+
import java.util.List;
57+
import java.util.Map;
58+
import java.util.Optional;
59+
import java.util.OptionalLong;
60+
4761
import org.apache.commons.lang3.StringUtils;
4862
import org.apache.commons.lang3.tuple.Pair;
4963
import org.apache.hadoop.hdds.client.ECReplicationConfig;
@@ -220,6 +234,13 @@ public Response put(
220234
@QueryParam("uploadId") @DefaultValue("") String uploadID,
221235
final InputStream body) throws IOException, OS3Exception {
222236
long startNanos = Time.monotonicNowNanos();
237+
238+
// Check if the S3Gateway status is readonly
239+
Optional<Response> checkResult = checkIfReadonly();
240+
if (checkResult.isPresent()) {
241+
return checkResult.get();
242+
}
243+
223244
S3GAction s3GAction = S3GAction.CREATE_KEY;
224245
boolean auditSuccess = true;
225246
PerformanceStringBuilder perf = new PerformanceStringBuilder();
@@ -676,6 +697,13 @@ public Response delete(
676697
@QueryParam("uploadId") @DefaultValue("") String uploadId) throws
677698
IOException, OS3Exception {
678699
long startNanos = Time.monotonicNowNanos();
700+
701+
// Check if the S3Gateway status is readonly
702+
Optional<Response> checkResult = checkIfReadonly();
703+
if (checkResult.isPresent()) {
704+
return checkResult.get();
705+
}
706+
679707
S3GAction s3GAction = S3GAction.DELETE_KEY;
680708

681709
try {
@@ -741,6 +769,13 @@ public Response initializeMultipartUpload(
741769
)
742770
throws IOException, OS3Exception {
743771
long startNanos = Time.monotonicNowNanos();
772+
773+
// Check if the S3Gateway status is readonly
774+
Optional<Response> checkResult = checkIfReadonly();
775+
if (checkResult.isPresent()) {
776+
return checkResult.get();
777+
}
778+
744779
S3GAction s3GAction = S3GAction.INIT_MULTIPART_UPLOAD;
745780

746781
try {
@@ -813,6 +848,13 @@ public Response completeMultipartUpload(@PathParam("bucket") String bucket,
813848
CompleteMultipartUploadRequest multipartUploadRequest)
814849
throws IOException, OS3Exception {
815850
long startNanos = Time.monotonicNowNanos();
851+
852+
// Check if the S3Gateway status is readonly
853+
Optional<Response> checkResult = checkIfReadonly();
854+
if (checkResult.isPresent()) {
855+
return checkResult.get();
856+
}
857+
816858
S3GAction s3GAction = S3GAction.COMPLETE_MULTIPART_UPLOAD;
817859
OzoneVolume volume = getVolume();
818860
// Using LinkedHashMap to preserve ordering of parts list.

hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneClientStub.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
package org.apache.hadoop.ozone.client;
2121

22+
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
23+
2224
/**
2325
* In-memory OzoneClient for testing.
2426
*/
@@ -31,6 +33,11 @@ public OzoneClientStub(ObjectStoreStub objectStoreStub) {
3133
super(objectStoreStub, new ClientProtocolStub(objectStoreStub));
3234
}
3335

36+
public OzoneClientStub(ObjectStoreStub objectStoreStub,
37+
OzoneConfiguration conf) {
38+
super(objectStoreStub, new ClientProtocolStub(objectStoreStub), conf);
39+
}
40+
3441
@Override
3542
public void close() {
3643
//NOOP.

0 commit comments

Comments
 (0)