This is an automated email from the ASF dual-hosted git repository.
prashantpogde 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 7f5277fabb HDDS-8994. [Multi-Tenant] Add CLI option to allow tenant
creation on top of existing volumes (#5045)
7f5277fabb is described below
commit 7f5277fabb09118860ae6e24124b4183b4b96e14
Author: Siyao Meng <[email protected]>
AuthorDate: Thu Jul 13 13:36:05 2023 -0700
HDDS-8994. [Multi-Tenant] Add CLI option to allow tenant creation on top of
existing volumes (#5045)
---
.../org/apache/hadoop/ozone/client/TenantArgs.java | 25 ++++-
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 15 ++-
.../hadoop/ozone/om/helpers/OmTenantArgs.java | 26 ++++-
...OzoneManagerProtocolClientSideTranslatorPB.java | 4 +-
.../hadoop/ozone/shell/TestOzoneTenantShell.java | 18 +++-
.../src/main/proto/OmClientProtocol.proto | 1 +
.../request/s3/tenant/OMTenantCreateRequest.java | 96 ++++++++++++------
.../response/s3/tenant/OMTenantCreateResponse.java | 19 ++--
.../hadoop/ozone/om/TestOMMultiTenantManager.java | 2 +-
.../hadoop/ozone/om/TestOMTenantCreateRequest.java | 111 +++++++++++++++++++--
.../ozone/om/request/OMRequestTestUtils.java | 6 +-
.../ozone/shell/tenant/TenantCreateHandler.java | 15 ++-
12 files changed, 277 insertions(+), 61 deletions(-)
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/TenantArgs.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/TenantArgs.java
index f1b67a5773..eed7a6829c 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/TenantArgs.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/TenantArgs.java
@@ -30,18 +30,30 @@ public final class TenantArgs {
*/
private final String volumeName;
+ /**
+ * Force tenant creation when volume exists.
+ */
+ private final boolean forceCreationWhenVolumeExists;
+
/**
* Private constructor, constructed via builder.
- * @param volumeName Volume name.
+ *
+ * @param volumeName Volume name.
+ * @param forceCreationWhenVolumeExists Force creation when volume exists.
*/
- private TenantArgs(String volumeName) {
+ private TenantArgs(String volumeName, boolean forceCreationWhenVolumeExists)
{
this.volumeName = volumeName;
+ this.forceCreationWhenVolumeExists = forceCreationWhenVolumeExists;
}
public String getVolumeName() {
return volumeName;
}
+ public boolean getForceCreationWhenVolumeExists() {
+ return forceCreationWhenVolumeExists;
+ }
+
/**
* Returns new builder class that builds a TenantArgs.
*
@@ -57,6 +69,7 @@ public final class TenantArgs {
@SuppressWarnings("checkstyle:hiddenfield")
public static class Builder {
private String volumeName;
+ private boolean forceCreationWhenVolumeExists;
/**
* Constructs a builder.
@@ -69,13 +82,19 @@ public final class TenantArgs {
return this;
}
+ public TenantArgs.Builder setForceCreationWhenVolumeExists(
+ boolean forceCreationWhenVolumeExists) {
+ this.forceCreationWhenVolumeExists = forceCreationWhenVolumeExists;
+ return this;
+ }
+
/**
* Constructs a TenantArgs.
* @return TenantArgs.
*/
public TenantArgs build() {
Preconditions.checkNotNull(volumeName);
- return new TenantArgs(volumeName);
+ return new TenantArgs(volumeName, forceCreationWhenVolumeExists);
}
}
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 f6e9b2a328..8bf0527b64 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
@@ -885,14 +885,21 @@ public class RpcClient implements ClientProtocol {
final String volumeName = tenantArgs.getVolumeName();
verifyVolumeName(volumeName);
+ final boolean forceCreationWhenVolumeExists =
+ tenantArgs.getForceCreationWhenVolumeExists();
+
OmTenantArgs.Builder builder = OmTenantArgs.newBuilder();
builder.setTenantId(tenantId);
builder.setVolumeName(volumeName);
- // TODO: Add more fields
- // TODO: Include OmVolumeArgs in (Om)TenantArgs as well for volume
creation?
+ builder.setForceCreationWhenVolumeExists(
+ tenantArgs.getForceCreationWhenVolumeExists());
+
+ // TODO: Add more fields. e.g. include OmVolumeArgs in (Om)TenantArgs
+ // as well for customized volume creation.
- LOG.info("Creating Tenant: '{}', with new volume: '{}'",
- tenantId, volumeName);
+ LOG.info("Creating Tenant: '{}', with volume: '{}', "
+ + "forceCreationWhenVolumeExists: {}",
+ tenantId, volumeName, forceCreationWhenVolumeExists);
ozoneManagerClient.createTenant(builder.build());
}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmTenantArgs.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmTenantArgs.java
index 518a08bacb..bf331c48a1 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmTenantArgs.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmTenantArgs.java
@@ -36,6 +36,11 @@ public class OmTenantArgs {
*/
private final String volumeName;
+ /**
+ * Force tenant creation when volume exists.
+ */
+ private boolean forceCreationWhenVolumeExists;
+
public OmTenantArgs(String tenantId) {
this.tenantId = tenantId;
this.volumeName = this.tenantId;
@@ -46,6 +51,13 @@ public class OmTenantArgs {
this.volumeName = volumeName;
}
+ public OmTenantArgs(String tenantId, String volumeName,
+ boolean forceCreationWhenVolumeExists) {
+ this.tenantId = tenantId;
+ this.volumeName = volumeName;
+ this.forceCreationWhenVolumeExists = forceCreationWhenVolumeExists;
+ }
+
public String getTenantId() {
return tenantId;
}
@@ -54,6 +66,10 @@ public class OmTenantArgs {
return volumeName;
}
+ public boolean getForceCreationWhenVolumeExists() {
+ return forceCreationWhenVolumeExists;
+ }
+
public static OmTenantArgs.Builder newBuilder() {
return new OmTenantArgs.Builder();
}
@@ -65,6 +81,7 @@ public class OmTenantArgs {
public static class Builder {
private String tenantId;
private String volumeName;
+ private boolean forceCreationWhenVolumeExists;
/**
* Constructs a builder.
@@ -82,10 +99,17 @@ public class OmTenantArgs {
return this;
}
+ public Builder setForceCreationWhenVolumeExists(
+ boolean forceCreationWhenVolumeExists) {
+ this.forceCreationWhenVolumeExists = forceCreationWhenVolumeExists;
+ return this;
+ }
+
public OmTenantArgs build() {
Preconditions.checkNotNull(tenantId);
Preconditions.checkNotNull(volumeName);
- return new OmTenantArgs(tenantId, volumeName);
+ return new OmTenantArgs(tenantId, volumeName,
+ forceCreationWhenVolumeExists);
}
}
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 348e364a42..e8b1bd2254 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
@@ -1074,7 +1074,9 @@ public final class
OzoneManagerProtocolClientSideTranslatorPB
final CreateTenantRequest.Builder requestBuilder =
CreateTenantRequest.newBuilder()
.setTenantId(omTenantArgs.getTenantId())
- .setVolumeName(omTenantArgs.getVolumeName());
+ .setVolumeName(omTenantArgs.getVolumeName())
+ .setForceCreationWhenVolumeExists(
+ omTenantArgs.getForceCreationWhenVolumeExists());
// Can add more args (like policy names) later if needed
final OMRequest omRequest = createOMRequest(Type.CreateTenant)
.setCreateTenantRequest(requestBuilder)
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
index c2f113743f..b6b8d295d7 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
@@ -1077,7 +1077,7 @@ public class TestOzoneTenantShell {
}
@Test
- public void testCreateTenantOnExistingVolumeShouldFail() throws IOException {
+ public void testCreateTenantOnExistingVolume() throws IOException {
final String testVolume = "existing-volume-1";
int exitC = execute(ozoneSh, new String[] {"volume", "create",
testVolume});
// Volume create should succeed
@@ -1085,12 +1085,26 @@ public class TestOzoneTenantShell {
checkOutput(out, "", true);
checkOutput(err, "", true);
- // Try to create tenant on the same volume, should fail
+ // Try to create tenant on the same volume, should fail by default
executeHA(tenantShell, new String[] {"create", testVolume});
checkOutput(out, "", true);
checkOutput(err, "Volume already exists\n", true);
+ // Try to create tenant on the same volume with --force, should work
+ executeHA(tenantShell, new String[] {"create", testVolume, "--force"});
+ checkOutput(out, "", true);
+ checkOutput(err, "", true);
+
+ // Try to create the same tenant one more time, should fail even
+ // with --force because the tenant already exists.
+ executeHA(tenantShell, new String[] {"create", testVolume, "--force"});
+ checkOutput(out, "", true);
+ checkOutput(err, "Tenant '" + testVolume + "' already exists\n", true);
+
// Clean up
+ executeHA(tenantShell, new String[] {"delete", testVolume});
+ checkOutput(out, "", true);
+ checkOutput(err, "Deleted tenant '" + testVolume + "'.\n", false);
deleteVolume(testVolume);
}
}
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 2655c30c11..760d68557a 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -1724,6 +1724,7 @@ message CreateTenantRequest {
optional string volumeName = 2;
optional string userRoleName = 3;
optional string adminRoleName = 4;
+ optional bool forceCreationWhenVolumeExists = 5;
}
message SetRangerServiceVersionRequest {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
index 2c7158c4f4..d61ad27d27 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
@@ -147,9 +147,16 @@ public class OMTenantCreateRequest extends OMVolumeRequest
{
final String dbVolumeKey = ozoneManager.getMetadataManager()
.getVolumeKey(volumeName);
+ // Backwards compatibility with older Ozone clients that don't have this
+ // field. Defaults to false.
+ boolean forceCreationWhenVolumeExists =
+ request.hasForceCreationWhenVolumeExists()
+ && request.getForceCreationWhenVolumeExists();
+
// Check volume existence
- if (ozoneManager.getMetadataManager().getVolumeTable()
- .isExist(dbVolumeKey)) {
+ if (!forceCreationWhenVolumeExists &&
+ ozoneManager.getMetadataManager().getVolumeTable().isExist(
+ dbVolumeKey)) {
LOG.debug("volume: '{}' already exists", volumeName);
throw new OMException("Volume already exists", VOLUME_ALREADY_EXISTS);
}
@@ -192,7 +199,9 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
.setTenantId(tenantId)
.setVolumeName(volumeName)
.setUserRoleName(userRoleName)
- .setAdminRoleName(adminRoleName))
+ .setAdminRoleName(adminRoleName)
+ .setForceCreationWhenVolumeExists(
+ forceCreationWhenVolumeExists))
.setCreateVolumeRequest(
CreateVolumeRequest.newBuilder()
.setVolumeInfo(updatedVolumeInfo));
@@ -216,7 +225,7 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
OMClientResponse omClientResponse = null;
final OMResponse.Builder omResponse =
OmResponseUtil.getOMResponseBuilder(getOmRequest());
- OmVolumeArgs omVolumeArgs;
+ OmVolumeArgs omVolumeArgs = null;
boolean acquiredVolumeLock = false;
boolean acquiredUserLock = false;
final String owner = getOmRequest().getUserInfo().getUserName();
@@ -227,6 +236,8 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
final String tenantId = request.getTenantId();
final String userRoleName = request.getUserRoleName();
final String adminRoleName = request.getAdminRoleName();
+ final boolean forceCreationWhenVolumeExists =
+ request.getForceCreationWhenVolumeExists();
final VolumeInfo volumeInfo =
getOmRequest().getCreateVolumeRequest().getVolumeInfo();
@@ -249,41 +260,64 @@ public class OMTenantCreateRequest extends
OMVolumeRequest {
acquiredVolumeLock = omMetadataManager.getLock().acquireWriteLock(
VOLUME_LOCK, volumeName);
+ boolean skipVolumeCreation = false;
// Check volume existence
if (omMetadataManager.getVolumeTable().isExist(dbVolumeKey)) {
LOG.debug("volume: '{}' already exists", volumeName);
- throw new OMException("Volume already exists", VOLUME_ALREADY_EXISTS);
+ if (forceCreationWhenVolumeExists) {
+ LOG.warn("forceCreationWhenVolumeExists = true. Resuming "
+ + "tenant creation despite volume '{}' existence", volumeName);
+ skipVolumeCreation = true;
+ } else {
+ // forceCreationWhenVolumeExists is false, throw
+ throw new OMException("Volume already exists",
VOLUME_ALREADY_EXISTS);
+ }
+ }
+
+ acquiredUserLock = omMetadataManager.getLock().acquireWriteLock(
+ USER_LOCK, owner);
+
+ PersistedUserVolumeInfo volumeList = null;
+ if (!skipVolumeCreation) {
+ // Create volume. TODO: dedup OMVolumeCreateRequest
+ omVolumeArgs = OmVolumeArgs.getFromProtobuf(volumeInfo);
+ omVolumeArgs.setQuotaInBytes(OzoneConsts.QUOTA_RESET);
+ omVolumeArgs.setQuotaInNamespace(OzoneConsts.QUOTA_RESET);
+ omVolumeArgs.setObjectID(
+ ozoneManager.getObjectIdFromTxId(transactionLogIndex));
+ omVolumeArgs.setUpdateID(transactionLogIndex,
+ ozoneManager.isRatisEnabled());
+
+ omVolumeArgs.incRefCount();
+ // Remove this check when vol ref count is also used by other features
+ Preconditions.checkState(omVolumeArgs.getRefCount() == 1L,
+ "refCount should have been set to 1");
+
+ final String dbUserKey = omMetadataManager.getUserKey(owner);
+ volumeList = omMetadataManager.getUserTable().get(dbUserKey);
+ volumeList = addVolumeToOwnerList(volumeList, volumeName, owner,
+ ozoneManager.getMaxUserVolumeCount(), transactionLogIndex);
+ createVolume(omMetadataManager, omVolumeArgs, volumeList, dbVolumeKey,
+ dbUserKey, transactionLogIndex);
+ LOG.debug("volume: '{}' successfully created", dbVolumeKey);
+ } else {
+ LOG.info("Skipped volume '{}' creation. "
+ + "Will only increment volume refCount", volumeName);
+ omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName);
+
+ omVolumeArgs.incRefCount();
+ // Remove this check when vol ref count is also used by other features
+ Preconditions.checkState(omVolumeArgs.getRefCount() == 1L,
+ "refCount should have been set to 1");
+
+ omMetadataManager.getVolumeTable().addCacheEntry(
+ new CacheKey<>(omMetadataManager.getVolumeKey(volumeName)),
+ CacheValue.get(transactionLogIndex, omVolumeArgs));
}
- // Create volume
- acquiredUserLock =
omMetadataManager.getLock().acquireWriteLock(USER_LOCK,
- owner);
-
- // TODO: dedup OMVolumeCreateRequest
- omVolumeArgs = OmVolumeArgs.getFromProtobuf(volumeInfo);
- omVolumeArgs.setQuotaInBytes(OzoneConsts.QUOTA_RESET);
- omVolumeArgs.setQuotaInNamespace(OzoneConsts.QUOTA_RESET);
- omVolumeArgs.setObjectID(
- ozoneManager.getObjectIdFromTxId(transactionLogIndex));
- omVolumeArgs.setUpdateID(transactionLogIndex,
- ozoneManager.isRatisEnabled());
- // Set volume reference count to 1
- omVolumeArgs.incRefCount();
- Preconditions.checkState(omVolumeArgs.getRefCount() == 1,
- "refCount should have been set to 1");
// Audit
auditMap = omVolumeArgs.toAuditMap();
- PersistedUserVolumeInfo volumeList;
- final String dbUserKey = omMetadataManager.getUserKey(owner);
- volumeList = omMetadataManager.getUserTable().get(dbUserKey);
- volumeList = addVolumeToOwnerList(volumeList, volumeName, owner,
- ozoneManager.getMaxUserVolumeCount(), transactionLogIndex);
- createVolume(omMetadataManager, omVolumeArgs, volumeList, dbVolumeKey,
- dbUserKey, transactionLogIndex);
- LOG.debug("volume: '{}' successfully created", dbVolumeKey);
-
-
// Check tenant existence in tenantStateTable
if (omMetadataManager.getTenantStateTable().isExist(tenantId)) {
LOG.debug("tenant: '{}' already exists", tenantId);
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
index 11172cbcd1..a845734dd5 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
@@ -26,7 +26,7 @@ import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
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.storage.proto.OzoneManagerStorageProtos;
+import
org.apache.hadoop.ozone.storage.proto.OzoneManagerStorageProtos.PersistedUserVolumeInfo;
import javax.annotation.Nonnull;
import java.io.IOException;
@@ -43,13 +43,13 @@ import static
org.apache.hadoop.ozone.om.OmMetadataManagerImpl.VOLUME_TABLE;
})
public class OMTenantCreateResponse extends OMClientResponse {
- private OzoneManagerStorageProtos.PersistedUserVolumeInfo userVolumeInfo;
+ private PersistedUserVolumeInfo userVolumeInfo;
private OmVolumeArgs omVolumeArgs;
private OmDBTenantState omTenantState;
public OMTenantCreateResponse(@Nonnull OMResponse omResponse,
@Nonnull OmVolumeArgs omVolumeArgs,
- @Nonnull OzoneManagerStorageProtos.PersistedUserVolumeInfo
userVolumeInfo,
+ PersistedUserVolumeInfo userVolumeInfo,
@Nonnull OmDBTenantState omTenantState
) {
super(omResponse);
@@ -78,13 +78,16 @@ public class OMTenantCreateResponse extends
OMClientResponse {
// From OMVolumeCreateResponse
String dbVolumeKey =
omMetadataManager.getVolumeKey(omVolumeArgs.getVolume());
- String dbUserKey =
- omMetadataManager.getUserKey(omVolumeArgs.getOwnerName());
-
omMetadataManager.getVolumeTable().putWithBatch(batchOperation,
dbVolumeKey, omVolumeArgs);
- omMetadataManager.getUserTable().putWithBatch(batchOperation, dbUserKey,
- userVolumeInfo);
+
+ // userVolumeInfo can be null when skipped volume creation
+ if (userVolumeInfo != null) {
+ String dbUserKey =
+ omMetadataManager.getUserKey(omVolumeArgs.getOwnerName());
+ omMetadataManager.getUserTable().putWithBatch(batchOperation, dbUserKey,
+ userVolumeInfo);
+ }
}
@VisibleForTesting
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
index 39062472c8..41ab197c4f 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
@@ -139,7 +139,7 @@ public class TestOMMultiTenantManager {
// Check that Multi-Tenancy write requests are blocked when not enabled
expectWriteRequestToFail(ozoneManager,
- OMRequestTestUtils.createTenantRequest(tenantId));
+ OMRequestTestUtils.createTenantRequest(tenantId, false));
expectWriteRequestToFail(ozoneManager,
OMRequestTestUtils.deleteTenantRequest(tenantId));
expectWriteRequestToFail(ozoneManager,
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
index ff7407e3db..5b8762ed4f 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMTenantCreateRequest.java
@@ -28,8 +28,10 @@ import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
import org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantCreateRequest;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
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.Status;
import org.apache.ozone.test.LambdaTestUtils;
import org.junit.After;
import org.junit.Assert;
@@ -39,6 +41,7 @@ import org.junit.rules.TemporaryFolder;
import org.junit.Test;
import org.mockito.Mockito;
+import java.io.IOException;
import java.util.UUID;
import static org.mockito.ArgumentMatchers.any;
@@ -102,6 +105,102 @@ public class TestOMTenantCreateRequest {
Mockito.framework().clearInlineMocks();
}
+ @Test
+ public void testValidateAndUpdateCache() throws IOException {
+ // Happy path
+
+ final String tenantId = UUID.randomUUID().toString();
+
+ OMRequest originalRequest =
+ OMRequestTestUtils.createTenantRequest(tenantId, false);
+ OMTenantCreateRequest omTenantCreateRequest =
+ Mockito.spy(new OMTenantCreateRequest(originalRequest));
+ Mockito.doReturn("username").when(omTenantCreateRequest).getUserName();
+
+ // First creation should be successful
+ OMRequest modifiedRequest = omTenantCreateRequest.preExecute(ozoneManager);
+ omTenantCreateRequest = new OMTenantCreateRequest(modifiedRequest);
+
+ long txLogIndex = 1L;
+ OMClientResponse omClientResponse =
+ omTenantCreateRequest.validateAndUpdateCache(ozoneManager, txLogIndex,
+ ozoneManagerDoubleBufferHelper);
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ Assert.assertNotNull(omResponse.getCreateTenantResponse());
+ Assert.assertEquals(Status.OK, omResponse.getStatus());
+ Assert.assertNotNull(omMetadataManager.getVolumeTable().get(
+ omMetadataManager.getVolumeKey(tenantId)));
+ }
+
+ @Test
+ public void testValidateAndUpdateCacheWhenVolumeExists() throws Exception {
+ // Check that forceCreationWhenVolumeExists flag behaves as expected
+
+ final String tenantId = UUID.randomUUID().toString();
+ final String ownerName = "username";
+
+ // Deliberately put volume entry in VolumeTable, to simulate the case where
+ // the volume already exists.
+ OMRequestTestUtils.addVolumeToDB(tenantId, ownerName, omMetadataManager);
+
+ // First with forceCreationWhenVolumeExists = false
+ OMRequest originalRequest =
+ OMRequestTestUtils.createTenantRequest(tenantId, false);
+ OMTenantCreateRequest omTenantCreateRequest1 =
+ Mockito.spy(new OMTenantCreateRequest(originalRequest));
+ Mockito.doReturn(ownerName).when(omTenantCreateRequest1).getUserName();
+
+ // Should throw in preExecute
+ LambdaTestUtils.intercept(OMException.class, "VOLUME_ALREADY_EXISTS",
+ () -> omTenantCreateRequest1.preExecute(ozoneManager));
+
+ // Now with forceCreationWhenVolumeExists = true
+ originalRequest =
+ OMRequestTestUtils.createTenantRequest(tenantId, true);
+ OMTenantCreateRequest omTenantCreateRequest2 =
+ Mockito.spy(new OMTenantCreateRequest(originalRequest));
+ Mockito.doReturn(ownerName).when(omTenantCreateRequest2).getUserName();
+
+ // Should not throw now that forceCreationWhenVolumeExists = true
+ OMRequest modifiedRequest =
omTenantCreateRequest2.preExecute(ozoneManager);
+ omTenantCreateRequest2 = new OMTenantCreateRequest(modifiedRequest);
+
+ // Craft a request that sets forceCreationWhenVolumeExists to false to test
+ // validateAndUpdateCache.
+ CreateTenantRequest reqPostPreExecute =
+ omTenantCreateRequest2.getOmRequest().getCreateTenantRequest();
+ OMRequest modReqPostPreExecute =
+ omTenantCreateRequest2.getOmRequest().toBuilder()
+ .setCreateTenantRequest(
+ CreateTenantRequest.newBuilder()
+ .setTenantId(tenantId)
+ .setVolumeName(reqPostPreExecute.getVolumeName())
+ .setUserRoleName(reqPostPreExecute.getUserRoleName())
+ .setAdminRoleName(reqPostPreExecute.getAdminRoleName())
+ .setForceCreationWhenVolumeExists(false)).build();
+ OMTenantCreateRequest modTenantCreateRequest =
+ new OMTenantCreateRequest(modReqPostPreExecute);
+ // OMResponse should have status VOLUME_ALREADY_EXISTS in this crafted case
+ OMClientResponse modOMClientResponse =
+ modTenantCreateRequest.validateAndUpdateCache(ozoneManager, 2L,
+ ozoneManagerDoubleBufferHelper);
+ Assert.assertEquals(Status.VOLUME_ALREADY_EXISTS,
+ modOMClientResponse.getOMResponse().getStatus());
+ Assert.assertEquals("Volume already exists",
+ modOMClientResponse.getOMResponse().getMessage());
+
+ // validateAndUpdateCache with forceCreationWhenVolumeExists = true
+ OMClientResponse omClientResponse =
+ omTenantCreateRequest2.validateAndUpdateCache(ozoneManager, 2L,
+ ozoneManagerDoubleBufferHelper);
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ Assert.assertNotNull(omResponse.getCreateTenantResponse());
+ Assert.assertEquals(Status.OK, omResponse.getStatus());
+ Assert.assertNotNull(omMetadataManager.getVolumeTable().get(
+ omMetadataManager.getVolumeKey(tenantId)));
+ }
@Test
public void
@@ -140,7 +239,7 @@ public class TestOMTenantCreateRequest {
private void acceptTenantIdCreationHelper(String tenantId)
throws Exception {
OMRequest originalRequest =
- OMRequestTestUtils.createTenantRequest(tenantId);
+ OMRequestTestUtils.createTenantRequest(tenantId, false);
OMTenantCreateRequest omTenantCreateRequest =
Mockito.spy(new OMTenantCreateRequest(originalRequest));
Mockito.doReturn("username").when(omTenantCreateRequest).getUserName();
@@ -151,12 +250,10 @@ public class TestOMTenantCreateRequest {
OMClientResponse omClientResponse =
omTenantCreateRequest.validateAndUpdateCache(ozoneManager, txLogIndex,
ozoneManagerDoubleBufferHelper);
- OzoneManagerProtocolProtos.OMResponse omResponse =
- omClientResponse.getOMResponse();
+ OMResponse omResponse = omClientResponse.getOMResponse();
Assert.assertNotNull(omResponse.getCreateTenantResponse());
- Assert.assertEquals(OzoneManagerProtocolProtos.Status.OK,
- omResponse.getStatus());
+ Assert.assertEquals(Status.OK, omResponse.getStatus());
Assert.assertNotNull(omMetadataManager.getVolumeTable().get(
omMetadataManager.getVolumeKey(tenantId)));
}
@@ -171,7 +268,7 @@ public class TestOMTenantCreateRequest {
private void doPreExecute(String tenantId) throws Exception {
OMRequest originalRequest =
- OMRequestTestUtils.createTenantRequest(tenantId);
+ OMRequestTestUtils.createTenantRequest(tenantId, false);
OMTenantCreateRequest omTenantCreateRequest =
Mockito.spy(new OMTenantCreateRequest(originalRequest));
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
index 1be049ef78..c1fd0f3069 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
@@ -971,12 +971,14 @@ public final class OMRequestTestUtils {
.setClientId(UUID.randomUUID().toString()).build();
}
- public static OMRequest createTenantRequest(String tenantId) {
+ public static OMRequest createTenantRequest(String tenantId,
+ boolean forceCreationWhenVolumeExists) {
final CreateTenantRequest.Builder requestBuilder =
CreateTenantRequest.newBuilder()
.setTenantId(tenantId)
- .setVolumeName(tenantId);
+ .setVolumeName(tenantId)
+ .setForceCreationWhenVolumeExists(forceCreationWhenVolumeExists);
return OMRequest.newBuilder()
.setCreateTenantRequest(requestBuilder)
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantCreateHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantCreateHandler.java
index 0789124412..fd6c410960 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantCreateHandler.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantCreateHandler.java
@@ -21,6 +21,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.TenantArgs;
import org.apache.hadoop.ozone.shell.OzoneAddress;
import picocli.CommandLine;
@@ -37,11 +38,23 @@ public class TenantCreateHandler extends TenantHandler {
@CommandLine.Parameters(description = "Tenant name", arity = "1..1")
private String tenantId;
+ @CommandLine.Option(names = {"-f", "--force"},
+ description = "(Optional) Force tenant creation even when volume exists.
"
+ + "This does NOT override other errors like Ranger failure.",
+ hidden = true)
+ // This option is intentionally hidden to avoid abuse.
+ private boolean forceCreationWhenVolumeExists;
+
@Override
protected void execute(OzoneClient client, OzoneAddress address)
throws IOException {
- client.getObjectStore().createTenant(tenantId);
+ final TenantArgs tenantArgs = TenantArgs.newBuilder()
+ .setVolumeName(tenantId)
+ .setForceCreationWhenVolumeExists(forceCreationWhenVolumeExists)
+ .build();
+
+ client.getObjectStore().createTenant(tenantId, tenantArgs);
// RpcClient#createTenant prints INFO level log of tenant and volume name
if (isVerbose()) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]