This is an automated email from the ASF dual-hosted git repository.
Gargi-jais11 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 809db17267d HDDS-15510. Implement OM read/write paths for bucket
tagging with audit and metrics (#10498).
809db17267d is described below
commit 809db17267ded01d7fd636fd25a2d061b3d6e7e3
Author: Gargi Jaiswal <[email protected]>
AuthorDate: Tue Jun 16 13:59:16 2026 +0530
HDDS-15510. Implement OM read/write paths for bucket tagging with audit and
metrics (#10498).
---
.../apache/hadoop/ozone/om/IOmMetadataReader.java | 8 +
.../ozone/om/protocol/OzoneManagerProtocol.java | 12 +
.../org/apache/hadoop/ozone/audit/OMAction.java | 4 +
.../java/org/apache/hadoop/ozone/om/OMMetrics.java | 37 +++
.../hadoop/ozone/om/OMPerformanceMetrics.java | 21 ++
.../apache/hadoop/ozone/om/OmMetadataReader.java | 40 +++
.../hadoop/ozone/om/OmMetadataReaderMetrics.java | 4 +
.../org/apache/hadoop/ozone/om/OmSnapshot.java | 10 +
.../apache/hadoop/ozone/om/OmSnapshotMetrics.java | 12 +
.../org/apache/hadoop/ozone/om/OzoneManager.java | 10 +
.../org/apache/hadoop/ozone/om/ResolvedBucket.java | 10 +
.../hadoop/ozone/om/helpers/OMAuditLogger.java | 3 +
.../om/ratis/utils/OzoneManagerRatisUtils.java | 6 +
.../s3/tagging/S3DeleteBucketTaggingRequest.java | 187 ++++++++++++++
.../s3/tagging/S3PutBucketTaggingRequest.java | 185 ++++++++++++++
.../protocolPB/OzoneManagerRequestHandler.java | 23 ++
.../tagging/TestS3DeleteBucketTaggingRequest.java | 257 +++++++++++++++++++
.../s3/tagging/TestS3PutBucketTaggingRequest.java | 274 +++++++++++++++++++++
18 files changed, 1103 insertions(+)
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/IOmMetadataReader.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/IOmMetadataReader.java
index df10fad74e6..df90bbecd14 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/IOmMetadataReader.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/IOmMetadataReader.java
@@ -25,6 +25,7 @@
import org.apache.hadoop.ozone.om.helpers.KeyInfoWithVolumeContext;
import org.apache.hadoop.ozone.om.helpers.ListKeysLightResult;
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
@@ -173,4 +174,11 @@ ListKeysLightResult listKeysLight(String volumeName,
String bucketName,
* @return Tags associated with the key.
*/
Map<String, String> getObjectTagging(OmKeyArgs args) throws IOException;
+
+ /**
+ * Gets the tags for the specified bucket.
+ * @param args Bucket args
+ * @return Tags associated with the bucket.
+ */
+ Map<String, String> getBucketTagging(OmBucketArgs args) throws IOException;
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
index 1376174720a..92d5fad53a6 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
@@ -1213,6 +1213,18 @@ default void deleteObjectTagging(OmKeyArgs args) throws
IOException {
"this to be implemented, as write requests use a new approach.");
}
+ /**
+ * Gets the tags for the specified bucket.
+ * @param args Bucket args
+ * @return Tags associated with the bucket.
+ */
+ @Override
+ default Map<String, String> getBucketTagging(OmBucketArgs args) throws
IOException {
+ // This will be removed in the follow-up ticket HDDS-15511.
+ throw new UnsupportedOperationException("OzoneManager does not require " +
+ "this to be implemented, as bucket tagging client support is
pending.");
+ }
+
/**
* Get status of last triggered quota repair in OM.
* @return String
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
index 342bdf7c746..85c4545fcea 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
@@ -115,6 +115,10 @@ public enum OMAction implements AuditAction {
PUT_OBJECT_TAGGING,
DELETE_OBJECT_TAGGING,
+ GET_BUCKET_TAGGING,
+ PUT_BUCKET_TAGGING,
+ DELETE_BUCKET_TAGGING,
+
GET_SNAPSHOT_DIFF_REPORT,
LIST_SNAPSHOT_DIFF_JOBS,
CANCEL_SNAPSHOT_DIFF_JOBS,
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
index 5a70483b2bc..dc67f3c00d5 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
@@ -262,6 +262,14 @@ public class OMMetrics implements OmMetadataReaderMetrics {
private final DBCheckpointMetrics dbCheckpointMetrics;
private OMSnapshotDirectoryMetrics snapshotDirectoryMetrics;
+ // Bucket Tagging Metrics
+ private @Metric MutableCounterLong numGetBucketTagging;
+ private @Metric MutableCounterLong numPutBucketTagging;
+ private @Metric MutableCounterLong numDeleteBucketTagging;
+ private @Metric MutableCounterLong numGetBucketTaggingFails;
+ private @Metric MutableCounterLong numPutBucketTaggingFails;
+ private @Metric MutableCounterLong numDeleteBucketTaggingFails;
+
public OMMetrics(int maxRatisEvents) {
dbCheckpointMetrics = DBCheckpointMetrics.create("OM Metrics");
this.maxRatisEvents = maxRatisEvents;
@@ -1571,6 +1579,35 @@ public void incEcBucketCreateFailsTotal() {
ecBucketCreateFailsTotal.incr();
}
+ @Override
+ public void incNumGetBucketTagging() {
+ numGetBucketTagging.incr();
+ numBucketOps.incr();
+ }
+
+ @Override
+ public void incNumGetBucketTaggingFails() {
+ numGetBucketTaggingFails.incr();
+ }
+
+ public void incNumPutBucketTagging() {
+ numPutBucketTagging.incr();
+ numBucketOps.incr();
+ }
+
+ public void incNumPutBucketTaggingFails() {
+ numPutBucketTaggingFails.incr();
+ }
+
+ public void incNumDeleteBucketTagging() {
+ numDeleteBucketTagging.incr();
+ numBucketOps.incr();
+ }
+
+ public void incNumDeleteBucketTaggingFails() {
+ numDeleteBucketTaggingFails.incr();
+ }
+
public void incNumRecoverLease() {
numKeyOps.incr();
numFSOps.incr();
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMPerformanceMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMPerformanceMetrics.java
index 9c031e1a9fc..e142e4cfa71 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMPerformanceMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMPerformanceMetrics.java
@@ -139,6 +139,15 @@ public class OMPerformanceMetrics {
@Metric(about = "ACLs check in getObjectTagging")
private MutableRate getObjectTaggingAclCheckLatencyNs;
+ @Metric(about = "resolveBucketLink latency in getBucketTagging")
+ private MutableRate getBucketTaggingResolveBucketLatencyNs;
+
+ @Metric(about = "ACLs check latency in getBucketTagging")
+ private MutableRate getBucketTaggingAclCheckLatencyNs;
+
+ @Metric(about = "End-to-end latency in getBucketTagging")
+ private MutableRate getBucketTaggingLatencyNs;
+
@Metric(about = "Latency of each iteration of DirectoryDeletingService in
ms")
private MutableGaugeLong directoryDeletingServiceLatencyMs;
@@ -349,6 +358,18 @@ public void addGetObjectTaggingLatencyNs(long latencyInNs)
{
getObjectTaggingAclCheckLatencyNs.add(latencyInNs);
}
+ public MutableRate getGetBucketTaggingResolveBucketLatencyNs() {
+ return getBucketTaggingResolveBucketLatencyNs;
+ }
+
+ public MutableRate getGetBucketTaggingAclCheckLatencyNs() {
+ return getBucketTaggingAclCheckLatencyNs;
+ }
+
+ public void addGetBucketTaggingLatencyNs(long latencyInNs) {
+ getBucketTaggingLatencyNs.add(latencyInNs);
+ }
+
public void setDirectoryDeletingServiceLatencyMs(long latencyInMs) {
directoryDeletingServiceLatencyMs.set(latencyInMs);
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
index a5ba074156e..64f46089c06 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
@@ -48,6 +48,8 @@
import org.apache.hadoop.ozone.om.helpers.KeyInfoWithVolumeContext;
import org.apache.hadoop.ozone.om.helpers.ListKeysLightResult;
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
@@ -472,6 +474,44 @@ public Map<String, String> getObjectTagging(OmKeyArgs
args) throws IOException {
}
}
+ @Override
+ public Map<String, String> getBucketTagging(OmBucketArgs args) throws
IOException {
+ long start = Time.monotonicNowNanos();
+
+ ResolvedBucket bucket = captureLatencyNs(
+ perfMetrics.getGetBucketTaggingResolveBucketLatencyNs(),
+ () -> ozoneManager.resolveBucketLink(Pair.of(
+ args.getVolumeName(), args.getBucketName())));
+
+ boolean auditSuccess = true;
+ Map<String, String> auditMap = bucket.audit(args.toAuditMap());
+
+ try {
+ if (isAclEnabled) {
+ captureLatencyNs(perfMetrics.getGetBucketTaggingAclCheckLatencyNs(),
+ () -> checkAcls(ResourceType.BUCKET, StoreType.OZONE,
+ ACLType.READ, bucket, null));
+ }
+ metrics.incNumGetBucketTagging();
+
+ OmBucketInfo info =
+ bucketManager.getBucketInfo(bucket.realVolume(),
bucket.realBucket());
+ return info.getTags();
+ } catch (Exception ex) {
+ metrics.incNumGetBucketTaggingFails();
+ auditSuccess = false;
+ audit.logReadFailure(buildAuditMessageForFailure(
+ OMAction.GET_BUCKET_TAGGING, auditMap, ex));
+ throw ex;
+ } finally {
+ if (auditSuccess) {
+ audit.logReadSuccess(buildAuditMessageForSuccess(
+ OMAction.GET_BUCKET_TAGGING, auditMap));
+ }
+ perfMetrics.addGetBucketTaggingLatencyNs(Time.monotonicNowNanos() -
start);
+ }
+ }
+
/**
* Checks if current caller has acl permissions.
*
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReaderMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReaderMetrics.java
index a46a93ac89b..00547c334d6 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReaderMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReaderMetrics.java
@@ -50,4 +50,8 @@ public interface OmMetadataReaderMetrics {
void incNumGetObjectTagging();
void incNumGetObjectTaggingFails();
+
+ void incNumGetBucketTagging();
+
+ void incNumGetBucketTaggingFails();
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshot.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshot.java
index 426aa300044..5147eafe628 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshot.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshot.java
@@ -36,6 +36,7 @@
import org.apache.hadoop.ozone.om.helpers.KeyInfoWithVolumeContext;
import org.apache.hadoop.ozone.om.helpers.ListKeysLightResult;
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
@@ -190,6 +191,15 @@ public Map<String, String> getObjectTagging(OmKeyArgs
args) throws IOException {
return omMetadataReader.getObjectTagging(normalizeOmKeyArgs(args));
}
+ @Override
+ public Map<String, String> getBucketTagging(OmBucketArgs args) throws
IOException {
+ if (args == null) {
+ return null;
+ }
+
+ return omMetadataReader.getBucketTagging(args);
+ }
+
private OzoneObj normalizeOzoneObj(OzoneObj o) {
if (o == null) {
return null;
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotMetrics.java
index 65cb1d56732..0162c28d290 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotMetrics.java
@@ -60,6 +60,8 @@ public final class OmSnapshotMetrics implements
OmMetadataReaderMetrics {
private @Metric MutableCounterLong numFSOps;
private @Metric MutableCounterLong numGetObjectTagging;
private @Metric MutableCounterLong numGetObjectTaggingFails;
+ private @Metric MutableCounterLong numGetBucketTagging;
+ private @Metric MutableCounterLong numGetBucketTaggingFails;
private OmSnapshotMetrics() {
}
@@ -151,5 +153,15 @@ public void incNumGetObjectTagging() {
public void incNumGetObjectTaggingFails() {
numGetObjectTaggingFails.incr();
}
+
+ @Override
+ public void incNumGetBucketTagging() {
+ numGetBucketTagging.incr();
+ }
+
+ @Override
+ public void incNumGetBucketTaggingFails() {
+ numGetBucketTaggingFails.incr();
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 06533dfd207..2bc8d501fc1 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -258,6 +258,7 @@
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
import org.apache.hadoop.ozone.om.helpers.ListOpenFilesResult;
import org.apache.hadoop.ozone.om.helpers.OMNodeDetails;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
import org.apache.hadoop.ozone.om.helpers.OmDBTenantState;
@@ -5195,6 +5196,15 @@ public Map<String, String> getObjectTagging(final
OmKeyArgs args)
}
}
+ @Override
+ public Map<String, String> getBucketTagging(final OmBucketArgs args)
+ throws IOException {
+ try (UncheckedAutoCloseableSupplier<IOmMetadataReader> rcReader =
+ getReader(args.getVolumeName(), args.getBucketName(), "")) {
+ return rcReader.get().getBucketTagging(args);
+ }
+ }
+
/**
* Write down Layout version of a finalized feature to DB on finalization.
* @param lvm OMLayoutVersionManager
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ResolvedBucket.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ResolvedBucket.java
index 4e976e1a276..19b41355d09 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ResolvedBucket.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ResolvedBucket.java
@@ -25,6 +25,7 @@
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyArgs;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
@@ -121,6 +122,15 @@ public KeyArgs update(KeyArgs args) {
: args;
}
+ public BucketArgs update(BucketArgs args) {
+ return isLink()
+ ? args.toBuilder()
+ .setVolumeName(realVolume())
+ .setBucketName(realBucket())
+ .build()
+ : args;
+ }
+
public OzoneObj update(OzoneObj ozoneObj) {
return isLink()
? OzoneObjInfo.Builder.fromOzoneObj(ozoneObj)
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/helpers/OMAuditLogger.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/helpers/OMAuditLogger.java
index e6185f3d65a..ed742bad164 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/helpers/OMAuditLogger.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/helpers/OMAuditLogger.java
@@ -95,6 +95,9 @@ private static void init() {
CMD_AUDIT_ACTION_MAP.put(Type.GetObjectTagging,
OMAction.GET_OBJECT_TAGGING);
CMD_AUDIT_ACTION_MAP.put(Type.PutObjectTagging,
OMAction.PUT_OBJECT_TAGGING);
CMD_AUDIT_ACTION_MAP.put(Type.DeleteObjectTagging,
OMAction.DELETE_OBJECT_TAGGING);
+ CMD_AUDIT_ACTION_MAP.put(Type.GetBucketTagging,
OMAction.GET_BUCKET_TAGGING);
+ CMD_AUDIT_ACTION_MAP.put(Type.PutBucketTagging,
OMAction.PUT_BUCKET_TAGGING);
+ CMD_AUDIT_ACTION_MAP.put(Type.DeleteBucketTagging,
OMAction.DELETE_BUCKET_TAGGING);
}
private static OMAction getAction(OzoneManagerProtocolProtos.OMRequest
request) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
index 1778de3520d..0a46c589af2 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
@@ -67,6 +67,8 @@
import org.apache.hadoop.ozone.om.request.s3.security.OMSetSecretRequest;
import org.apache.hadoop.ozone.om.request.s3.security.S3GetSecretRequest;
import org.apache.hadoop.ozone.om.request.s3.security.S3RevokeSecretRequest;
+import
org.apache.hadoop.ozone.om.request.s3.tagging.S3DeleteBucketTaggingRequest;
+import org.apache.hadoop.ozone.om.request.s3.tagging.S3PutBucketTaggingRequest;
import
org.apache.hadoop.ozone.om.request.s3.tenant.OMSetRangerServiceVersionRequest;
import org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantAssignAdminRequest;
import
org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantAssignUserAccessIdRequest;
@@ -342,6 +344,10 @@ public static OMClientRequest
createClientRequest(OMRequest omRequest,
volumeName = keyArgs.getVolumeName();
bucketName = keyArgs.getBucketName();
break;
+ case PutBucketTagging:
+ return new S3PutBucketTaggingRequest(omRequest);
+ case DeleteBucketTagging:
+ return new S3DeleteBucketTaggingRequest(omRequest);
default:
throw new OMException("Unrecognized write command type request "
+ cmdType, OMException.ResultCodes.INVALID_REQUEST);
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3DeleteBucketTaggingRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3DeleteBucketTaggingRequest.java
new file mode 100644
index 00000000000..826c7f7ebb1
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3DeleteBucketTaggingRequest.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.s3.tagging;
+
+import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.LeveledResource.BUCKET_LOCK;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.audit.OMAction;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.OzoneManagerUtils;
+import org.apache.hadoop.ozone.om.ResolvedBucket;
+import org.apache.hadoop.ozone.om.execution.flowcontrol.ExecutionContext;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.bucket.OMBucketSetPropertyResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteBucketTaggingRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteBucketTaggingResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+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;
+
+/**
+ * Handles DeleteBucketTagging (S3 bucket tagging).
+ */
+public class S3DeleteBucketTaggingRequest extends OMClientRequest {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(S3DeleteBucketTaggingRequest.class);
+
+ public S3DeleteBucketTaggingRequest(OMRequest omRequest) {
+ super(omRequest);
+ }
+
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager)
+ throws IOException {
+ DeleteBucketTaggingRequest deleteBucketTaggingRequest =
+ getOmRequest().getDeleteBucketTaggingRequest();
+ Objects.requireNonNull(deleteBucketTaggingRequest,
+ "deleteBucketTaggingRequest == null");
+
+ BucketArgs bucketArgs = deleteBucketTaggingRequest.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+ String volumeName = bucketArgs.getVolumeName();
+ String bucketName = bucketArgs.getBucketName();
+
+ ResolvedBucket resolvedBucket = ozoneManager.resolveBucketLink(
+ Pair.of(volumeName, bucketName), this);
+
+ if (ozoneManager.getAclsEnabled()) {
+ try {
+ checkAcls(ozoneManager, OzoneObj.ResourceType.BUCKET,
+ OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE,
+ resolvedBucket.realVolume(), resolvedBucket.realBucket(), null);
+ } catch (IOException ex) {
+ markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
+ OMAction.DELETE_BUCKET_TAGGING,
+ resolvedBucket.audit(omBucketArgs.toAuditMap()), ex,
+ getOmRequest().getUserInfo()));
+ throw ex;
+ }
+ }
+
+ DeleteBucketTaggingRequest.Builder req =
+ deleteBucketTaggingRequest.toBuilder();
+ req.setModificationTime(Time.now());
+ req.setBucketArgs(resolvedBucket.update(bucketArgs));
+
+ return getOmRequest().toBuilder()
+ .setDeleteBucketTaggingRequest(req.build())
+ .setUserInfo(getUserInfo())
+ .build();
+ }
+
+ @Override
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
+ ExecutionContext context) {
+ final long transactionLogIndex = context.getIndex();
+
+ DeleteBucketTaggingRequest deleteBucketTaggingRequest =
+ getOmRequest().getDeleteBucketTaggingRequest();
+ Objects.requireNonNull(deleteBucketTaggingRequest,
+ "deleteBucketTaggingRequest == null");
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ OMMetrics omMetrics = ozoneManager.getMetrics();
+ omMetrics.incNumDeleteBucketTagging();
+
+ BucketArgs bucketArgs = deleteBucketTaggingRequest.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+
+ String volumeName = bucketArgs.getVolumeName();
+ String bucketName = bucketArgs.getBucketName();
+
+ OMResponse.Builder omResponse = OmResponseUtil.getOMResponseBuilder(
+ getOmRequest());
+ OmBucketInfo omBucketInfo = null;
+
+ Exception exception = null;
+ boolean acquiredBucketLock = false;
+ boolean success = true;
+ OMClientResponse omClientResponse = null;
+ try {
+ mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLock(
+ BUCKET_LOCK, volumeName, bucketName));
+ acquiredBucketLock = getOmLockDetails().isLockAcquired();
+
+ String bucketKey = omMetadataManager.getBucketKey(volumeName,
bucketName);
+ OmBucketInfo dbBucketInfo = OzoneManagerUtils.getBucketInfo(
+ omMetadataManager, volumeName, bucketName);
+
+ omBucketInfo = dbBucketInfo.toBuilder()
+ .setTags(Collections.emptyMap())
+ .setUpdateID(transactionLogIndex)
+
.setModificationTime(deleteBucketTaggingRequest.getModificationTime())
+ .build();
+
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey),
+ CacheValue.get(transactionLogIndex, omBucketInfo));
+
+ omResponse.setDeleteBucketTaggingResponse(
+ DeleteBucketTaggingResponse.newBuilder().build());
+ omClientResponse = new OMBucketSetPropertyResponse(
+ omResponse.build(), omBucketInfo);
+ } catch (IOException ex) {
+ success = false;
+ exception = ex;
+ omClientResponse = new OMBucketSetPropertyResponse(
+ createErrorOMResponse(omResponse, exception));
+ } finally {
+ if (acquiredBucketLock) {
+ mergeOmLockDetails(omMetadataManager.getLock()
+ .releaseWriteLock(BUCKET_LOCK, volumeName, bucketName));
+ }
+ if (omClientResponse != null) {
+ omClientResponse.setOmLockDetails(getOmLockDetails());
+ }
+ }
+
+ Map<String, String> auditMap = omBucketArgs.toAuditMap();
+ markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
+ OMAction.DELETE_BUCKET_TAGGING, auditMap, exception,
+ getOmRequest().getUserInfo()));
+
+ if (success) {
+ LOG.debug("Delete bucket tagging for bucket:{} in volume:{}",
+ bucketName, volumeName);
+ return omClientResponse;
+ }
+ omMetrics.incNumDeleteBucketTaggingFails();
+ LOG.error("Delete bucket tagging failed for bucket:{} in volume:{}",
+ bucketName, volumeName, exception);
+ return omClientResponse;
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3PutBucketTaggingRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3PutBucketTaggingRequest.java
new file mode 100644
index 00000000000..f192cbf5e08
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tagging/S3PutBucketTaggingRequest.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.s3.tagging;
+
+import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.LeveledResource.BUCKET_LOCK;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.audit.OMAction;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.OzoneManagerUtils;
+import org.apache.hadoop.ozone.om.ResolvedBucket;
+import org.apache.hadoop.ozone.om.execution.flowcontrol.ExecutionContext;
+import org.apache.hadoop.ozone.om.helpers.KeyValueUtil;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.bucket.OMBucketSetPropertyResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutBucketTaggingRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutBucketTaggingResponse;
+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;
+
+/**
+ * Handles PutBucketTagging (S3 bucket tagging).
+ */
+public class S3PutBucketTaggingRequest extends OMClientRequest {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(S3PutBucketTaggingRequest.class);
+
+ public S3PutBucketTaggingRequest(OMRequest omRequest) {
+ super(omRequest);
+ }
+
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager)
+ throws IOException {
+ PutBucketTaggingRequest putBucketTaggingRequest =
+ getOmRequest().getPutBucketTaggingRequest();
+ Objects.requireNonNull(putBucketTaggingRequest, "putBucketTaggingRequest
== null");
+
+ BucketArgs bucketArgs = putBucketTaggingRequest.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+ String volumeName = bucketArgs.getVolumeName();
+ String bucketName = bucketArgs.getBucketName();
+
+ ResolvedBucket resolvedBucket = ozoneManager.resolveBucketLink(
+ Pair.of(volumeName, bucketName), this);
+
+ if (ozoneManager.getAclsEnabled()) {
+ try {
+ checkAcls(ozoneManager, OzoneObj.ResourceType.BUCKET,
+ OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE,
+ resolvedBucket.realVolume(), resolvedBucket.realBucket(), null);
+ } catch (IOException ex) {
+ markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
+ OMAction.PUT_BUCKET_TAGGING,
+ resolvedBucket.audit(omBucketArgs.toAuditMap()), ex,
+ getOmRequest().getUserInfo()));
+ throw ex;
+ }
+ }
+
+ PutBucketTaggingRequest.Builder req = putBucketTaggingRequest.toBuilder();
+ req.setModificationTime(Time.now());
+ req.setBucketArgs(resolvedBucket.update(bucketArgs));
+ return getOmRequest().toBuilder()
+ .setPutBucketTaggingRequest(req.build())
+ .setUserInfo(getUserInfo())
+ .build();
+ }
+
+ @Override
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
+ ExecutionContext context) {
+ final long transactionLogIndex = context.getIndex();
+
+ PutBucketTaggingRequest putBucketTaggingRequest =
+ getOmRequest().getPutBucketTaggingRequest();
+ Objects.requireNonNull(putBucketTaggingRequest, "putBucketTaggingRequest
== null");
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ OMMetrics omMetrics = ozoneManager.getMetrics();
+ omMetrics.incNumPutBucketTagging();
+
+ BucketArgs bucketArgs = putBucketTaggingRequest.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+
+ String volumeName = bucketArgs.getVolumeName();
+ String bucketName = bucketArgs.getBucketName();
+
+ OMResponse.Builder omResponse = OmResponseUtil.getOMResponseBuilder(
+ getOmRequest());
+ OmBucketInfo omBucketInfo = null;
+
+ Exception exception = null;
+ boolean acquiredBucketLock = false;
+ boolean success = true;
+ OMClientResponse omClientResponse = null;
+ try {
+ mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLock(
+ BUCKET_LOCK, volumeName, bucketName));
+ acquiredBucketLock = getOmLockDetails().isLockAcquired();
+
+ String bucketKey = omMetadataManager.getBucketKey(volumeName,
bucketName);
+ OmBucketInfo dbBucketInfo = OzoneManagerUtils.getBucketInfo(
+ omMetadataManager, volumeName, bucketName);
+
+ Map<String, String> tags =
+ KeyValueUtil.getFromProtobuf(bucketArgs.getTagsList());
+
+ omBucketInfo = dbBucketInfo.toBuilder()
+ .setTags(tags)
+ .setUpdateID(transactionLogIndex)
+ .setModificationTime(putBucketTaggingRequest.getModificationTime())
+ .build();
+
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey),
+ CacheValue.get(transactionLogIndex, omBucketInfo));
+
+ omResponse.setPutBucketTaggingResponse(
+ PutBucketTaggingResponse.newBuilder().build());
+ omClientResponse = new OMBucketSetPropertyResponse(
+ omResponse.build(), omBucketInfo);
+ } catch (IOException ex) {
+ success = false;
+ exception = ex;
+ omClientResponse = new OMBucketSetPropertyResponse(
+ createErrorOMResponse(omResponse, exception));
+ } finally {
+ if (acquiredBucketLock) {
+ mergeOmLockDetails(omMetadataManager.getLock()
+ .releaseWriteLock(BUCKET_LOCK, volumeName, bucketName));
+ }
+ if (omClientResponse != null) {
+ omClientResponse.setOmLockDetails(getOmLockDetails());
+ }
+ }
+ Map<String, String> auditMap = omBucketArgs.toAuditMap();
+ markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
+ OMAction.PUT_BUCKET_TAGGING, auditMap, exception,
+ getOmRequest().getUserInfo()));
+
+ if (success) {
+ LOG.debug("Put bucket tagging for bucket:{} in volume:{}",
+ bucketName, volumeName);
+ return omClientResponse;
+ }
+ omMetrics.incNumPutBucketTaggingFails();
+ LOG.error("Put bucket tagging failed for bucket:{} in volume:{}",
+ bucketName, volumeName, exception);
+ return omClientResponse;
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index 4454b68e078..760dd90e9ce 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -74,6 +74,7 @@
import org.apache.hadoop.ozone.om.helpers.ListKeysResult;
import org.apache.hadoop.ozone.om.helpers.ListOpenFilesResult;
import org.apache.hadoop.ozone.om.helpers.OMAuditLogger;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
@@ -100,6 +101,7 @@
import org.apache.hadoop.ozone.om.response.OMClientResponse;
import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelSnapshotDiffRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelSnapshotDiffResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CheckVolumeAccessRequest;
@@ -108,6 +110,8 @@
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.EchoRPCResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FinalizeUpgradeProgressRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FinalizeUpgradeProgressResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetBucketTaggingRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetBucketTaggingResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoRequest;
@@ -398,6 +402,11 @@ public OMResponse handleReadRequest(OMRequest request) {
getObjectTagging(request.getGetObjectTaggingRequest());
responseBuilder.setGetObjectTaggingResponse(getObjectTaggingResponse);
break;
+ case GetBucketTagging:
+ GetBucketTaggingResponse getBucketTaggingResponse =
+ getBucketTagging(request.getGetBucketTaggingRequest());
+ responseBuilder.setGetBucketTaggingResponse(getBucketTaggingResponse);
+ break;
default:
responseBuilder.setSuccess(false);
responseBuilder.setMessage("Unrecognized Command Type: " + cmdType);
@@ -1591,6 +1600,20 @@ private GetObjectTaggingResponse
getObjectTagging(GetObjectTaggingRequest reques
return resp.build();
}
+ private GetBucketTaggingResponse getBucketTagging(GetBucketTaggingRequest
request)
+ throws IOException {
+ BucketArgs bucketArgs = request.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+
+ GetBucketTaggingResponse.Builder resp =
+ GetBucketTaggingResponse.newBuilder();
+
+ Map<String, String> result = impl.getBucketTagging(omBucketArgs);
+
+ resp.addAllTags(KeyValueUtil.toProtobuf(result));
+ return resp.build();
+ }
+
private SafeModeAction toSafeModeAction(
OzoneManagerProtocolProtos.SafeMode safeMode) {
switch (safeMode) {
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3DeleteBucketTaggingRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3DeleteBucketTaggingRequest.java
new file mode 100644
index 00000000000..01d5c13eb48
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3DeleteBucketTaggingRequest.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.s3.tagging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.om.BucketManager;
+import org.apache.hadoop.ozone.om.BucketManagerImpl;
+import org.apache.hadoop.ozone.om.OMPerformanceMetrics;
+import org.apache.hadoop.ozone.om.ResolvedBucket;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.KeyValueUtil;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.request.bucket.TestBucketRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteBucketTaggingRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutBucketTaggingRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link S3DeleteBucketTaggingRequest}.
+ */
+public class TestS3DeleteBucketTaggingRequest extends TestBucketRequest {
+
+ private String volumeName;
+ private String bucketName;
+
+ @BeforeEach
+ public void setupDeleteBucketTagging() throws Exception {
+ volumeName = UUID.randomUUID().toString();
+ bucketName = UUID.randomUUID().toString();
+ OMPerformanceMetrics perfMetrics = OMPerformanceMetrics.register();
+ when(ozoneManager.getPerfMetrics()).thenReturn(perfMetrics);
+ when(ozoneManager.getAclsEnabled()).thenReturn(false);
+
+ doAnswer(invocation -> new ResolvedBucket(
+ invocation.getArgument(0), invocation.getArgument(0),
+ "", BucketLayout.DEFAULT))
+ .when(ozoneManager)
+ .resolveBucketLink(any(Pair.class), any(OMClientRequest.class));
+
+ BucketManager bucketManager =
+ new BucketManagerImpl(ozoneManager, omMetadataManager);
+ when(ozoneManager.getBucketManager()).thenReturn(bucketManager);
+ }
+
+ @AfterEach
+ public void teardown() {
+ OMPerformanceMetrics.unregister();
+ }
+
+ @Test
+ public void testPreExecute() throws Exception {
+ doPreExecute(volumeName, bucketName);
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheSuccess() throws Exception {
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager);
+ Map<String, String> tags = getTags(5);
+ executePut(volumeName, bucketName, tags, 1L);
+
+ OmBucketInfo bucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertNotNull(bucketInfo);
+ assertEquals(tags.size(), bucketInfo.getTags().size());
+
+ OMRequest originalRequest =
+ createDeleteBucketTaggingRequest(volumeName, bucketName);
+ S3DeleteBucketTaggingRequest request =
+ getDeleteBucketTaggingRequest(originalRequest);
+
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ request = getDeleteBucketTaggingRequest(modifiedRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ assertNotNull(omResponse.getDeleteBucketTaggingResponse());
+ assertEquals(OzoneManagerProtocolProtos.Status.OK, omResponse.getStatus());
+ assertEquals(Type.DeleteBucketTagging, omResponse.getCmdType());
+
+ OmBucketInfo updatedBucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertNotNull(updatedBucketInfo);
+ assertEquals(bucketInfo.getVolumeName(),
updatedBucketInfo.getVolumeName());
+ assertEquals(bucketInfo.getBucketName(),
updatedBucketInfo.getBucketName());
+ assertEquals(0, updatedBucketInfo.getTags().size());
+ assertThat(updatedBucketInfo.getModificationTime())
+ .isGreaterThan(bucketInfo.getModificationTime());
+ assertEquals(2L, updatedBucketInfo.getUpdateID());
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheVolumeNotFound() throws Exception {
+ OMRequest modifiedOmRequest = doPreExecute(volumeName, bucketName);
+
+ S3DeleteBucketTaggingRequest request =
+ getDeleteBucketTaggingRequest(modifiedOmRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+
+ assertEquals(OzoneManagerProtocolProtos.Status.VOLUME_NOT_FOUND,
+ omClientResponse.getOMResponse().getStatus());
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheBucketNotFound() throws Exception {
+ OMRequestTestUtils.addVolumeToDB(volumeName, OzoneConsts.OZONE,
+ omMetadataManager);
+
+ OMRequest modifiedOmRequest = doPreExecute(volumeName, bucketName);
+
+ S3DeleteBucketTaggingRequest request =
+ getDeleteBucketTaggingRequest(modifiedOmRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+
+ assertEquals(OzoneManagerProtocolProtos.Status.BUCKET_NOT_FOUND,
+ omClientResponse.getOMResponse().getStatus());
+ }
+
+ protected OMRequest doPreExecute(String vol, String buck)
+ throws Exception {
+ OMRequest originalRequest =
+ createDeleteBucketTaggingRequest(vol, buck);
+
+ S3DeleteBucketTaggingRequest request =
+ getDeleteBucketTaggingRequest(originalRequest);
+
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ verifyRequest(modifiedRequest, originalRequest);
+
+ return modifiedRequest;
+ }
+
+ public OMRequest createDeleteBucketTaggingRequest(String vol, String buck) {
+ BucketArgs bucketArgs = BucketArgs.newBuilder()
+ .setVolumeName(vol)
+ .setBucketName(buck)
+ .build();
+
+ DeleteBucketTaggingRequest deleteBucketTaggingRequest =
+ DeleteBucketTaggingRequest.newBuilder()
+ .setBucketArgs(bucketArgs)
+ .setModificationTime(0)
+ .build();
+
+ return OMRequest.newBuilder()
+ .setDeleteBucketTaggingRequest(deleteBucketTaggingRequest)
+ .setCmdType(Type.DeleteBucketTagging)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ private void verifyRequest(OMRequest modifiedRequest,
+ OMRequest originalRequest) {
+ BucketArgs original =
+ originalRequest.getDeleteBucketTaggingRequest().getBucketArgs();
+ BucketArgs updated =
+ modifiedRequest.getDeleteBucketTaggingRequest().getBucketArgs();
+
+ assertEquals(original.getVolumeName(), updated.getVolumeName());
+ assertEquals(original.getBucketName(), updated.getBucketName());
+
+ long originModTime =
+ originalRequest.getDeleteBucketTaggingRequest().getModificationTime();
+ long newModTime =
+ modifiedRequest.getDeleteBucketTaggingRequest().getModificationTime();
+ assertThat(newModTime).isGreaterThan(originModTime);
+ }
+
+ protected S3DeleteBucketTaggingRequest getDeleteBucketTaggingRequest(
+ OMRequest originalRequest) {
+ return new S3DeleteBucketTaggingRequest(originalRequest);
+ }
+
+ private OMRequest createPutBucketTaggingRequest(String volume, String bucket,
+ Map<String, String> tags) {
+ BucketArgs.Builder bucketArgs = BucketArgs.newBuilder()
+ .setVolumeName(volume)
+ .setBucketName(bucket)
+ .addAllTags(KeyValueUtil.toProtobuf(tags));
+
+ PutBucketTaggingRequest putReq = PutBucketTaggingRequest.newBuilder()
+ .setBucketArgs(bucketArgs)
+ .setModificationTime(0)
+ .build();
+
+ return OMRequest.newBuilder()
+ .setCmdType(Type.PutBucketTagging)
+ .setPutBucketTaggingRequest(putReq)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ private OMClientResponse executePut(String volume, String bucket,
+ Map<String, String> tags, long trxnLogIndex) throws Exception {
+ OMRequest originalRequest = createPutBucketTaggingRequest(volume, bucket,
+ tags);
+ S3PutBucketTaggingRequest request =
+ new S3PutBucketTaggingRequest(originalRequest);
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ request = new S3PutBucketTaggingRequest(modifiedRequest);
+ return request.validateAndUpdateCache(ozoneManager, trxnLogIndex);
+ }
+
+ private OmBucketInfo getBucketFromDb(String volume, String bucket)
+ throws Exception {
+ return omMetadataManager.getBucketTable().get(
+ omMetadataManager.getBucketKey(volume, bucket));
+ }
+
+ protected Map<String, String> getTags(int size) {
+ Map<String, String> tags = new HashMap<>();
+ for (int i = 0; i < size; i++) {
+ tags.put("tag-key-" + UUID.randomUUID(), "tag-value-" +
UUID.randomUUID());
+ }
+ return tags;
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3PutBucketTaggingRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3PutBucketTaggingRequest.java
new file mode 100644
index 00000000000..348a3de8d87
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/tagging/TestS3PutBucketTaggingRequest.java
@@ -0,0 +1,274 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.s3.tagging;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.om.BucketManager;
+import org.apache.hadoop.ozone.om.BucketManagerImpl;
+import org.apache.hadoop.ozone.om.OMPerformanceMetrics;
+import org.apache.hadoop.ozone.om.ResolvedBucket;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.KeyValueUtil;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.request.bucket.TestBucketRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutBucketTaggingRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link S3PutBucketTaggingRequest}.
+ */
+public class TestS3PutBucketTaggingRequest extends TestBucketRequest {
+
+ private String volumeName;
+ private String bucketName;
+
+ @BeforeEach
+ public void setupPutBucketTagging() throws Exception {
+ volumeName = UUID.randomUUID().toString();
+ bucketName = UUID.randomUUID().toString();
+
+ OMPerformanceMetrics perfMetrics = OMPerformanceMetrics.register();
+ when(ozoneManager.getPerfMetrics()).thenReturn(perfMetrics);
+ when(ozoneManager.getAclsEnabled()).thenReturn(false);
+
+ doAnswer(invocation -> new ResolvedBucket(
+ invocation.getArgument(0), invocation.getArgument(0),
+ "", BucketLayout.DEFAULT))
+ .when(ozoneManager)
+ .resolveBucketLink(any(Pair.class), any(OMClientRequest.class));
+
+ BucketManager bucketManager =
+ new BucketManagerImpl(ozoneManager, omMetadataManager);
+ when(ozoneManager.getBucketManager()).thenReturn(bucketManager);
+ }
+
+ @AfterEach
+ public void teardown() {
+ OMPerformanceMetrics.unregister();
+ }
+
+ @Test
+ public void testPreExecute() throws Exception {
+ Map<String, String> tags = getTags(2);
+ doPreExecute(volumeName, bucketName, tags);
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheSuccess() throws Exception {
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager);
+
+ OmBucketInfo bucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertNotNull(bucketInfo);
+ assertTrue(bucketInfo.getTags().isEmpty());
+
+ Map<String, String> tags = getTags(5);
+
+ OMRequest originalRequest =
+ createPutBucketTaggingRequest(volumeName, bucketName, tags);
+ S3PutBucketTaggingRequest request =
+ getPutBucketTaggingRequest(originalRequest);
+
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ request = getPutBucketTaggingRequest(modifiedRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ assertNotNull(omResponse.getPutBucketTaggingResponse());
+ assertEquals(OzoneManagerProtocolProtos.Status.OK, omResponse.getStatus());
+ assertEquals(Type.PutBucketTagging, omResponse.getCmdType());
+
+ OmBucketInfo updatedBucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertNotNull(updatedBucketInfo);
+ assertEquals(bucketInfo.getVolumeName(),
updatedBucketInfo.getVolumeName());
+ assertEquals(bucketInfo.getBucketName(),
updatedBucketInfo.getBucketName());
+ assertEquals(tags.size(), updatedBucketInfo.getTags().size());
+ for (Map.Entry<String, String> tag : tags.entrySet()) {
+ String value = updatedBucketInfo.getTags().get(tag.getKey());
+ assertNotNull(value);
+ assertEquals(tag.getValue(), value);
+ }
+ assertThat(updatedBucketInfo.getModificationTime())
+ .isGreaterThan(bucketInfo.getModificationTime());
+ assertEquals(2L, updatedBucketInfo.getUpdateID());
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheVolumeNotFound() throws Exception {
+ OMRequest modifiedOmRequest =
+ doPreExecute(volumeName, bucketName, getTags(2));
+
+ S3PutBucketTaggingRequest request =
+ getPutBucketTaggingRequest(modifiedOmRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+
+ assertEquals(OzoneManagerProtocolProtos.Status.VOLUME_NOT_FOUND,
+ omClientResponse.getOMResponse().getStatus());
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheBucketNotFound() throws Exception {
+ OMRequestTestUtils.addVolumeToDB(volumeName, OzoneConsts.OZONE,
+ omMetadataManager);
+
+ OMRequest modifiedOmRequest =
+ doPreExecute(volumeName, bucketName, getTags(2));
+
+ S3PutBucketTaggingRequest request =
+ getPutBucketTaggingRequest(modifiedOmRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 2L);
+
+ assertEquals(OzoneManagerProtocolProtos.Status.BUCKET_NOT_FOUND,
+ omClientResponse.getOMResponse().getStatus());
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheEmptyTagSet() throws Exception {
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager);
+
+ OmBucketInfo bucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertNotNull(bucketInfo);
+ assertTrue(bucketInfo.getTags().isEmpty());
+
+ Map<String, String> tags = getTags(0);
+
+ OMRequest originalRequest =
+ createPutBucketTaggingRequest(volumeName, bucketName, tags);
+ S3PutBucketTaggingRequest request =
+ getPutBucketTaggingRequest(originalRequest);
+
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ request = getPutBucketTaggingRequest(modifiedRequest);
+
+ OMClientResponse omClientResponse =
+ request.validateAndUpdateCache(ozoneManager, 1L);
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ assertNotNull(omResponse.getPutBucketTaggingResponse());
+ assertEquals(OzoneManagerProtocolProtos.Status.OK, omResponse.getStatus());
+ assertEquals(Type.PutBucketTagging, omResponse.getCmdType());
+
+ OmBucketInfo updatedBucketInfo = getBucketFromDb(volumeName, bucketName);
+ assertEquals(bucketInfo.getVolumeName(),
updatedBucketInfo.getVolumeName());
+ assertEquals(bucketInfo.getBucketName(),
updatedBucketInfo.getBucketName());
+ assertTrue(updatedBucketInfo.getTags().isEmpty());
+ assertEquals(tags.size(), updatedBucketInfo.getTags().size());
+ }
+
+ protected OMRequest doPreExecute(String vol, String buck,
+ Map<String, String> tags) throws Exception {
+ OMRequest originalRequest =
+ createPutBucketTaggingRequest(vol, buck, tags);
+
+ S3PutBucketTaggingRequest request =
+ getPutBucketTaggingRequest(originalRequest);
+
+ OMRequest modifiedRequest = request.preExecute(ozoneManager);
+ verifyRequest(modifiedRequest, originalRequest);
+
+ return modifiedRequest;
+ }
+
+ private OMRequest createPutBucketTaggingRequest(String vol, String buck,
+ Map<String, String> tags) {
+ BucketArgs.Builder bucketArgs = BucketArgs.newBuilder()
+ .setVolumeName(vol)
+ .setBucketName(buck);
+
+ if (tags != null && !tags.isEmpty()) {
+ bucketArgs.addAllTags(KeyValueUtil.toProtobuf(tags));
+ }
+
+ PutBucketTaggingRequest putBucketTaggingRequest =
+ PutBucketTaggingRequest.newBuilder()
+ .setBucketArgs(bucketArgs)
+ .setModificationTime(0)
+ .build();
+
+ return OMRequest.newBuilder()
+ .setPutBucketTaggingRequest(putBucketTaggingRequest)
+ .setCmdType(Type.PutBucketTagging)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ private void verifyRequest(OMRequest modifiedRequest, OMRequest
originalRequest) {
+ BucketArgs original =
+ originalRequest.getPutBucketTaggingRequest().getBucketArgs();
+ BucketArgs updated =
+ modifiedRequest.getPutBucketTaggingRequest().getBucketArgs();
+
+ assertEquals(original.getVolumeName(), updated.getVolumeName());
+ assertEquals(original.getBucketName(), updated.getBucketName());
+ assertEquals(original.getTagsList(), updated.getTagsList());
+
+ long originModTime =
+ originalRequest.getPutBucketTaggingRequest().getModificationTime();
+ long newModTime =
+ modifiedRequest.getPutBucketTaggingRequest().getModificationTime();
+ assertThat(newModTime).isGreaterThan(originModTime);
+ }
+
+ protected S3PutBucketTaggingRequest getPutBucketTaggingRequest(
+ OMRequest originalRequest) {
+ return new S3PutBucketTaggingRequest(originalRequest);
+ }
+
+ private OmBucketInfo getBucketFromDb(String volume, String bucket)
+ throws Exception {
+ return omMetadataManager.getBucketTable().get(
+ omMetadataManager.getBucketKey(volume, bucket));
+ }
+
+ protected Map<String, String> getTags(int size) {
+ Map<String, String> tags = new HashMap<>();
+ for (int i = 0; i < size; i++) {
+ tags.put("tag-key-" + UUID.randomUUID(), "tag-value-" +
UUID.randomUUID());
+ }
+ return tags;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]