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]