Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -160,6 +161,11 @@ public class OzoneBucket extends WithMetadata {
*/
private long pendingDeleteNamespace;

/**
* S3-style bucketTags on the bucket.
*/
private final Map<String, String> bucketTags = new HashMap<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need this in-memory bucket tags? Similar to object tagging, I think we should use simply use getObjectTagging when we want to see the latest updated bucket tags (there might be other concurrent bucket concurrent bucket tags modification).

However, I also understand that OzoneBucket also contains in-memory stats that might be changed in OM DB.

@ivandika3 ivandika3 Jun 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is related to #10553, we can probably discuss it there.


protected OzoneBucket(Builder builder) {
super(builder);
this.proxy = builder.proxy;
Expand Down Expand Up @@ -201,6 +207,9 @@ protected OzoneBucket(Builder builder) {
this.bucketLayout = builder.bucketLayout;
}
this.owner = builder.owner;
if (builder.tags != null) {
this.bucketTags.putAll(builder.tags);
}
}

/**
Expand Down Expand Up @@ -267,6 +276,15 @@ public Instant getModificationTime() {
return modificationTime;
}

/**
* Returns the bucketTags of the bucket.
*
* @return bucket bucketTags.
*/
public Map<String, String> getBucketTags() {
return Collections.unmodifiableMap(bucketTags);
}

/**
* Return the bucket encryption key name.
* @return the bucket encryption key name
Expand Down Expand Up @@ -1214,6 +1232,52 @@ public void deleteObjectTagging(String keyName) throws IOException {
proxy.deleteObjectTagging(volumeName, name, keyName);
}

/**
* Gets the bucketTags for this bucket.
* @return Tags for this bucket.
* @throws IOException
*/
@JsonIgnore
public Map<String, String> getBucketTagging() throws IOException {
return proxy.getBucketTagging(volumeName, name);
}

/**
* Sets bucketTags on this bucket (replaces existing tag set).
* @param tags Tags to set on the bucket.
* @throws IOException
*/
public void putBucketTagging(Map<String, String> tags) throws IOException {
proxy.putBucketTagging(volumeName, name, tags);
applyBucketTaggingUpdate(tags);
}

/**
* Removes all bucketTags from this bucket.
* @throws IOException
*/
public void deleteBucketTagging() throws IOException {
proxy.deleteBucketTagging(volumeName, name);
applyBucketTaggingDelete();
}

/**
* Updates cached bucket tags after a successful put.
*/
protected void applyBucketTaggingUpdate(Map<String, String> tags) {
bucketTags.clear();
if (tags != null) {
bucketTags.putAll(tags);
}
}

/**
* Updates cached bucket tags after a successful delete tagging call.
*/
protected void applyBucketTaggingDelete() {
bucketTags.clear();
}

public void setSourcePathExist(boolean b) {
this.sourcePathExist = b;
}
Expand Down Expand Up @@ -1252,6 +1316,7 @@ public static class Builder extends WithMetadata.Builder {
private String owner;
private long pendingDeleteBytes;
private long pendingDeleteNamespace;
private Map<String, String> tags;

protected Builder() {
}
Expand Down Expand Up @@ -1358,6 +1423,11 @@ public Builder setPendingDeleteNamespace(long pendingDeleteNamespace) {
return this;
}

public Builder setTags(Map<String, String> tags) {
this.tags = tags;
return this;
}

public OzoneBucket build() {
return new OzoneBucket(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1493,4 +1493,31 @@ void putObjectTagging(String volumeName, String bucketName, String keyName,
void deleteObjectTagging(String volumeName, String bucketName, String keyName)
throws IOException;

/**
* Gets the tags for an existing bucket.
* @param volumeName Volume name.
* @param bucketName Bucket name.
* @return Tags for the specified bucket.
* @throws IOException
*/
Map<String, String> getBucketTagging(String volumeName, String bucketName)
throws IOException;

/**
* Sets tags on an existing bucket (replaces existing tag set).
* @param volumeName Volume name.
* @param bucketName Bucket name.
* @param tags Tags to set on the bucket.
* @throws IOException
*/
void putBucketTagging(String volumeName, String bucketName,
Map<String, String> tags) throws IOException;

/**
* Removes all tags from the specified bucket.
* @param volumeName Volume name.
* @param bucketName Bucket name.
* @throws IOException
*/
void deleteBucketTagging(String volumeName, String bucketName) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,7 @@ public OzoneBucket getBucketDetails(
.setBucketLayout(bucketInfo.getBucketLayout())
.setOwner(bucketInfo.getOwner())
.setDefaultReplicationConfig(bucketInfo.getDefaultReplicationConfig())
.setTags(bucketInfo.getTags())
.build();
}

Expand Down Expand Up @@ -1374,6 +1375,7 @@ public List<OzoneBucket> listBuckets(String volumeName, String bucketPrefix,
.setOwner(bucket.getOwner())
.setDefaultReplicationConfig(
bucket.getDefaultReplicationConfig())
.setTags(bucket.getTags())
.build())
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -2885,6 +2887,55 @@ public void deleteObjectTagging(String volumeName, String bucketName,
ozoneManagerClient.deleteObjectTagging(keyArgs);
}

@Override
public Map<String, String> getBucketTagging(String volumeName, String bucketName)
throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.S3_BUCKET_TAGGING_API) < 0) {
throw new IOException("OzoneManager does not support S3 bucket tagging API");
}

verifyVolumeName(volumeName);
verifyBucketName(bucketName);
OmBucketArgs bucketArgs = new OmBucketArgs.Builder()
.setVolumeName(volumeName)
.setBucketName(bucketName)
.build();
return ozoneManagerClient.getBucketTagging(bucketArgs);
}

@Override
public void putBucketTagging(String volumeName, String bucketName,
Map<String, String> tags) throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.S3_BUCKET_TAGGING_API) < 0) {
throw new IOException("OzoneManager does not support S3 bucket tagging API");
}

