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

siyao pushed a commit to branch HDDS-4944
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/HDDS-4944 by this push:
     new 83a8c5f  HDDS-6084. [Multi-Tenant] Handle upgrades to version 
supporting S3 multi-tenancy (#3018)
83a8c5f is described below

commit 83a8c5f14b28b03d7f852bbde1dd34610b4c67a0
Author: Siyao Meng <[email protected]>
AuthorDate: Thu Feb 10 15:16:23 2022 -0800

    HDDS-6084. [Multi-Tenant] Handle upgrades to version supporting S3 
multi-tenancy (#3018)
---
 hadoop-ozone/dist/src/main/compose/testlib.sh      |  12 +-
 .../main/compose/upgrade/compose/ha/docker-config  |   4 +-
 .../non-rolling-upgrade/1.1.0-1.2.0/callback.sh    |   3 +-
 .../dist/src/main/smoketest/upgrade/finalize.robot |   2 +-
 .../dist/src/main/smoketest/upgrade/generate.robot |  28 ++++-
 .../dist/src/main/smoketest/upgrade/prepare.robot  |   2 +-
 .../dist/src/main/smoketest/upgrade/validate.robot |  22 ++++
 .../hadoop/hdds/upgrade/TestHDDSUpgrade.java       |   9 +-
 .../om/multitenant/TestMultiTenantVolume.java      | 132 ++++++++++++++++++---
 .../s3/tenant/OMAssignUserToTenantRequest.java     |   3 +
 .../s3/tenant/OMTenantAssignAdminRequest.java      |   3 +
 .../request/s3/tenant/OMTenantCreateRequest.java   |   3 +
 .../request/s3/tenant/OMTenantDeleteRequest.java   |   3 +
 .../s3/tenant/OMTenantRevokeAdminRequest.java      |   3 +
 .../tenant/OMTenantRevokeUserAccessIdRequest.java  |   3 +
 .../om/upgrade/DisallowedUntilLayoutVersion.java   |   2 +-
 .../hadoop/ozone/om/upgrade/OMLayoutFeature.java   |   4 +-
 .../ozone/om/upgrade/OMLayoutFeatureAspect.java    |  17 ++-
 .../protocolPB/OzoneManagerRequestHandler.java     |   5 +
 .../src/main/resources/META-INF/aop.xml            |  24 ++++
 .../s3/security/TestS3GetSecretRequest.java        |   5 +
 .../om/upgrade/TestOMLayoutFeatureAspect.java      |   1 +
 22 files changed, 252 insertions(+), 38 deletions(-)

diff --git a/hadoop-ozone/dist/src/main/compose/testlib.sh 
b/hadoop-ozone/dist/src/main/compose/testlib.sh
index 9c3d6c4..d7604f3 100755
--- a/hadoop-ozone/dist/src/main/compose/testlib.sh
+++ b/hadoop-ozone/dist/src/main/compose/testlib.sh
@@ -147,8 +147,8 @@ start_docker_env(){
   create_results_dir
   export OZONE_SAFEMODE_MIN_DATANODES="${datanode_count}"
 
-  docker-compose --no-ansi down
-  if ! { docker-compose --no-ansi up -d --scale datanode="${datanode_count}" \
+  docker-compose --ansi never down
+  if ! { docker-compose --ansi never up -d --scale 
datanode="${datanode_count}" \
       && wait_for_safemode_exit \
       && wait_for_om_leader ; }; then
     [[ -n "$OUTPUT_NAME" ]] || OUTPUT_NAME="$COMPOSE_ENV_NAME"
@@ -235,7 +235,7 @@ execute_command_in_container(){
 ## @param       List of container names, eg datanode_1 datanode_2
 stop_containers() {
   set -e
-  docker-compose --no-ansi stop $@
+  docker-compose --ansi never stop $@
   set +e
 }
 
@@ -244,7 +244,7 @@ stop_containers() {
 ## @param       List of container names, eg datanode_1 datanode_2
 start_containers() {
   set -e
-  docker-compose --no-ansi start $@
+  docker-compose --ansi never start $@
   set +e
 }
 
@@ -280,9 +280,9 @@ wait_for_port(){
 
 ## @description  Stops a docker-compose based test environment (with saving 
the logs)
 stop_docker_env(){
-  docker-compose --no-ansi logs > "$RESULT_DIR/docker-$OUTPUT_NAME.log"
+  docker-compose --ansi never logs > "$RESULT_DIR/docker-$OUTPUT_NAME.log"
   if [ "${KEEP_RUNNING:-false}" = false ]; then
-     docker-compose --no-ansi down
+     docker-compose --ansi never down
   fi
 }
 
diff --git 
a/hadoop-ozone/dist/src/main/compose/upgrade/compose/ha/docker-config 
b/hadoop-ozone/dist/src/main/compose/upgrade/compose/ha/docker-config
index 9a2b700..8e01004 100644
--- a/hadoop-ozone/dist/src/main/compose/upgrade/compose/ha/docker-config
+++ b/hadoop-ozone/dist/src/main/compose/upgrade/compose/ha/docker-config
@@ -24,8 +24,8 @@ OZONE-SITE.XML_ozone.om.address.omservice.om1=om1
 OZONE-SITE.XML_ozone.om.address.omservice.om2=om2
 OZONE-SITE.XML_ozone.om.address.omservice.om3=om3
 OZONE-SITE.XML_ozone.om.ratis.enable=true
-// setting ozone.scm.ratis.enable to false for now, as scm ha upgrade is
-// not supported yet. This is supposed to work without SCM HA configuration
+# setting ozone.scm.ratis.enable to false for now, as scm ha upgrade is
+# not supported yet. This is supposed to work without SCM HA configuration
 OZONE-SITE.XML_ozone.scm.ratis.enable=false
 OZONE-SITE.XML_ozone.scm.pipeline.creation.interval=30s
 OZONE-SITE.XML_ozone.scm.pipeline.owner.container.count=1
diff --git 
a/hadoop-ozone/dist/src/main/compose/upgrade/upgrades/non-rolling-upgrade/1.1.0-1.2.0/callback.sh
 
b/hadoop-ozone/dist/src/main/compose/upgrade/upgrades/non-rolling-upgrade/1.1.0-1.2.0/callback.sh
index b533e6c..96528bb 100755
--- 
a/hadoop-ozone/dist/src/main/compose/upgrade/upgrades/non-rolling-upgrade/1.1.0-1.2.0/callback.sh
+++ 
b/hadoop-ozone/dist/src/main/compose/upgrade/upgrades/non-rolling-upgrade/1.1.0-1.2.0/callback.sh
@@ -64,8 +64,7 @@ with_old_version_downgraded() {
 
 with_new_version_finalized() {
   _check_hdds_mlvs 2
-  # OM currently only has one layout version.
-  _check_om_mlvs 0
+  _check_om_mlvs 1
 
   validate old1
   validate new1
diff --git a/hadoop-ozone/dist/src/main/smoketest/upgrade/finalize.robot 
b/hadoop-ozone/dist/src/main/smoketest/upgrade/finalize.robot
index 288f9c0..b70f3ca 100644
--- a/hadoop-ozone/dist/src/main/smoketest/upgrade/finalize.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/upgrade/finalize.robot
@@ -19,7 +19,7 @@ Resource            ../commonlib.robot
 Test Timeout        5 minutes
 Test Setup          Run Keyword if    '${SECURITY_ENABLED}' == 'true'    Kinit 
test user     testuser     testuser.keytab
 
-** Test Cases ***
+*** Test Cases ***
 Finalize SCM
     ${result} =        Execute      ozone admin scm finalizeupgrade
                        #Wait Until Keyword Succeeds      3min       10sec     
Should contain   ${result}   OM Preparation successful!
diff --git a/hadoop-ozone/dist/src/main/smoketest/upgrade/generate.robot 
b/hadoop-ozone/dist/src/main/smoketest/upgrade/generate.robot
index 0a14604..7493c65 100644
--- a/hadoop-ozone/dist/src/main/smoketest/upgrade/generate.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/upgrade/generate.robot
@@ -18,6 +18,7 @@ Documentation       Generate data
 Library             OperatingSystem
 Library             BuiltIn
 Resource            ../commonlib.robot
+Resource            ../s3/commonawslib.robot
 Test Timeout        5 minutes
 
 *** Variables ***
@@ -29,5 +30,30 @@ Create a volume, bucket and key
                         Should not contain  ${output}       Failed
     ${output} =         Execute          ozone sh bucket create 
/${PREFIX}-volume/${PREFIX}-bucket
                         Should not contain  ${output}       Failed
-    ${output} =         Execute          ozone sh key put 
/${PREFIX}-volume/${PREFIX}-bucket/${PREFIX}-key /opt/hadoop/NOTICE.txt
+                        Execute and checkrc    echo "${PREFIX}: key created 
using Ozone Shell" > /tmp/sourcekey    0
+    ${output} =         Execute          ozone sh key put 
/${PREFIX}-volume/${PREFIX}-bucket/${PREFIX}-key /tmp/sourcekey
                         Should not contain  ${output}       Failed
+                        Execute and checkrc    rm /tmp/sourcekey    0
+
+Create a bucket and key in volume s3v
+    ${output} =         Execute          ozone sh bucket create 
/s3v/${PREFIX}-bucket
+                        Should not contain  ${output}       Failed
+                        Execute and checkrc    echo "${PREFIX}: another key 
created using Ozone Shell" > /tmp/sourcekey    0
+    ${output} =         Execute          ozone sh key put 
/s3v/${PREFIX}-bucket/key1-shell /tmp/sourcekey
+                        Should not contain  ${output}       Failed
+                        Execute and checkrc    rm /tmp/sourcekey    0
+
+Setup credentials for S3
+    # TODO: Run "Setup secure v4 headers" instead when security is enabled
+    Run Keyword         Setup dummy credentials for S3
+
+Try to create a bucket using S3 API
+    # Note: S3 API does not return error if the bucket already exists
+    ${output} =         Create bucket with name    ${PREFIX}-bucket
+                        Should Be Equal    ${output}    ${None}
+
+Create key using S3 API
+                        Execute and checkrc    echo "${PREFIX}: key created 
using S3 API" > /tmp/sourcekey    0
+    ${output} =         Execute AWSS3APICli and checkrc    put-object --bucket 
${PREFIX}-bucket --key key2-s3api --body /tmp/sourcekey    0
+                        Should not contain    ${output}    error
+                        Execute and checkrc    rm /tmp/sourcekey    0
diff --git a/hadoop-ozone/dist/src/main/smoketest/upgrade/prepare.robot 
b/hadoop-ozone/dist/src/main/smoketest/upgrade/prepare.robot
index 0f6d7a0..b1b4095 100644
--- a/hadoop-ozone/dist/src/main/smoketest/upgrade/prepare.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/upgrade/prepare.robot
@@ -19,7 +19,7 @@ Resource            ../commonlib.robot
 Test Timeout        5 minutes
 Test Setup          Run Keyword if    '${SECURITY_ENABLED}' == 'true'    Kinit 
test user     testuser     testuser.keytab
 
-** Test Cases ***
+*** Test Cases ***
 Prepare Ozone Manager
     ${result} =        Execute      ozone admin om prepare -id %{OM_SERVICE_ID}
                        Wait Until Keyword Succeeds      3min       10sec     
Should contain   ${result}   OM Preparation successful!
diff --git a/hadoop-ozone/dist/src/main/smoketest/upgrade/validate.robot 
b/hadoop-ozone/dist/src/main/smoketest/upgrade/validate.robot
index 4461ddf..9f5b0a0 100644
--- a/hadoop-ozone/dist/src/main/smoketest/upgrade/validate.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/upgrade/validate.robot
@@ -18,6 +18,7 @@ Documentation       Smoketest ozone cluster startup
 Library             OperatingSystem
 Library             BuiltIn
 Resource            ../commonlib.robot
+Resource            ../s3/commonawslib.robot
 Test Timeout        5 minutes
 
 *** Variables ***
@@ -28,3 +29,24 @@ Read data from previously created key
     ${random} =         Generate Random String  5  [NUMBERS]
     ${output} =         Execute          ozone sh key get 
/${PREFIX}-volume/${PREFIX}-bucket/${PREFIX}-key /tmp/key-${random}
                         Should not contain  ${output}       Failed
+    ${output} =         Execute and checkrc    cat /tmp/key-${random}    0
+                        Should contain    ${output}    ${PREFIX}: key created 
using Ozone Shell
+                        Execute and checkrc    rm /tmp/key-${random}    0
+
+Setup credentials for S3
+    # TODO: Run "Setup secure v4 headers" instead when security is enabled
+    Run Keyword         Setup dummy credentials for S3
+
+Read key created with Ozone Shell using S3 API
+    ${output} =         Execute AWSS3APICli and checkrc    get-object --bucket 
${PREFIX}-bucket --key key1-shell /tmp/get-result    0
+                        Should contain    ${output}    "ContentLength"
+    ${output} =         Execute and checkrc    cat /tmp/get-result    0
+                        Should contain    ${output}    ${PREFIX}: another key 
created using Ozone Shell
+                        Execute and checkrc    rm /tmp/get-result    0
+
+Read key created with S3 API using S3 API
+    ${output} =         Execute AWSS3APICli and checkrc    get-object --bucket 
${PREFIX}-bucket --key key2-s3api /tmp/get-result    0
+                        Should contain    ${output}    "ContentLength"
+    ${output} =         Execute and checkrc    cat /tmp/get-result    0
+                        Should contain    ${output}    ${PREFIX}: key created 
using S3 API
+                        Execute and checkrc    rm /tmp/get-result    0
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/upgrade/TestHDDSUpgrade.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/upgrade/TestHDDSUpgrade.java
index e7f6f34..6f356ac 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/upgrade/TestHDDSUpgrade.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/upgrade/TestHDDSUpgrade.java
@@ -28,7 +28,6 @@ import static 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeState.HEALTHY
 import static 
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_DATANODE_PIPELINE_LIMIT;
 import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_HA_ENABLE_KEY;
 import static org.apache.hadoop.hdds.scm.pipeline.Pipeline.PipelineState.OPEN;
-import static org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.INITIAL_VERSION;
 import static 
org.apache.hadoop.ozone.upgrade.InjectedUpgradeFinalizationExecutor.UpgradeTestInjectionPoints.AFTER_COMPLETE_FINALIZATION;
 import static 
org.apache.hadoop.ozone.upgrade.InjectedUpgradeFinalizationExecutor.UpgradeTestInjectionPoints.AFTER_POST_FINALIZE_UPGRADE;
 import static 
org.apache.hadoop.ozone.upgrade.InjectedUpgradeFinalizationExecutor.UpgradeTestInjectionPoints.AFTER_PRE_FINALIZE_UPGRADE;
@@ -78,6 +77,7 @@ import org.apache.hadoop.ozone.client.OzoneClientFactory;
 import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
 import org.apache.hadoop.ozone.container.common.interfaces.Container;
 import 
org.apache.hadoop.ozone.container.common.statemachine.DatanodeStateMachine;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
 import org.apache.hadoop.ozone.upgrade.BasicUpgradeFinalizer;
 import org.apache.hadoop.ozone.upgrade.InjectedUpgradeFinalizationExecutor;
 import 
org.apache.hadoop.ozone.upgrade.InjectedUpgradeFinalizationExecutor.UpgradeTestInjectionPoints;
@@ -155,8 +155,9 @@ public class TestHDDSUpgrade {
         .setTotalPipelineNumLimit(NUM_DATA_NODES + 1)
         .setHbInterval(500)
         .setHbProcessorInterval(500)
-        .setScmLayoutVersion(INITIAL_VERSION.layoutVersion())
-        .setDnLayoutVersion(INITIAL_VERSION.layoutVersion());
+        .setOmLayoutVersion(OMLayoutFeature.INITIAL_VERSION.layoutVersion())
+        .setScmLayoutVersion(HDDSLayoutFeature.INITIAL_VERSION.layoutVersion())
+        .setDnLayoutVersion(HDDSLayoutFeature.INITIAL_VERSION.layoutVersion());
 
     // Setting the provider to a max of 100 clusters. Some of the tests here
     // use multiple clusters, so its hard to know exactly how many will be
@@ -219,7 +220,7 @@ public class TestHDDSUpgrade {
    * Helper function to test Pre-Upgrade conditions on the SCM
    */
   private void testPreUpgradeConditionsSCM() {
-    Assert.assertEquals(INITIAL_VERSION.layoutVersion(),
+    Assert.assertEquals(HDDSLayoutFeature.INITIAL_VERSION.layoutVersion(),
         scmVersionManager.getMetadataLayoutVersion());
     for (ContainerInfo ci : scmContainerManager.getContainers()) {
       Assert.assertEquals(HddsProtos.LifeCycleState.OPEN, ci.getState());
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
index ee2d9ab..0bb1d58 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
@@ -26,13 +26,25 @@ import org.apache.hadoop.ozone.client.OzoneVolume;
 import org.apache.hadoop.ozone.client.rpc.RpcClient;
 import org.apache.hadoop.ozone.om.OMMultiTenantManagerImpl;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
+import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
 import org.apache.hadoop.ozone.om.protocol.S3Auth;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
+import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer;
+import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ozone.test.LambdaTestUtils;
+import org.apache.ozone.test.LambdaTestUtils.VoidCallable;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+
+import static 
org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isDone;
+import static 
org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isStarting;
 
 /**
  * Tests that S3 requests for a tenant are directed to that tenant's volume,
@@ -43,15 +55,24 @@ public class TestMultiTenantVolume {
   private static MiniOzoneCluster cluster;
   private static String s3VolumeName;
 
+  private static final String TENANT_NAME = "tenant";
+  private static final String USER_PRINCIPAL = "username";
+  private static final String BUCKET_NAME = "bucket";
+  private static final String ACCESS_ID = UUID.randomUUID().toString();
+
   @BeforeClass
   public static void initClusterProvider() throws Exception {
     OzoneConfiguration conf = new OzoneConfiguration();
     conf.setBoolean(
         OMMultiTenantManagerImpl.OZONE_OM_TENANT_DEV_SKIP_RANGER, true);
     MiniOzoneCluster.Builder builder = MiniOzoneCluster.newBuilder(conf)
-        .withoutDatanodes();
+        .withoutDatanodes()
+        .setOmLayoutVersion(OMLayoutFeature.INITIAL_VERSION.layoutVersion());
     cluster = builder.build();
     s3VolumeName = HddsClientUtils.getDefaultS3VolumeName(conf);
+
+    preFinalizationChecks(getStoreForAccessID(ACCESS_ID));
+    finalizeOMUpgrade();
   }
 
   @AfterClass
@@ -59,6 +80,82 @@ public class TestMultiTenantVolume {
     cluster.shutdown();
   }
 
+  private static void expectFailurePreFinalization(VoidCallable eval)
+      throws Exception {
+    LambdaTestUtils.intercept(OMException.class,
+        "cannot be invoked before finalization", eval);
+  }
+
+  /**
+   * Perform sanity checks before triggering upgrade finalization.
+   */
+  private static void preFinalizationChecks(ObjectStore store)
+      throws Exception {
+
+    // None of the tenant APIs is usable before the upgrade finalization step
+    expectFailurePreFinalization(
+        store::listTenant);
+    expectFailurePreFinalization(() ->
+        store.listUsersInTenant(TENANT_NAME, ""));
+    expectFailurePreFinalization(() ->
+        store.tenantGetUserInfo(USER_PRINCIPAL));
+    expectFailurePreFinalization(() ->
+        store.createTenant(TENANT_NAME));
+    expectFailurePreFinalization(() ->
+        store.tenantAssignUserAccessId(USER_PRINCIPAL, TENANT_NAME, 
ACCESS_ID));
+    expectFailurePreFinalization(() ->
+        store.tenantAssignAdmin(USER_PRINCIPAL, TENANT_NAME, true));
+    expectFailurePreFinalization(() ->
+        store.tenantRevokeAdmin(ACCESS_ID, TENANT_NAME));
+    expectFailurePreFinalization(() ->
+        store.tenantRevokeUserAccessId(ACCESS_ID));
+    expectFailurePreFinalization(() ->
+        store.deleteTenant(TENANT_NAME));
+
+    // S3 get/set/revoke secret APIs still work before finalization
+    final String accessId = "testUser1accessId1";
+    S3SecretValue s3SecretValue = store.getS3Secret(accessId);
+    Assert.assertEquals(accessId, s3SecretValue.getAwsAccessKey());
+    final String setSecret = "testsecret";
+    s3SecretValue = store.setS3Secret(accessId, setSecret);
+    Assert.assertEquals(accessId, s3SecretValue.getAwsAccessKey());
+    Assert.assertEquals(setSecret, s3SecretValue.getAwsSecret());
+    store.revokeS3Secret(accessId);
+  }
+
+  /**
+   * Trigger OM upgrade finalization from the client and block until completion
+   * (status FINALIZATION_DONE).
+   */
+  private static void finalizeOMUpgrade()
+      throws IOException, InterruptedException, TimeoutException {
+
+    // Trigger OM upgrade finalization. Ref: FinalizeUpgradeSubCommand#call
+    final OzoneManagerProtocol client = cluster.getRpcClient().getObjectStore()
+        .getClientProxy().getOzoneManagerClient();
+    final String upgradeClientID = "Test-Upgrade-Client-" + UUID.randomUUID();
+    UpgradeFinalizer.StatusAndMessages finalizationResponse =
+        client.finalizeUpgrade(upgradeClientID);
+
+    // The status should transition as soon as the client call above returns
+    Assert.assertTrue(isStarting(finalizationResponse.status()));
+
+    // Wait for the finalization to be marked as done.
+    // 10s timeout should be plenty.
+    GenericTestUtils.waitFor(() -> {
+      try {
+        final UpgradeFinalizer.StatusAndMessages progress =
+            client.queryUpgradeFinalizationProgress(
+                upgradeClientID, false, false);
+        return isDone(progress.status());
+      } catch (IOException e) {
+        Assert.fail("Unexpected exception while waiting for "
+            + "the OM upgrade to finalize: " + e.getMessage());
+      }
+      return false;
+    }, 500, 10000);
+  }
+
   @Test
   public void testDefaultS3Volume() throws Exception {
     final String bucketName = "bucket";
@@ -79,31 +176,31 @@ public class TestMultiTenantVolume {
 
   @Test
   public void testS3TenantVolume() throws Exception {
-    final String tenant = "tenant";
-    final String principal = "username";
-    final String bucketName = "bucket";
-    final String accessID = UUID.randomUUID().toString();
 
-    ObjectStore store = getStoreForAccessID(accessID);
-    store.createTenant(tenant);
-    store.tenantAssignUserAccessId(principal, tenant, accessID);
+    ObjectStore store = getStoreForAccessID(ACCESS_ID);
+
+    store.createTenant(TENANT_NAME);
+    store.tenantAssignUserAccessId(USER_PRINCIPAL, TENANT_NAME, ACCESS_ID);
 
     // S3 volume pointed to by the store should be for the tenant.
-    Assert.assertEquals(tenant, store.getS3Volume().getName());
+    Assert.assertEquals(TENANT_NAME, store.getS3Volume().getName());
 
     // Create bucket in the tenant volume.
-    store.createS3Bucket(bucketName);
-    OzoneBucket bucket = store.getS3Bucket(bucketName);
-    Assert.assertEquals(tenant, bucket.getVolumeName());
+    store.createS3Bucket(BUCKET_NAME);
+    OzoneBucket bucket = store.getS3Bucket(BUCKET_NAME);
+    Assert.assertEquals(TENANT_NAME, bucket.getVolumeName());
 
     // A different user should not see bucket, since they will be directed to
     // the s3 volume.
     ObjectStore store2 = getStoreForAccessID(UUID.randomUUID().toString());
-    assertS3BucketNotFound(store2, bucketName);
+    assertS3BucketNotFound(store2, BUCKET_NAME);
 
     // Delete bucket.
-    store.deleteS3Bucket(bucketName);
-    assertS3BucketNotFound(store, bucketName);
+    store.deleteS3Bucket(BUCKET_NAME);
+    assertS3BucketNotFound(store, BUCKET_NAME);
+
+    store.tenantRevokeUserAccessId(ACCESS_ID);
+    store.deleteTenant(TENANT_NAME);
   }
 
   /**
@@ -112,7 +209,7 @@ public class TestMultiTenantVolume {
    * by the ObjectStore.
    */
   private void assertS3BucketNotFound(ObjectStore store, String bucketName)
-      throws Exception {
+      throws IOException {
     try {
       store.getS3Bucket(bucketName);
     } catch(OMException ex) {
@@ -131,7 +228,8 @@ public class TestMultiTenantVolume {
     }
   }
 
-  private ObjectStore getStoreForAccessID(String accessID) throws Exception {
+  private static ObjectStore getStoreForAccessID(String accessID)
+      throws IOException {
     // Cluster provider will modify our provided configuration. We must use
     // this version to build the client.
     OzoneConfiguration conf = cluster.getOzoneManager().getConfiguration();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
index 8d796e1..6e686ca 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
@@ -37,6 +37,7 @@ 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.s3.tenant.OMTenantAssignUserAccessIdResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 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.S3Secret;
@@ -58,6 +59,7 @@ import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.S3_SECRE
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
 import static 
org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantRequestHelper.checkTenantAdmin;
 import static 
org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantRequestHelper.checkTenantExistence;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /*
   Ratis execution flow for OMAssignUserToTenant request:
@@ -112,6 +114,7 @@ public class OMAssignUserToTenantRequest extends 
OMClientRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     final TenantAssignUserAccessIdRequest request =
         getOmRequest().getTenantAssignUserAccessIdRequest();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
index 4c021d2..d3fb708 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
@@ -34,6 +34,7 @@ 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.s3.tenant.OMTenantAssignAdminResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignAdminRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignAdminResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
@@ -46,6 +47,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /*
   Execution flow
@@ -68,6 +70,7 @@ public class OMTenantAssignAdminRequest extends 
OMClientRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     final TenantAssignAdminRequest request =
         getOmRequest().getTenantAssignAdminRequest();
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 1d4777f..73da4ee 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
@@ -38,6 +38,7 @@ import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
 import org.apache.hadoop.ozone.om.request.volume.OMVolumeRequest;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.response.s3.tenant.OMTenantCreateResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateVolumeRequest;
@@ -61,6 +62,7 @@ import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENA
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_ALREADY_EXISTS;
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.USER_LOCK;
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /*
   Ratis execution flow for OMTenantCreate
@@ -110,6 +112,7 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
 
     // Check Ozone cluster admin privilege
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
index ff88449..f9931cc 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
@@ -34,6 +34,7 @@ import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
 import org.apache.hadoop.ozone.om.request.volume.OMVolumeRequest;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.response.s3.tenant.OMTenantDeleteResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
@@ -50,6 +51,7 @@ import java.util.Map;
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_NOT_EMPTY;
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_NOT_FOUND;
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /**
  * Handles OMTenantDelete request.
@@ -63,6 +65,7 @@ public class OMTenantDeleteRequest extends OMVolumeRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
 
     // Check Ozone cluster admin privilege
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
index 0987ab0..0f4a2d5 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
@@ -34,6 +34,7 @@ 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.s3.tenant.OMTenantRevokeAdminResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 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.TenantRevokeAdminRequest;
@@ -46,6 +47,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /*
   Execution flow
@@ -68,6 +70,7 @@ public class OMTenantRevokeAdminRequest extends 
OMClientRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     final TenantRevokeAdminRequest request =
         getOmRequest().getTenantRevokeAdminRequest();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
index c9436fb..7b52cd2 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
@@ -34,6 +34,7 @@ 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.s3.tenant.OMTenantRevokeUserAccessIdResponse;
+import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantRevokeUserAccessIdRequest;
@@ -47,6 +48,7 @@ import java.util.Map;
 
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.S3_SECRET_LOCK;
 import static 
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 
 /*
   Execution flow
@@ -73,6 +75,7 @@ public class OMTenantRevokeUserAccessIdRequest extends 
OMClientRequest {
   }
 
   @Override
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     final TenantRevokeUserAccessIdRequest request =
         getOmRequest().getTenantRevokeUserAccessIdRequest();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/DisallowedUntilLayoutVersion.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/DisallowedUntilLayoutVersion.java
index c437c1d..ef44d47 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/DisallowedUntilLayoutVersion.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/DisallowedUntilLayoutVersion.java
@@ -28,7 +28,7 @@ import java.lang.annotation.Target;
  * not include the associated layout feature. Helps to keep the method logic
  * and upgrade related cross cutting concern separate.
  */
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface DisallowedUntilLayoutVersion {
   OMLayoutFeature value();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeature.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeature.java
index 5338c16..a57d540 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeature.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeature.java
@@ -29,8 +29,8 @@ import org.apache.hadoop.ozone.upgrade.LayoutFeature;
  */
 public enum OMLayoutFeature implements LayoutFeature {
   //////////////////////////////  //////////////////////////////
-  INITIAL_VERSION(0, "Initial Layout Version");
-
+  INITIAL_VERSION(0, "Initial Layout Version"),
+  MULTITENANCY_SCHEMA(1, "Multi-Tenancy Schema");
 
   ///////////////////////////////  /////////////////////////////
   //    Example OM Layout Feature with Actions
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeatureAspect.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeatureAspect.java
index a6fe773..3688718 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeatureAspect.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMLayoutFeatureAspect.java
@@ -25,6 +25,7 @@ import java.lang.reflect.Method;
 
 import org.apache.hadoop.ozone.om.OzoneManager;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
 import org.apache.hadoop.ozone.protocolPB.OzoneManagerRequestHandler;
 import org.apache.hadoop.ozone.upgrade.LayoutFeature;
 import org.apache.hadoop.ozone.upgrade.LayoutVersionManager;
@@ -54,11 +55,17 @@ public class OMLayoutFeatureAspect {
     String featureName = ((MethodSignature) joinPoint.getSignature())
         .getMethod().getAnnotation(DisallowedUntilLayoutVersion.class)
         .value().name();
-    LayoutVersionManager lvm = null;
+    LayoutVersionManager lvm;
+    final Object[] args = joinPoint.getArgs();
     if (joinPoint.getTarget() instanceof OzoneManagerRequestHandler) {
       OzoneManager ozoneManager = ((OzoneManagerRequestHandler)
           joinPoint.getTarget()).getOzoneManager();
       lvm = ozoneManager.getVersionManager();
+    } else if (joinPoint.getTarget() instanceof OMClientRequest &&
+        joinPoint.toShortString().endsWith(".preExecute(..))")) {
+      // Get OzoneManager instance from preExecute first argument
+      OzoneManager ozoneManager = (OzoneManager) args[0];
+      lvm = ozoneManager.getVersionManager();
     } else {
       try {
         Method method = joinPoint.getTarget().getClass()
@@ -111,4 +118,12 @@ public class OMLayoutFeatureAspect {
         om.getVersionManager(), lf.name());
   }
 
+  /**
+   * Note: Without this, it occasionally throws NoSuchMethodError when running
+   * the test.
+   */
+  public static OMLayoutFeatureAspect aspectOf() {
+    return new OMLayoutFeatureAspect();
+  }
+
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index 820686b..b6e5137 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -49,6 +49,7 @@ import 
org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
 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.upgrade.DisallowedUntilLayoutVersion;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CheckVolumeAccessRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CheckVolumeAccessResponse;
@@ -91,6 +92,7 @@ import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
 
 import com.google.common.collect.Lists;
 
+import static 
org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.MULTITENANCY_SCHEMA;
 import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesRequest;
 import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesResponse;
 import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetAclRequest;
@@ -372,6 +374,7 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
     return resp.build();
   }
 
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   private TenantGetUserInfoResponse tenantGetUserInfo(
       TenantGetUserInfoRequest request) throws IOException {
 
@@ -390,6 +393,7 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
     return resp.build();
   }
 
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   private TenantListUserResponse tenantListUsers(
       TenantListUserRequest request) throws IOException {
     TenantListUserResponse.Builder builder =
@@ -406,6 +410,7 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
     return builder.build();
   }
 
+  @DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
   private ListTenantResponse listTenant(
       ListTenantRequest request) throws IOException {
 
diff --git a/hadoop-ozone/ozone-manager/src/main/resources/META-INF/aop.xml 
b/hadoop-ozone/ozone-manager/src/main/resources/META-INF/aop.xml
new file mode 100644
index 0000000..f92d820
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/resources/META-INF/aop.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed 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. See accompanying LICENSE file.
+-->
+<aspectj>
+  <aspects>
+    <aspect name="org.apache.hadoop.ozone.om.upgrade.OMLayoutFeatureAspect"/>
+    <weaver options="-verbose -showWeaveInfo">
+      <!-- TODO: Auto generate this class list later. The list should include 
whatever class that calls methods with the DisallowedUntilLayoutVersion 
annotation -->
+      <include 
within="org.apache.hadoop.ozone.protocolPB.OzoneManagerRequestHandler"/>
+      <include 
within="org.apache.hadoop.ozone.protocolPB.OzoneManagerProtocolServerSideTranslatorPB"/>
+    </weaver>
+  </aspects>
+</aspectj>
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
index 3ebb14c..52803e2 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
@@ -41,6 +41,7 @@ import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.response.s3.security.S3GetSecretResponse;
 import 
org.apache.hadoop.ozone.om.response.s3.tenant.OMTenantAssignUserAccessIdResponse;
 import org.apache.hadoop.ozone.om.response.s3.tenant.OMTenantCreateResponse;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3SecretRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3SecretResponse;
@@ -328,6 +329,10 @@ public class TestS3GetSecretRequest {
 
     // This effectively makes alice an admin.
     when(ozoneManager.isAdmin(ugiAlice)).thenReturn(true);
+    // Init LayoutVersionManager to prevent NPE in checkLayoutFeature
+    final OMLayoutVersionManager lvm =
+        new OMLayoutVersionManager(OMLayoutVersionManager.maxLayoutVersion());
+    when(ozoneManager.getVersionManager()).thenReturn(lvm);
 
     // 1. CreateTenantRequest: Create tenant "finance".
     long txLogIndex = 1;
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOMLayoutFeatureAspect.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOMLayoutFeatureAspect.java
index 842cf87..dd60d5a 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOMLayoutFeatureAspect.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOMLayoutFeatureAspect.java
@@ -69,6 +69,7 @@ public class TestOMLayoutFeatureAspect {
     MethodSignature methodSignature = mock(MethodSignature.class);
     when(methodSignature.getMethod())
         .thenReturn(OMLayoutFeatureUtil.class.getMethod("ecMethod"));
+    when(methodSignature.toShortString()).thenReturn("ecMethod");
     when(joinPoint.getSignature()).thenReturn(methodSignature);
 
     LambdaTestUtils.intercept(OMException.class,

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

Reply via email to