You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ng...@apache.org on 2019/10/19 22:40:56 UTC

[hive] branch master updated: HIVE-22342: HMS Translation: Location for external tables too strict (Naveen Gangam, reviewed by Sam An)

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

ngangam pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new b4431f3  HIVE-22342: HMS Translation: Location for external tables too strict (Naveen Gangam, reviewed by Sam An)
b4431f3 is described below

commit b4431f33b153b4e21129c90cb942091a480981ff
Author: Naveen Gangam <ng...@apache.org>
AuthorDate: Sat Oct 19 18:40:39 2019 -0400

    HIVE-22342: HMS Translation: Location for external tables too strict (Naveen Gangam, reviewed by Sam An)
---
 .../metastore/TestHiveMetastoreTransformer.java    | 13 +++++---
 standalone-metastore/metastore-server/pom.xml      |  7 ++--
 .../metastore/MetastoreDefaultTransformer.java     | 38 ++++++++++++----------
 .../hive/metastore/client/TestAlterPartitions.java |  4 +--
 .../metastore/client/TestAppendPartitions.java     |  4 +--
 .../hive/metastore/client/TestDropPartitions.java  | 14 +++++---
 .../metastore/client/TestExchangePartitions.java   | 18 +++++-----
 .../minihms/AbstractMetaStoreService.java          | 10 ++++++
 standalone-metastore/pom.xml                       |  1 +
 9 files changed, 70 insertions(+), 39 deletions(-)

diff --git a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetastoreTransformer.java b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetastoreTransformer.java
index dd6a4ea..802ce4e 100644
--- a/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetastoreTransformer.java
+++ b/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetastoreTransformer.java
@@ -77,21 +77,23 @@ public class TestHiveMetastoreTransformer {
 
   protected static boolean isThriftClient = true;
   private static final String CAPABILITIES_KEY = "OBJCAPABILITIES";
+  private static final String DATABASE_WAREHOUSE_SUFFIX = ".db";
 
   @Before
   public void setUp() throws Exception {
     conf = MetastoreConf.newMetastoreConf();
     wh = new File(System.getProperty("java.io.tmpdir") + File.separator +
-        "hive" + File.separator + "warehouse" + File.separator + "managed" + File.separator);
+        "hive" + File.separator + "warehouse" + File.separator + "hive" + File.separator);
     wh.mkdirs();
 
     ext_wh = new File(System.getProperty("java.io.tmpdir") + File.separator +
-        "hive" + File.separator + "warehouse" + File.separator + "external" + File.separator);
+        "hive" + File.separator + "warehouse" + File.separator + "hive-external" + File.separator);
     ext_wh.mkdirs();
 
     MetastoreConf.setVar(conf, ConfVars.METASTORE_METADATA_TRANSFORMER_CLASS,
         "org.apache.hadoop.hive.metastore.MetastoreDefaultTransformer");
     MetastoreConf.setBoolVar(conf, ConfVars.HIVE_IN_TEST, false);
+    MetastoreConf.setVar(conf, ConfVars.WAREHOUSE, wh.getCanonicalPath());
     MetastoreConf.setVar(conf, ConfVars.WAREHOUSE_EXTERNAL, ext_wh.getCanonicalPath());
     client = new HiveMetaStoreClient(conf);
   }