verifyVolumeName(volumeName);
verifyBucketName(bucketName);
OmBucketArgs bucketArgs = new OmBucketArgs.Builder()
.setVolumeName(volumeName)
.setBucketName(bucketName)
.addAllTags(tags)
.build();
ozoneManagerClient.putBucketTagging(bucketArgs);
}

@Override
public void deleteBucketTagging(String volumeName, String bucketName)
throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.S3_BUCKET_TAGGING_API) < 0) {
throw new IOException("OzoneManager does not support S3 bucket tagging API");
}

verifyVolumeName(volumeName);
verifyBucketName(bucketName);
OmBucketArgs bucketArgs = new OmBucketArgs.Builder()
.setVolumeName(volumeName)
.setBucketName(bucketName)
.build();
ozoneManagerClient.deleteBucketTagging(bucketArgs);
}

private static ExecutorService createThreadPoolExecutor(
int corePoolSize, int maximumPoolSize, String threadNameFormat) {
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1219,10 +1219,24 @@ default void deleteObjectTagging(OmKeyArgs args) throws IOException {
* @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.
Map<String, String> getBucketTagging(OmBucketArgs args) throws IOException;

/**
* Sets tags on an existing bucket (replaces existing tag set).
* @param args Bucket args
*/
default void putBucketTagging(OmBucketArgs args) throws IOException {
throw new UnsupportedOperationException("OzoneManager does not require " +
"this to be implemented, as write requests use a new approach.");
}

/**
* Removes all tags from the specified bucket.
* @param args Bucket args
*/
default void deleteBucketTagging(OmBucketArgs args) throws IOException {
throw new UnsupportedOperationException("OzoneManager does not require " +
"this to be implemented, as bucket tagging client support is pending.");
"this to be implemented, as write requests use a new approach.");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteBucketRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteBucketTaggingRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeyArgs;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeyRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeysRequest;
Expand All @@ -136,6 +137,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FinalizeUpgradeResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetAclRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetAclResponse;
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.GetDelegationTokenResponseProto;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusResponse;
Expand Down Expand Up @@ -191,6 +194,7 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutBucketTaggingRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PutObjectTaggingRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RangerBGSyncRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RangerBGSyncResponse;
Expand Down Expand Up @@ -2752,6 +2756,67 @@ public void deleteObjectTagging(OmKeyArgs args) throws IOException {
handleError(omResponse);
}

@Override
public Map<String, String> getBucketTagging(OmBucketArgs args) throws IOException {
BucketArgs bucketArgs = BucketArgs.newBuilder()
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName())
.build();

GetBucketTaggingRequest req =
GetBucketTaggingRequest.newBuilder()
.setBucketArgs(bucketArgs)
.build();

OMRequest omRequest = createOMRequest(Type.GetBucketTagging)
.setGetBucketTaggingRequest(req)
.build();

GetBucketTaggingResponse resp =
handleError(submitRequest(omRequest)).getGetBucketTaggingResponse();

return KeyValueUtil.getFromProtobuf(resp.getTagsList());
}

@Override
public void putBucketTagging(OmBucketArgs args) throws IOException {
BucketArgs bucketArgs = BucketArgs.newBuilder()
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName())
.addAllTags(KeyValueUtil.toProtobuf(args.getTags()))
.build();

PutBucketTaggingRequest req =
PutBucketTaggingRequest.newBuilder()
.setBucketArgs(bucketArgs)
.build();

OMRequest omRequest = createOMRequest(Type.PutBucketTagging)
.setPutBucketTaggingRequest(req)
.build();

handleError(submitRequest(omRequest));
}

@Override
public void deleteBucketTagging(OmBucketArgs args) throws IOException {
BucketArgs bucketArgs = BucketArgs.newBuilder()
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName())
.build();

DeleteBucketTaggingRequest req =
DeleteBucketTaggingRequest.newBuilder()
.setBucketArgs(bucketArgs)
.build();

OMRequest omRequest = createOMRequest(Type.DeleteBucketTagging)
.setDeleteBucketTaggingRequest(req)
.build();

handleError(submitRequest(omRequest));
}

private SafeMode toProtoBuf(SafeModeAction action) {
switch (action) {
case ENTER:
Expand Down
Loading