This is an automated email from the ASF dual-hosted git repository.

ivandika3 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 6901880cc5a HDDS-15509. Add protobuf schema and OmBucketInfo storage 
for S3 bucket tags (#10475)
6901880cc5a is described below

commit 6901880cc5a1624d1f1cd62cee65642772a87065
Author: Gargi Jaiswal <[email protected]>
AuthorDate: Thu Jun 11 10:13:16 2026 +0530

    HDDS-15509. Add protobuf schema and OmBucketInfo storage for S3 bucket tags 
(#10475)
---
 .../apache/hadoop/ozone/OzoneManagerVersion.java   |  4 ++
 .../main/java/org/apache/hadoop/ozone/OmUtils.java |  9 ++++
 .../hadoop/ozone/om/helpers/OmBucketArgs.java      | 38 ++++++++++++++++
 .../hadoop/ozone/om/helpers/OmBucketInfo.java      | 36 ++++++++++++++-
 .../src/main/proto/OmClientProtocol.proto          | 53 ++++++++++++++++++++++
 5 files changed, 138 insertions(+), 2 deletions(-)

diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneManagerVersion.java
 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneManagerVersion.java
index 7d3f8629f0e..a968dd9618e 100644
--- 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneManagerVersion.java
+++ 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneManagerVersion.java
@@ -57,6 +57,10 @@ public enum OzoneManagerVersion implements ComponentVersion {
 
   ATOMIC_CREATE_IF_NOT_EXISTS(12,
       "OzoneManager version that supports explicit create-if-not-exists key 
semantics"),
+
+  S3_BUCKET_TAGGING_API(13,
+      "OzoneManager version that supports S3 bucket tagging APIs, such as "
+          + "PutBucketTagging, GetBucketTagging, and DeleteBucketTagging"),
     
   FUTURE_VERSION(-1, "Used internally in the client when the server side is "
       + " newer and an unknown server version has arrived to the client.");
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index b71c41920af..c38163f8753 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -259,6 +259,8 @@ public static boolean isReadOnly(OMRequest omRequest) {
       // keeping it here for compatibility
     case GetSnapshotInfo:
     case GetObjectTagging:
+    case GetBucketTagging:
+      return true;
     case GetQuotaRepairStatus:
     case StartQuotaRepair:
       return true;
@@ -322,6 +324,9 @@ public static boolean isReadOnly(OMRequest omRequest) {
     case QuotaRepair:
     case PutObjectTagging:
     case DeleteObjectTagging:
+    case PutBucketTagging:
+    case DeleteBucketTagging:
+      return false;
     case UnknownCommand:
       return false;
     case EchoRPC:
@@ -377,6 +382,8 @@ public static boolean shouldSendToFollower(OMRequest 
omRequest) {
     case GetSnapshotInfo:
     case GetObjectTagging:
       return true;
+    case GetBucketTagging:
+      return true;
     case CreateVolume:
     case SetVolumeProperty:
     case DeleteVolume:
@@ -437,6 +444,8 @@ public static boolean shouldSendToFollower(OMRequest 
omRequest) {
     case QuotaRepair:
     case PutObjectTagging:
     case DeleteObjectTagging:
+    case PutBucketTagging:
+    case DeleteBucketTagging:
     case ServiceList: // OM leader should have the most up-to-date OM service 
list info
     case RangerBGSync: // Ranger Background Sync task is only run on leader
     case SnapshotDiff:
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketArgs.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketArgs.java
index 6491a2ec146..8eed2630ead 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketArgs.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketArgs.java
@@ -17,6 +17,7 @@
 
 package org.apache.hadoop.ozone.om.helpers;
 
+import com.google.common.collect.ImmutableMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -62,6 +63,10 @@ public final class OmBucketArgs extends WithMetadata 
implements Auditable {
    * Bucket Owner Name.
    */
   private final String ownerName;
+  /**
+   * Tags for S3 bucket tagging RPC.
+   */
+  private final ImmutableMap<String, String> tags;
 
   private OmBucketArgs(Builder b) {
     super(b);
@@ -76,6 +81,7 @@ private OmBucketArgs(Builder b) {
     this.quotaInNamespaceSet = b.quotaInNamespaceSet;
     this.quotaInNamespace = quotaInNamespaceSet ? b.quotaInNamespace : 
OzoneConsts.QUOTA_RESET;
     this.bekInfo = b.bekInfo;
+    this.tags = b.tags.build();
   }
 
   /**
@@ -160,6 +166,13 @@ public String getOwnerName() {
     return ownerName;
   }
 
+  /**
+   * Tags supplied for bucket tagging operations; never null (may be empty).
+   */
+  public Map<String, String> getTags() {
+    return tags;
+  }
+
   /**
    * Returns new builder class that builds a OmBucketArgs.
    * @return Builder
@@ -222,6 +235,7 @@ public static class Builder extends WithMetadata.Builder {
     private BucketEncryptionKeyInfo bekInfo;
     private DefaultReplicationConfig defaultReplicationConfig;
     private String ownerName;
+    private final MapBuilder<String, String> tags;
 
     /**
      * Constructs a builder.
@@ -229,6 +243,7 @@ public static class Builder extends WithMetadata.Builder {
     public Builder() {
       quotaInBytes = OzoneConsts.QUOTA_RESET;
       quotaInNamespace = OzoneConsts.QUOTA_RESET;
+      tags = MapBuilder.empty();
     }
 
     public Builder setVolumeName(String volume) {
@@ -288,6 +303,20 @@ public Builder setOwnerName(String owner) {
       return this;
     }
 
+    public Builder addAllTags(Map<String, String> tagMap) {
+      if (tagMap != null) {
+        this.tags.putAll(tagMap);
+      }
+      return this;
+    }
+
+    public Builder setTags(Map<String, String> tagMap) {
+      if (tagMap != null) {
+        this.tags.set(tagMap);
+      }
+      return this;
+    }
+
     /**
      * Constructs the OmBucketArgs.
      * @return instance of OmBucketArgs.
@@ -295,6 +324,7 @@ public Builder setOwnerName(String owner) {
     public OmBucketArgs build() {
       Objects.requireNonNull(volumeName, "volumeName == null");
       Objects.requireNonNull(bucketName, "bucketName == null");
+      Objects.requireNonNull(tags, "tags == null");
       return new OmBucketArgs(this);
     }
   }
@@ -331,6 +361,10 @@ public BucketArgs getProtobuf() {
       builder.setBekInfo(OMPBHelper.convert(bekInfo));
     }
 
+    if (!tags.isEmpty()) {
+      builder.addAllTags(KeyValueUtil.toProtobuf(tags));
+    }
+
     return builder.build();
   }
 
@@ -372,6 +406,10 @@ public static Builder builderFromProtobuf(BucketArgs 
bucketArgs) {
           OMPBHelper.convert(bucketArgs.getBekInfo()));
     }
 
+    if (!bucketArgs.getTagsList().isEmpty()) {
+      builder.setTags(KeyValueUtil.getFromProtobuf(bucketArgs.getTagsList()));
+    }
+
     return builder;
   }
 
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
index bce6adb636a..0d4eabf0bc2 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.ozone.om.helpers;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -107,6 +108,11 @@ public final class OmBucketInfo extends WithObjectID 
implements Auditable, CopyO
 
   private final String owner;
 
+  /**
+   * S3-style tags stored on the bucket.
+   */
+  private final ImmutableMap<String, String> tags;
+
   private OmBucketInfo(Builder b) {
     super(b);
     this.volumeName = b.volumeName;
@@ -128,6 +134,7 @@ private OmBucketInfo(Builder b) {
     this.bucketLayout = b.bucketLayout;
     this.owner = b.owner;
     this.defaultReplicationConfig = b.defaultReplicationConfig;
+    this.tags = b.tags.build();
   }
 
   public static Codec<OmBucketInfo> getCodec() {
@@ -303,6 +310,13 @@ public String getOwner() {
     return owner;
   }
 
+  /**
+   * @return tag map associated with this bucket; never null (may be empty).
+   */
+  public Map<String, String> getTags() {
+    return tags;
+  }
+
   /**
    * Returns new builder class that builds a OmBucketInfo.
    *
@@ -378,7 +392,8 @@ public Builder toBuilder() {
         .setSnapshotUsedNamespace(snapshotUsedNamespace)
         .setBucketLayout(bucketLayout)
         .setOwner(owner)
-        .setDefaultReplicationConfig(defaultReplicationConfig);
+        .setDefaultReplicationConfig(defaultReplicationConfig)
+        .setTags(tags);
   }
 
   /**
@@ -402,16 +417,19 @@ public static class Builder extends 
WithObjectID.Builder<OmBucketInfo> {
     private BucketLayout bucketLayout = BucketLayout.DEFAULT;
     private String owner;
     private DefaultReplicationConfig defaultReplicationConfig;
+    private final MapBuilder<String, String> tags;
     private long snapshotUsedBytes;
     private long snapshotUsedNamespace;
 
     public Builder() {
       acls = AclListBuilder.empty();
+      tags = MapBuilder.empty();
     }
 
     private Builder(OmBucketInfo obj) {
       super(obj);
       acls = AclListBuilder.of(obj.acls);
+      tags = MapBuilder.of(obj.tags);
     }
 
     public Builder setVolumeName(String volume) {
@@ -550,6 +568,13 @@ public Builder setDefaultReplicationConfig(
       return this;
     }
 
+    public Builder setTags(Map<String, String> tagMap) {
+      if (tagMap != null) {
+        this.tags.set(tagMap);
+      }
+      return this;
+    }
+
     @Override
     protected void validate() {
       super.validate();
@@ -557,6 +582,7 @@ protected void validate() {
       Objects.requireNonNull(bucketName, "bucketName == null");
       Objects.requireNonNull(acls, "acls == null");
       Objects.requireNonNull(storageType, "storageType == null");
+      Objects.requireNonNull(tags, "tags == null");
     }
 
     @Override
@@ -582,6 +608,7 @@ public BucketInfo getProtobuf() {
         .setUsedBytes(usedBytes)
         .setUsedNamespace(usedNamespace)
         .addAllMetadata(KeyValueUtil.toProtobuf(getMetadata()))
+        .addAllTags(KeyValueUtil.toProtobuf(tags))
         .setQuotaInBytes(quotaInBytes)
         .setQuotaInNamespace(quotaInNamespace)
         .setSnapshotUsedBytes(snapshotUsedBytes)
@@ -661,6 +688,9 @@ public static Builder builderFromProtobuf(BucketInfo 
bucketInfo,
       obib.addAllMetadata(KeyValueUtil
           .getFromProtobuf(bucketInfo.getMetadataList()));
     }
+    if (!bucketInfo.getTagsList().isEmpty()) {
+      obib.setTags(KeyValueUtil.getFromProtobuf(bucketInfo.getTagsList()));
+    }
     if (bucketInfo.hasBeinfo()) {
       obib.setBucketEncryptionKey(OMPBHelper.convert(bucketInfo.getBeinfo()));
     }
@@ -745,7 +775,8 @@ public boolean equals(Object o) {
         Objects.equals(getMetadata(), that.getMetadata()) &&
         Objects.equals(bekInfo, that.bekInfo) &&
         Objects.equals(owner, that.owner) &&
-        Objects.equals(defaultReplicationConfig, 
that.defaultReplicationConfig);
+        Objects.equals(defaultReplicationConfig, 
that.defaultReplicationConfig) &&
+        Objects.equals(tags, that.tags);
   }
 
   @Override
@@ -777,6 +808,7 @@ public String toString() {
         ", bucketLayout=" + bucketLayout +
         ", owner=" + owner +
         ", defaultReplicationConfig=" + defaultReplicationConfig +
+        ", tags=" + tags +
         '}';
   }
 }
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 22c71cc2985..d71ff27f302 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -157,6 +157,11 @@ enum Type {
   GetObjectTagging = 141;
   DeleteObjectTagging = 142;
   SubmitSnapshotDiff = 143;
+
+  // TODO(HDDS-15497): S3 bucket tagging RPCs; handled by OM in a follow-up PR 
(S3G maps to PUT/GET/DELETE ?tagging).
+  PutBucketTagging = 144;
+  GetBucketTagging = 145;
+  DeleteBucketTagging = 146;
 }
 
 enum SafeMode {
@@ -309,6 +314,13 @@ message OMRequest {
   repeated SetSnapshotPropertyRequest       SetSnapshotPropertyRequests    = 
143;
 
   optional SubmitSnapshotDiffRequest        submitSnapshotDiffRequest       = 
144;
+
+  // TODO: PutBucketTagging — tags in bucketArgs.tags; OM persists to 
BucketInfo.tags.
+  optional PutBucketTaggingRequest          putBucketTaggingRequest         = 
145;
+  // TODO: GetBucketTagging — volume/bucket in bucketArgs; response returns 
tag list.
+  optional GetBucketTaggingRequest          getBucketTaggingRequest          = 
146;
+  // TODO: DeleteBucketTagging — clears tags on target bucket (link resolves 
in OM).
+  optional DeleteBucketTaggingRequest       deleteBucketTaggingRequest       = 
147;
 }
 
 message OMResponse {
@@ -444,6 +456,13 @@ message OMResponse {
   optional DeleteObjectTaggingResponse       deleteObjectTaggingResponse   = 
142;
 
   optional SubmitSnapshotDiffResponse        submitSnapshotDiffResponse    = 
143;
+
+  // TODO: Empty ack after OM applies tag set to OmBucketInfo.
+  optional PutBucketTaggingResponse          putBucketTaggingResponse      = 
144;
+  // TODO: Tag list for S3G GetBucketTagging XML; empty if no tags.
+  optional GetBucketTaggingResponse          getBucketTaggingResponse      = 
145;
+  // TODO: Empty ack after OM clears BucketInfo.tags.
+  optional DeleteBucketTaggingResponse       deleteBucketTaggingResponse    = 
146;
 }
 
 enum Status {
@@ -787,6 +806,8 @@ message BucketInfo {
     optional hadoop.hdds.DefaultReplicationConfig defaultReplicationConfig = 
20;
     optional uint64 snapshotUsedBytes = 21;
     optional uint64 snapshotUsedNamespace = 22;
+    // TODO: S3 bucket tags persisted in OM DB; set by PutBucketTagging, read 
by GetBucketTagging.
+    repeated hadoop.hdds.KeyValue tags = 23;
 }
 
 enum BucketLayoutProto {
@@ -860,6 +881,8 @@ message BucketArgs {
     optional string ownerName = 10;
     optional hadoop.hdds.DefaultReplicationConfig defaultReplicationConfig = 
11;
     optional BucketEncryptionInfoProto bekInfo = 12;
+    // TODO: Tag payload for PutBucketTagging only.
+    repeated hadoop.hdds.KeyValue tags = 13;
 }
 
 message PrefixInfo {
@@ -2476,3 +2499,33 @@ service OzoneManagerService {
     rpc submitRequest(OMRequest)
           returns(OMResponse);
 }
+
+// TODO: S3 PutBucketTagging — bucketArgs identifies bucket; tags in 
bucketArgs.tags replace existing set.
+message PutBucketTaggingRequest {
+  required BucketArgs bucketArgs = 1;
+  optional uint64 modificationTime = 2;
+}
+
+// TODO: Success response; no body (tags stored on OmBucketInfo).
+message PutBucketTaggingResponse {
+}
+
+// TODO: S3 GetBucketTagging — bucketArgs.volumeName/bucketName; link resolved 
in OM reader.
+message GetBucketTaggingRequest {
+  required BucketArgs bucketArgs = 1;
+}
+
+// TODO: Returns current bucket tags for S3G Tagging XML response.
+message GetBucketTaggingResponse {
+  repeated hadoop.hdds.KeyValue tags = 1;
+}
+
+// TODO: S3 DeleteBucketTagging — clears all tags on bucket (link → source 
bucket in OM).
+message DeleteBucketTaggingRequest {
+  required BucketArgs bucketArgs = 1;
+  optional uint64 modificationTime = 2;
+}
+
+// TODO: Success response; bucket has no tags after commit.
+message DeleteBucketTaggingResponse {
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to