This is an automated email from the ASF dual-hosted git repository.
siyao 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 b8d97eb HDDS-6171. Create an API to change Bucket Owner (#2988)
b8d97eb is described below
commit b8d97eb3788d582721cd3f7824b63c1a2499934a
Author: Aswin Shakil Balasubramanian <[email protected]>
AuthorDate: Wed Jan 19 18:37:48 2022 -0800
HDDS-6171. Create an API to change Bucket Owner (#2988)
---
.../apache/hadoop/ozone/client/OzoneBucket.java | 11 ++
.../ozone/client/protocol/ClientProtocol.java | 10 ++
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 13 ++
.../hadoop/ozone/om/helpers/OmBucketArgs.java | 36 +++-
.../hadoop/ozone/om/helpers/OmBucketInfo.java | 10 +-
.../ozone/om/protocol/OzoneManagerProtocol.java | 12 ++
...OzoneManagerProtocolClientSideTranslatorPB.java | 22 +++
.../client/rpc/TestOzoneRpcClientAbstract.java | 22 +++
.../src/main/proto/OmClientProtocol.proto | 3 +-
.../om/ratis/utils/OzoneManagerRatisUtils.java | 9 +-
.../om/request/bucket/OMBucketSetOwnerRequest.java | 199 +++++++++++++++++++++
.../response/bucket/OMBucketSetOwnerResponse.java | 80 +++++++++
.../hadoop/ozone/shell/bucket/BucketCommands.java | 3 +-
.../ozone/shell/bucket/UpdateBucketHandler.java | 62 +++++++
14 files changed, 484 insertions(+), 8 deletions(-)
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
index 23cf922..16d5a1b 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
@@ -906,6 +906,17 @@ public class OzoneBucket extends WithMetadata {
}
/**
+ * Sets/Changes the owner of this Bucket.
+ * @param userName new owner
+ * @throws IOException
+ */
+ public boolean setOwner(String userName) throws IOException{
+ boolean result = proxy.setBucketOwner(volumeName, name, userName);
+ this.owner = userName;
+ return result;
+ }
+
+ /**
* An Iterator to iterate over {@link OzoneKey} list.
*/
private class KeyIterator implements Iterator<OzoneKey> {
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
index 8d6ea10..0431604 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
@@ -772,4 +772,14 @@ public interface ClientProtocol {
* Clears the S3 Authentication information attached to the thread.
*/
void clearTheadLocalS3Auth();
+
+ /**
+ * Sets the owner of bucket.
+ * @param volumeName Name of the Volume
+ * @param bucketName Name of the Bucket
+ * @param owner to be set for the bucket
+ * @throws IOException
+ */
+ boolean setBucketOwner(String volumeName, String bucketName,
+ String owner) throws IOException;
}
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
index 77ab1b0..966e381 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
@@ -1583,4 +1583,17 @@ public class RpcClient implements ClientProtocol {
public void clearTheadLocalS3Auth() {
ozoneManagerClient.clearThreadLocalS3Auth();
}
+
+ @Override
+ public boolean setBucketOwner(String volumeName, String bucketName,
+ String owner) throws IOException {
+ verifyVolumeName(volumeName);
+ verifyBucketName(bucketName);
+ Preconditions.checkNotNull(owner);
+ OmBucketArgs.Builder builder = OmBucketArgs.newBuilder();
+ builder.setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setOwnerName(owner);
+ return ozoneManagerClient.setBucketOwner(builder.build());
+ }
}
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 1c8c18a..1806a03 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
@@ -51,6 +51,10 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
private long quotaInBytes;
private long quotaInNamespace;
+ /**
+ * Bucket Owner Name.
+ */
+ private String ownerName;
/**
* Private constructor, constructed via builder.
@@ -61,9 +65,11 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
* @param quotaInBytes Volume quota in bytes.
* @param quotaInNamespace Volume quota in counts.
*/
+ @SuppressWarnings("checkstyle:ParameterNumber")
private OmBucketArgs(String volumeName, String bucketName,
Boolean isVersionEnabled, StorageType storageType,
- Map<String, String> metadata, long quotaInBytes, long quotaInNamespace) {
+ Map<String, String> metadata, long quotaInBytes, long quotaInNamespace,
+ String ownerName) {
this.volumeName = volumeName;
this.bucketName = bucketName;
this.isVersionEnabled = isVersionEnabled;
@@ -71,6 +77,7 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
this.metadata = metadata;
this.quotaInBytes = quotaInBytes;
this.quotaInNamespace = quotaInNamespace;
+ this.ownerName = ownerName;
}
/**
@@ -122,6 +129,14 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
}
/**
+ * Returns Bucket Owner Name.
+ * @return ownerName.
+ */
+ public String getOwnerName() {
+ return ownerName;
+ }
+
+ /**
* Returns new builder class that builds a OmBucketArgs.
* @return Builder
*/
@@ -141,6 +156,9 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
if(this.storageType != null){
auditMap.put(OzoneConsts.STORAGE_TYPE, this.storageType.name());
}
+ if (this.ownerName != null) {
+ auditMap.put(OzoneConsts.OWNER, this.ownerName);
+ }
return auditMap;
}
@@ -155,7 +173,7 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
private Map<String, String> metadata;
private long quotaInBytes;
private long quotaInNamespace;
-
+ private String ownerName;
/**
* Constructs a builder.
*/
@@ -199,6 +217,11 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
return this;
}
+ public Builder setOwnerName(String owner) {
+ ownerName = owner;
+ return this;
+ }
+
/**
* Constructs the OmBucketArgs.
* @return instance of OmBucketArgs.
@@ -207,7 +230,7 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
Preconditions.checkNotNull(volumeName);
Preconditions.checkNotNull(bucketName);
return new OmBucketArgs(volumeName, bucketName, isVersionEnabled,
- storageType, metadata, quotaInBytes, quotaInNamespace);
+ storageType, metadata, quotaInBytes, quotaInNamespace, ownerName);
}
}
@@ -230,6 +253,9 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
if(quotaInNamespace > 0 || quotaInNamespace == OzoneConsts.QUOTA_RESET) {
builder.setQuotaInNamespace(quotaInNamespace);
}
+ if (ownerName != null) {
+ builder.setOwnerName(ownerName);
+ }
return builder.build();
}
@@ -247,6 +273,8 @@ public final class OmBucketArgs extends WithMetadata
implements Auditable {
bucketArgs.getStorageType()) : null,
KeyValueUtil.getFromProtobuf(bucketArgs.getMetadataList()),
bucketArgs.getQuotaInBytes(),
- bucketArgs.getQuotaInNamespace());
+ bucketArgs.getQuotaInNamespace(),
+ bucketArgs.hasOwnerName() ?
+ bucketArgs.getOwnerName() : null);
}
}
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 786bb74..adbf398 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
@@ -91,7 +91,7 @@ public final class OmBucketInfo extends WithObjectID
implements Auditable {
*/
private BucketLayout bucketLayout;
- private final String owner;
+ private String owner;
/**
* Private constructor, constructed via builder.
@@ -297,6 +297,14 @@ public final class OmBucketInfo extends WithObjectID
implements Auditable {
return owner;
}
+ public void setModificationTime(long modificationTime) {
+ this.modificationTime = modificationTime;
+ }
+
+ public void setOwner(String ownerName) {
+ this.owner = ownerName;
+ }
+
/**
* Returns new builder class that builds a OmBucketInfo.
*
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 7bc67da..7da3bb8 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
@@ -199,6 +199,18 @@ public interface OzoneManagerProtocol
"this to be implemented, as write requests use a new approach.");
}
+ /**
+ * Changes the owner of a bucket.
+ * @param args - OMBucketArgs
+ * @return true if operation succeeded, false if specified user is
+ * already the owner.
+ * @throws IOException
+ */
+ default boolean setBucketOwner(OmBucketArgs args) throws IOException {
+ throw new UnsupportedOperationException("OzoneManager does not require " +
+ "this to be implemented, as write requests use a new approach.");
+ }
+
/**
* Open the given key and return an open key session.
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
index b2c367f..e2bf9f0 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
@@ -527,6 +527,28 @@ public final class
OzoneManagerProtocolClientSideTranslatorPB
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean setBucketOwner(OmBucketArgs args)
+ throws IOException {
+ SetBucketPropertyRequest.Builder req =
+ SetBucketPropertyRequest.newBuilder();
+ BucketArgs bucketArgs = args.getProtobuf();
+ req.setBucketArgs(bucketArgs);
+
+ OMRequest omRequest = createOMRequest(Type.SetBucketProperty)
+ .setSetBucketPropertyRequest(req)
+ .build();
+
+ OMResponse omResponse = submitRequest(omRequest);
+ SetBucketPropertyResponse response =
+ handleError(omResponse).getSetBucketPropertyResponse();
+
+ return response.getResponse();
+ }
+
+ /**
* List buckets in a volume.
*
* @param volumeName
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java
index 222e352..897ad22 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java
@@ -298,6 +298,28 @@ public abstract class TestOzoneRpcClientAbstract {
}
@Test
+ public void testBucketSetOwner() throws IOException {
+ String volumeName = UUID.randomUUID().toString();
+ String bucketName = UUID.randomUUID().toString();
+ store.createVolume(volumeName);
+ store.getVolume(volumeName).createBucket(bucketName);
+
+ String oldOwner = store.getVolume(volumeName).getBucket(bucketName)
+ .getOwner();
+ String ownerName = "testUser";
+
+ ClientProtocol proxy = store.getClientProxy();
+ proxy.setBucketOwner(volumeName, bucketName, ownerName);
+ String newOwner = store.getVolume(volumeName).getBucket(bucketName)
+ .getOwner();
+
+ assertEquals(ownerName, newOwner);
+ assertNotEquals(oldOwner, newOwner);
+ store.getVolume(volumeName).deleteBucket(bucketName);
+ store.deleteVolume(volumeName);
+ }
+
+ @Test
public void testSetAndClrQuota() throws Exception {
String volumeName = UUID.randomUUID().toString();
String bucketName = UUID.randomUUID().toString();
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index e69f08d..df3f2cc 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -623,6 +623,7 @@ message BucketArgs {
repeated hadoop.hdds.KeyValue metadata = 7;
optional uint64 quotaInBytes = 8;
optional uint64 quotaInNamespace = 9;
+ optional string ownerName = 10;
}
message PrefixInfo {
@@ -730,7 +731,7 @@ message SetBucketPropertyRequest {
}
message SetBucketPropertyResponse {
-
+ optional bool response = 1;
}
message DeleteBucketRequest {
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 0480859..47c2eb8 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
@@ -39,6 +39,7 @@ import
org.apache.hadoop.ozone.om.ratis.OzoneManagerRatisServer.RaftServerStatus
import org.apache.hadoop.ozone.om.request.OMKeyRequestFactory;
import org.apache.hadoop.ozone.om.request.bucket.OMBucketCreateRequest;
import org.apache.hadoop.ozone.om.request.bucket.OMBucketDeleteRequest;
+import org.apache.hadoop.ozone.om.request.bucket.OMBucketSetOwnerRequest;
import org.apache.hadoop.ozone.om.request.bucket.OMBucketSetPropertyRequest;
import org.apache.hadoop.ozone.om.request.OMClientRequest;
import org.apache.hadoop.ozone.om.request.bucket.acl.OMBucketAddAclRequest;
@@ -141,7 +142,13 @@ public final class OzoneManagerRatisUtils {
case DeleteBucket:
return new OMBucketDeleteRequest(omRequest);
case SetBucketProperty:
- return new OMBucketSetPropertyRequest(omRequest);
+ boolean hasBucketOwner = omRequest.getSetBucketPropertyRequest()
+ .getBucketArgs().hasOwnerName();
+ if (hasBucketOwner) {
+ return new OMBucketSetOwnerRequest(omRequest);
+ } else {
+ return new OMBucketSetPropertyRequest(omRequest);
+ }
case AddAcl:
case RemoveAcl:
case SetAcl:
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
new file mode 100644
index 0000000..6aad48b
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
@@ -0,0 +1,199 @@
+/**
+ * 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.bucket;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.audit.AuditLogger;
+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.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+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.OMBucketSetOwnerResponse;
+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.SetBucketPropertyRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetBucketPropertyResponse;
+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;
+
+import java.io.IOException;
+
+import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
+
+/**
+ * Handle set owner request for bucket.
+ */
+public class OMBucketSetOwnerRequest extends OMClientRequest {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(OMBucketSetOwnerRequest.class);
+
+ public OMBucketSetOwnerRequest(OMRequest omRequest) {
+ super(omRequest);
+ }
+
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager)
+ throws IOException {
+ long modificationTime = Time.now();
+ OzoneManagerProtocolProtos.SetBucketPropertyRequest.Builder
+ setBucketPropertyRequestBuilder = getOmRequest()
+ .getSetBucketPropertyRequest().toBuilder()
+ .setModificationTime(modificationTime);
+
+ return getOmRequest().toBuilder()
+ .setSetBucketPropertyRequest(setBucketPropertyRequestBuilder)
+ .setUserInfo(getUserInfo())
+ .build();
+ }
+
+ @Override
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
+ long transactionLogIndex,
+ OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
+ SetBucketPropertyRequest setBucketPropertyRequest =
+ getOmRequest().getSetBucketPropertyRequest();
+ Preconditions.checkNotNull(setBucketPropertyRequest);
+
+ OMResponse.Builder omResponse = OmResponseUtil.getOMResponseBuilder(
+ getOmRequest());
+
+ if (!setBucketPropertyRequest.getBucketArgs().hasOwnerName()) {
+ omResponse.setStatus(OzoneManagerProtocolProtos.Status.INVALID_REQUEST)
+ .setSuccess(false);
+ return new OMBucketSetOwnerResponse(omResponse.build());
+ }
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ OMMetrics omMetrics = ozoneManager.getMetrics();
+ omMetrics.incNumBucketUpdates();
+
+ BucketArgs bucketArgs = setBucketPropertyRequest.getBucketArgs();
+ OmBucketArgs omBucketArgs = OmBucketArgs.getFromProtobuf(bucketArgs);
+
+ String volumeName = bucketArgs.getVolumeName();
+ String bucketName = bucketArgs.getBucketName();
+ String newOwner = bucketArgs.getOwnerName();
+ String oldOwner = null;
+
+ AuditLogger auditLogger = ozoneManager.getAuditLogger();
+ OzoneManagerProtocolProtos.UserInfo userInfo =
getOmRequest().getUserInfo();
+ IOException exception = null;
+ boolean acquiredBucketLock = false, success = true;
+ OMClientResponse omClientResponse = null;
+ try {
+ // check Acl
+ if (ozoneManager.getAclsEnabled()) {
+ checkAcls(ozoneManager, OzoneObj.ResourceType.BUCKET,
+ OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE_ACL,
+ volumeName, bucketName, null);
+ }
+
+ // acquire lock.
+ acquiredBucketLock = omMetadataManager.getLock().acquireWriteLock(
+ BUCKET_LOCK, volumeName, bucketName);
+
+ String bucketKey = omMetadataManager.getBucketKey(volumeName,
bucketName);
+ OmBucketInfo omBucketInfo =
+ omMetadataManager.getBucketTable().get(bucketKey);
+ //Check if bucket exist
+ if (omBucketInfo == null) {
+ LOG.debug("Bucket: {} not found ", bucketName);
+ throw new OMException("Bucket doesnt exist",
+ OMException.ResultCodes.BUCKET_NOT_FOUND);
+ }
+
+ oldOwner = omBucketInfo.getOwner();
+
+ if (oldOwner.equals(newOwner)) {
+ LOG.warn("Bucket '{}/{}' owner is already user '{}'.",
+ volumeName, bucketName, oldOwner);
+ omResponse.setStatus(OzoneManagerProtocolProtos.Status.OK)
+ .setMessage("Bucket '" + volumeName + "/" + bucketName +
+ "' owner is already '" + newOwner + "'.")
+ .setSuccess(false);
+ omResponse.setSetBucketPropertyResponse(
+ SetBucketPropertyResponse.newBuilder().setResponse(false).build());
+ omClientResponse = new OMBucketSetOwnerResponse(omResponse.build());
+ return omClientResponse;
+ }
+
+ omBucketInfo.setOwner(newOwner);
+ LOG.debug("Updating bucket owner to {} for bucket: {} in volume: {}",
+ newOwner, bucketName, volumeName);
+
+ omBucketInfo.setModificationTime(
+ setBucketPropertyRequest.getModificationTime());
+ // Set the updateID to current transaction log index
+ omBucketInfo.setUpdateID(transactionLogIndex,
+ ozoneManager.isRatisEnabled());
+
+ // Update table cache.
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey),
+ new CacheValue<>(Optional.of(omBucketInfo), transactionLogIndex));
+
+ omResponse.setSetBucketPropertyResponse(
+ SetBucketPropertyResponse.newBuilder().setResponse(true).build());
+ omClientResponse = new OMBucketSetOwnerResponse(
+ omResponse.build(), omBucketInfo);
+ } catch (IOException ex) {
+ success = false;
+ exception = ex;
+ omClientResponse = new OMBucketSetOwnerResponse(
+ createErrorOMResponse(omResponse, exception));
+ } finally {
+ addResponseToDoubleBuffer(transactionLogIndex, omClientResponse,
+ ozoneManagerDoubleBufferHelper);
+ if (acquiredBucketLock) {
+ omMetadataManager.getLock().releaseWriteLock(BUCKET_LOCK, volumeName,
+ bucketName);
+ }
+ }
+
+ // Performing audit logging outside of the lock.
+ auditLog(auditLogger, buildAuditMessage(OMAction.SET_OWNER,
+ omBucketArgs.toAuditMap(), exception, userInfo));
+
+ // return response.
+ if (success) {
+ LOG.debug("Successfully changed Owner of Bucket {}/{} from {} -> {}",
+ volumeName, bucketName, oldOwner, newOwner);
+ return omClientResponse;
+ } else {
+ LOG.error("Setting Owner failed for bucket:{} in volume:{}",
+ bucketName, volumeName, exception);
+ omMetrics.incNumBucketUpdateFails();
+ return omClientResponse;
+ }
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/bucket/OMBucketSetOwnerResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/bucket/OMBucketSetOwnerResponse.java
new file mode 100644
index 0000000..268787f
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/bucket/OMBucketSetOwnerResponse.java
@@ -0,0 +1,80 @@
+/**
+ * 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.response.bucket;
+
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
+ .OMResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.BUCKET_TABLE;
+
+/**
+ * Response for set owner request.
+ */
+@CleanupTableInfo(cleanupTables = {BUCKET_TABLE})
+public class OMBucketSetOwnerResponse extends OMClientResponse {
+
+ private OmBucketInfo omBucketInfo;
+
+ public OMBucketSetOwnerResponse(@Nonnull OMResponse omResponse,
+ @Nonnull OmBucketInfo omBucketInfo) {
+ super(omResponse);
+ this.omBucketInfo = omBucketInfo;
+ }
+
+ /**
+ * For when the request is not successful.
+ * For a successful request, the other constructor should be used.
+ */
+ public OMBucketSetOwnerResponse(@Nonnull OMResponse omResponse) {
+ super(omResponse);
+ if (omResponse.getSuccess()) {
+ checkStatusNotOK();
+ }
+ }
+
+ @Override
+ public void checkAndUpdateDB(OMMetadataManager omMetadataManager,
+ BatchOperation batchOperation) throws IOException {
+ // When newOwner is the same as oldOwner, status is OK but success is
false.
+ // We don't want to add it to DB batch in this case.
+ if (getOMResponse().getStatus() == OzoneManagerProtocolProtos.Status.OK &&
+ getOMResponse().getSuccess()) {
+ addToDBBatch(omMetadataManager, batchOperation);
+ }
+ }
+
+ @Override
+ public void addToDBBatch(OMMetadataManager omMetadataManager,
+ BatchOperation batchOperation) throws IOException {
+
+ String dbBucketKey =
+ omMetadataManager.getBucketKey(omBucketInfo.getVolumeName(),
+ omBucketInfo.getBucketName());
+ omMetadataManager.getBucketTable().putWithBatch(batchOperation,
+ dbBucketKey, omBucketInfo);
+ }
+}
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/BucketCommands.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/BucketCommands.java
index cfb3763..2de2290 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/BucketCommands.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/BucketCommands.java
@@ -48,7 +48,8 @@ import picocli.CommandLine.ParentCommand;
RemoveAclBucketHandler.class,
GetAclBucketHandler.class,
SetAclBucketHandler.class,
- ClearQuotaHandler.class
+ ClearQuotaHandler.class,
+ UpdateBucketHandler.class
},
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class)
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/UpdateBucketHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/UpdateBucketHandler.java
new file mode 100644
index 0000000..7ba62a5
--- /dev/null
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/bucket/UpdateBucketHandler.java
@@ -0,0 +1,62 @@
+/**
+ * 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.shell.bucket;
+
+import org.apache.hadoop.ozone.client.OzoneBucket;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneClientException;
+import org.apache.hadoop.ozone.shell.OzoneAddress;
+
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+import java.io.IOException;
+
+/**
+ * Executes update bucket calls.
+ */
+@Command(name = "update",
+ description = "Updates the parameters of the bucket")
+public class UpdateBucketHandler extends BucketHandler {
+
+ @Option(names = {"--user", "-u"},
+ description = "Owner of the bucket to set")
+ private String ownerName;
+
+ @Override
+ protected void execute(OzoneClient client, OzoneAddress address)
+ throws IOException, OzoneClientException {
+
+ String volumeName = address.getVolumeName();
+ String bucketName = address.getBucketName();
+ OzoneBucket bucket = client.getObjectStore().getVolume(volumeName)
+ .getBucket(bucketName);
+
+ if (ownerName != null && !ownerName.isEmpty()) {
+ boolean result = bucket.setOwner(ownerName);
+ if (LOG.isDebugEnabled() && !result) {
+ out().format("Bucket '%s' owner is already '%s'. Unchanged.%n",
+ volumeName + "/" + bucketName, ownerName);
+ }
+ }
+
+ OzoneBucket updatedBucket = client.getObjectStore().getVolume(volumeName)
+ .getBucket(bucketName);
+ printObjectAsJson(updatedBucket);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]