@@ -1178,12 +1180,15 @@ public class TestHiveMetastoreTransformer {
       String tableLocation = tbl2.getSd().getLocation();
       int idx = (tableLocation.indexOf(":") > 0) ? tableLocation.indexOf(":") : 0;
       tableLocation = tableLocation.substring(idx+1);
+      String expectedPath = ext_wh.getAbsolutePath().concat(File.separator).concat(dbName).concat(DATABASE_WAREHOUSE_SUFFIX)
+          .concat(File.separator).concat(tblName);
+      assertEquals("Table location", expectedPath, tableLocation);
 
       String newLocation = wh.getAbsolutePath().concat(File.separator).concat(dbName).concat(File.separator)
           .concat(tblName);
-      table.getSd().setLocation(newLocation);
+      tbl2.getSd().setLocation(newLocation);
       try {
-        client.alter_table(dbName, tblName, table);
+        client.alter_table(dbName, tblName, tbl2);
         fail("alter_table expected to fail due to location:" + newLocation);
       } catch (Exception e) {
         e.printStackTrace();
diff --git a/standalone-metastore/metastore-server/pom.xml b/standalone-metastore/metastore-server/pom.xml
index 740b3ab..7645a98 100644
--- a/standalone-metastore/metastore-server/pom.xml
+++ b/standalone-metastore/metastore-server/pom.xml
@@ -350,6 +350,7 @@
               <metastore.schema.verification>false</metastore.schema.verification>
               <test.tmp.dir>${test.tmp.dir}</test.tmp.dir>
               <metastore.warehouse.dir>${test.warehouse.scheme}${test.warehouse.dir}</metastore.warehouse.dir>
+              <hive.metastore.warehouse.external.dir>${test.warehouse.scheme}${test.warehouse.external.dir}</hive.metastore.warehouse.external.dir>
             </systemPropertyVariables>
             <additionalClasspathElements>
               <additionalClasspathElement>${log4j.conf.dir}</additionalClasspathElement>
@@ -417,9 +418,11 @@
             <configuration>
               <target>
                 <delete dir="${test.tmp.dir}"/>
+                <delete dir="${test.warehouse.external.dir}" />
                 <delete dir="${test.warehouse.dir}"/>
                 <mkdir dir="${test.tmp.dir}"/>
                 <mkdir dir="${test.warehouse.dir}"/>
+                <mkdir dir="${test.warehouse.external.dir}" />
               </target>
             </configuration>
           </execution>
@@ -571,8 +574,8 @@
             </javax.jdo.option.ConnectionURL>
             <metastore.schema.verification>false</metastore.schema.verification>
             <test.tmp.dir>${test.tmp.dir}</test.tmp.dir>
-            <metastore.warehouse.dir>${test.warehouse.scheme}${test.warehouse.dir}
-            </metastore.warehouse.dir>
+            <metastore.warehouse.dir>${test.warehouse.scheme}${test.warehouse.dir}</metastore.warehouse.dir>
+            <hive.metastore.warehouse.external.dir>${test.warehouse.scheme}${test.warehouse.external.dir}</hive.metastore.warehouse.external.dir>
           </systemPropertyVariables>
           <additionalClasspathElements>
             <additionalClasspathElement>${log4j.conf.dir}</additionalClasspathElement>
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetastoreDefaultTransformer.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetastoreDefaultTransformer.java
index 9196d26..a4f588e 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetastoreDefaultTransformer.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetastoreDefaultTransformer.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.hive.metastore.api.MetaException;
 import org.apache.hadoop.hive.metastore.api.Partition;
 import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
 import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.utils.FileUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -573,7 +574,7 @@ public class MetastoreDefaultTransformer implements IMetaStoreMetadataTransforme
         params.remove(TABLE_IS_TRANSACTIONAL);
         params.remove(TABLE_TRANSACTIONAL_PROPERTIES);
         params.put("EXTERNAL", "TRUE");
-        params.put(EXTERNAL_TABLE_PURGE, "TRUE");
+        params.put(EXTERNAL_TABLE_PURGE, "true");
         params.put("TRANSLATED_TO_EXTERNAL", "TRUE");
         newTable.setParameters(params);
         LOG.info("Modified table params are:" + params.toString());
@@ -611,14 +612,16 @@ public class MetastoreDefaultTransformer implements IMetaStoreMetadataTransforme
     } else if (TableType.EXTERNAL_TABLE.name().equals(tableType)) {
       LOG.info("Table to be created is of type " + tableType + " but not " + TableType.MANAGED_TABLE.toString());
       String tableLocation = table.getSd().getLocation();
-      String externalWHRoot = hmsHandler.getWh().getWhRootExternal().toString();
+      Path whRootPath = Path.getPathWithoutSchemeAndAuthority(hmsHandler.getWh().getWhRoot());
 
-      if (tableLocation != null && !tableLocation.startsWith(externalWHRoot)) {
-        throw new MetaException(
-            "An external table's location needs to be under the external warehouse root directory," + "table:"
-                + table.getTableName() + ",location:" + tableLocation + ",Hive warehouse:" + externalWHRoot);
+      if (tableLocation != null) {
+        Path tablePath = Path.getPathWithoutSchemeAndAuthority(new Path(tableLocation));
+        if (FileUtils.isSubdirectory(whRootPath.toString(), tablePath.toString())) {
+          throw new MetaException(
+            "An external table's location should not be located within managed warehouse root directory," + "table:"
+                + table.getTableName() + ",location:" + tablePath + ",Hive managed warehouse:" + whRootPath);
+        }
       }
-
     }
     LOG.info("Transformer returning table:" + newTable.toString());
     return newTable;
@@ -634,25 +637,26 @@ public class MetastoreDefaultTransformer implements IMetaStoreMetadataTransforme
     LOG.info("Starting translation for Alter table for processor " + processorId + " with " + processorCapabilities
         + " on table " + table.getTableName());
     String tableType = table.getTableType();
+    Path tableLocation = null;
+    Path whRootPath = null;
 
     if (TableType.MANAGED_TABLE.name().equals(tableType)) {
       LOG.debug("Table is a MANAGED_TABLE");
-      Path tableLocation = Path.getPathWithoutSchemeAndAuthority(new Path(table.getSd().getLocation()));
-      Path whRootPath = Path.getPathWithoutSchemeAndAuthority(hmsHandler.getWh().getWhRoot());
-      if (!tableLocation.toString().startsWith(whRootPath.toString())) {
+      tableLocation = Path.getPathWithoutSchemeAndAuthority(new Path(table.getSd().getLocation()));
+      whRootPath = Path.getPathWithoutSchemeAndAuthority(hmsHandler.getWh().getWhRoot());
+      if (tableLocation != null && !FileUtils.isSubdirectory(whRootPath.toString(), tableLocation.toString())) {
         throw new MetaException(
             "A managed table's location needs to be under the hive warehouse root directory," + "table:"
                 + table.getTableName() + ",location:" + tableLocation + ",Hive warehouse:" + whRootPath);
       }
     } else if (TableType.EXTERNAL_TABLE.name().equals(tableType)) {
-      LOG.debug("Table is a EXTERNAL TABLE");
-      Path tableLocation = Path.getPathWithoutSchemeAndAuthority(new Path(table.getSd().getLocation()));
-      Path externalWHRootPath = Path.getPathWithoutSchemeAndAuthority(hmsHandler.getWh().getWhRootExternal());
-
-      if (tableLocation != null && !tableLocation.toString().startsWith(externalWHRootPath.toString())) {
+      tableLocation = Path.getPathWithoutSchemeAndAuthority(new Path(table.getSd().getLocation()));
+      whRootPath = Path.getPathWithoutSchemeAndAuthority(hmsHandler.getWh().getWhRoot());
+      LOG.debug("Table is a EXTERNAL TABLE:tableLocation=" + tableLocation.toString() + ",whroot=" + whRootPath.toString());
+      if (tableLocation != null && FileUtils.isSubdirectory(whRootPath.toString(), tableLocation.toString())) {
         throw new MetaException(
-            "An external table's location needs to be under the external warehouse root directory," + "table:"
-                + table.getTableName() + ",location:" + tableLocation + ",Hive external warehouse:" + externalWHRootPath);
+            "An external table's location should not be located within managed warehouse root directory," + "table:"
+                + table.getTableName() + ",location:" + tableLocation + ",Hive managed warehouse:" + whRootPath);
       }
     }
     LOG.debug("Transformer returning table:" + table.toString());
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAlterPartitions.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAlterPartitions.java
index 4de673e..c100b67 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAlterPartitions.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAlterPartitions.java
@@ -211,7 +211,7 @@ public class TestAlterPartitions extends MetaStoreClientTest {
       expectedKVPairs.add(partCols.get(i) + "=" + testValues.get(i));
     }
     String partPath = expectedKVPairs.stream().collect(joining("/"));
-    assertTrue(partition.getSd().getLocation().equals(metaStore.getWarehouseRoot()
+    assertTrue(partition.getSd().getLocation().equals(metaStore.getExternalWarehouseRoot()
         + "/testpartdb.db/testparttable/" + partPath));
     assertNotEquals(NEW_CREATE_TIME, partition.getCreateTime());
     assertNotEquals(NEW_CREATE_TIME, partition.getLastAccessTime());
@@ -227,7 +227,7 @@ public class TestAlterPartitions extends MetaStoreClientTest {
       expectedKVPairs.add(partCols.get(i) + "=" + testValues.get(i));
     }
     String partPath = expectedKVPairs.stream().collect(joining("/"));
-    assertTrue(partition.getSd().getLocation().equals(metaStore.getWarehouseRoot()
+    assertTrue(partition.getSd().getLocation().equals(metaStore.getExternalWarehouseRoot()
         + "/testpartdb.db/testparttable/" + partPath + "/hh=01"));
     assertEquals(NEW_CREATE_TIME, partition.getCreateTime());
     assertEquals(NEW_CREATE_TIME, partition.getLastAccessTime());
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAppendPartitions.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAppendPartitions.java
index 0df071f..e53720d 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAppendPartitions.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestAppendPartitions.java
@@ -559,7 +559,7 @@ public class TestAppendPartitions extends MetaStoreClientTest {
     tableParams.put("EXTERNAL", "TRUE");
     Table table = createTable("test_append_part_external_table", getYearAndMonthPartCols(),
         tableParams, TableType.EXTERNAL_TABLE.name(),
-        metaStore.getWarehouseRoot() + "/test_append_part_external_table");
+        metaStore.getExternalWarehouseRoot() + "/test_append_part_external_table");
     return table;
   }
 
@@ -615,7 +615,7 @@ public class TestAppendPartitions extends MetaStoreClientTest {
     Assert.assertEquals(expectedPartValues, partition.getValues());
     Assert.assertNotEquals(0, partition.getCreateTime());
     Assert.assertEquals(0, partition.getLastAccessTime());
-    Assert.assertEquals(1, partition.getParameters().size());
+    Assert.assertTrue("Expect atleast transient_lastDdlTime to be set in params", (partition.getParameters().size() > 0));
     Assert.assertTrue(partition.getParameters().containsKey("transient_lastDdlTime"));
     StorageDescriptor partitionSD = partition.getSd();
     Assert.assertEquals(table.getSd().getLocation() + "/" + partitionName,
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestDropPartitions.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestDropPartitions.java
index d496294..f84867d 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestDropPartitions.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestDropPartitions.java
@@ -217,7 +217,7 @@ public class TestDropPartitions extends MetaStoreClientTest {
     tableParams.put("auto.purge", "true");
     createTable(tableName, getYearPartCol(), tableParams);
 
-    String location = metaStore.getWarehouseRoot() + "/externalTable/year=2017";
+    String location = metaStore.getExternalWarehouseRoot() + "/externalTable/year=2017";
     Partition partition =
         createPartition(tableName, location, Lists.newArrayList("2017"), getYearPartCol(), null);
 
@@ -364,7 +364,7 @@ public class TestDropPartitions extends MetaStoreClientTest {
     tableParams.put("EXTERNAL", "true");
     createTable(tableName, getYearPartCol(), tableParams);
 
-    String location = metaStore.getWarehouseRoot() + "/externalTable/year=2017";
+    String location = metaStore.getExternalWarehouseRoot() + "/externalTable/year=2017";
     Partition partition =
         createPartition(tableName, location, Lists.newArrayList("2017"), getYearPartCol(), null);
 
@@ -587,9 +587,15 @@ public class TestDropPartitions extends MetaStoreClientTest {
   protected Table createTable(String tableName, List<FieldSchema> partCols,
       Map<String, String> tableParams) throws Exception {
     String type = "MANAGED_TABLE";
-    if (tableParams != null)
+    String location = metaStore.getWarehouseRoot() + "/" + tableName;
+
+    if (tableParams != null) {
       type = (tableParams.getOrDefault("EXTERNAL", "FALSE").equalsIgnoreCase("TRUE")) ?
         "EXTERNAL_TABLE" : "MANAGED_TABLE";
+      location = (type.equalsIgnoreCase("EXTERNAL_TABLE")) ?
+        (metaStore.getExternalWarehouseRoot() + "/" + tableName) : (metaStore.getWarehouseRoot() + "/" + tableName);
+    }
+
     Table table = new TableBuilder()
         .setDbName(DB_NAME)
         .setTableName(tableName)
@@ -597,7 +603,7 @@ public class TestDropPartitions extends MetaStoreClientTest {
         .addCol("test_id", "int", "test col id")
         .addCol("test_value", "string", "test col value")
         .setPartCols(partCols)
-        .setLocation(metaStore.getWarehouseRoot() + "/" + tableName)
+        .setLocation(location)
         .setTableParams(tableParams)
         .create(client, metaStore.getConf());
     return table;
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestExchangePartitions.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestExchangePartitions.java
index b008860..09d3862 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestExchangePartitions.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestExchangePartitions.java
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hive.metastore.IMetaStoreClient;
+import org.apache.hadoop.hive.metastore.TableType;
 import org.apache.hadoop.hive.metastore.Warehouse;
 import org.apache.hadoop.hive.metastore.annotation.MetastoreCheckinTest;
 import org.apache.hadoop.hive.metastore.api.FieldSchema;
@@ -230,9 +231,9 @@ public class TestExchangePartitions extends MetaStoreClientTest {
   public void testExchangePartitionsCustomTableLocations() throws Exception {
 
     Table source = createTable(DB_NAME, "test_source_table_cust_loc", getYearMonthAndDayPartCols(),
-        metaStore.getWarehouseRoot() + "/sourceTable");
+        metaStore.getExternalWarehouseRoot() + "/sourceTable");
     Table dest = createTable(DB_NAME, "test_dest_table_cust_loc", getYearMonthAndDayPartCols(),
-        metaStore.getWarehouseRoot() + "/destTable");
+        metaStore.getExternalWarehouseRoot() + "/destTable");
     Partition[] parts = new Partition[2];
     parts[0] = createPartition(source, Lists.newArrayList("2019", "may", "15"), null);
     parts[1] = createPartition(source, Lists.newArrayList("2019", "june", "14"), null);
@@ -250,9 +251,9 @@ public class TestExchangePartitions extends MetaStoreClientTest {
   public void testExchangePartitionsCustomTableAndPartLocation() throws Exception {
 
     Table source = createTable(DB_NAME, "test_source_table_cust_loc",
-        getYearMonthAndDayPartCols(), metaStore.getWarehouseRoot() + "/sourceTable");
+        getYearMonthAndDayPartCols(), metaStore.getExternalWarehouseRoot() + "/sourceTable");
     Table dest = createTable(DB_NAME, "test_dest_table_cust_loc", getYearMonthAndDayPartCols(),
-        metaStore.getWarehouseRoot() + "/destTable");
+        metaStore.getExternalWarehouseRoot() + "/destTable");
     Partition[] parts = new Partition[2];
     parts[0] = createPartition(source, Lists.newArrayList("2019", "may", "11"),
         source.getSd().getLocation() + "/2019m11");
@@ -753,9 +754,9 @@ public class TestExchangePartitions extends MetaStoreClientTest {
   public void testExchangePartitionCustomTableLocations() throws Exception {
 
     Table source = createTable(DB_NAME, "test_source_table_cust_loc",
-        getYearMonthAndDayPartCols(), metaStore.getWarehouseRoot() + "/sourceTable");
+        getYearMonthAndDayPartCols(), metaStore.getExternalWarehouseRoot() + "/sourceTable");
     Table dest = createTable(DB_NAME, "test_dest_table_cust_loc", getYearMonthAndDayPartCols(),
-        metaStore.getWarehouseRoot() + "/destTable");
+        metaStore.getExternalWarehouseRoot() + "/destTable");
     Partition[] parts = new Partition[2];
     parts[0] = createPartition(source, Lists.newArrayList("2019", "may", "15"), null);
     parts[1] = createPartition(source, Lists.newArrayList("2019", "june", "14"), null);
@@ -773,9 +774,9 @@ public class TestExchangePartitions extends MetaStoreClientTest {
   public void testExchangePartitionCustomTableAndPartLocation() throws Exception {
 
     Table source = createTable(DB_NAME, "test_source_table_cust_loc",
-        getYearMonthAndDayPartCols(), metaStore.getWarehouseRoot() + "/sourceTable");
+        getYearMonthAndDayPartCols(), metaStore.getExternalWarehouseRoot() + "/sourceTable");
     Table dest = createTable(DB_NAME, "test_dest_table_cust_loc", getYearMonthAndDayPartCols(),
-        metaStore.getWarehouseRoot() + "/destTable");
+        metaStore.getExternalWarehouseRoot() + "/destTable");
     Partition[] parts = new Partition[2];
     parts[0] = createPartition(source, Lists.newArrayList("2019", "may", "11"),
         source.getSd().getLocation() + "/2019m11");
@@ -1219,6 +1220,7 @@ public class TestExchangePartitions extends MetaStoreClientTest {
     new TableBuilder()
         .setDbName(dbName)
         .setTableName(tableName)
+        .setType(TableType.EXTERNAL_TABLE.name())
         .setCols(cols)
         .setPartCols(partCols)
         .setLocation(location)
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/minihms/AbstractMetaStoreService.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/minihms/AbstractMetaStoreService.java
index 709085d..5e9fdca 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/minihms/AbstractMetaStoreService.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/minihms/AbstractMetaStoreService.java
@@ -114,6 +114,16 @@ public abstract class AbstractMetaStoreService {
   }
 
   /**
+   * Returns the External MetaStore Warehouse root directory name.
+   *
+   * @return The external warehouse root directory
+   * @throws MetaException IO failure
+   */
+  public Path getExternalWarehouseRoot() throws MetaException {
+    return warehouse.getWhRootExternal();
+  }
+
+  /**
    * Check if a path exists.
    *
    * @param path The path to check
diff --git a/standalone-metastore/pom.xml b/standalone-metastore/pom.xml
index 9f064a8..54dae2c 100644
--- a/standalone-metastore/pom.xml
+++ b/standalone-metastore/pom.xml
@@ -52,6 +52,7 @@
     <log4j.conf.dir>${project.basedir}/src/test/resources</log4j.conf.dir>
     <test.tmp.dir>${project.build.directory}/tmp</test.tmp.dir>
     <test.warehouse.dir>${project.build.directory}/warehouse</test.warehouse.dir>
+    <test.warehouse.external.dir>${project.build.directory}/external</test.warehouse.external.dir>
     <test.warehouse.scheme>file://</test.warehouse.scheme>
     <test.forkcount>1</test.forkcount>
     <skipITests>true</skipITests>