diff --git a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestJdbcWithMiniHS2.java b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestJdbcWithMiniHS2.java index 5dce16f..e00c3f9 100644 --- a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestJdbcWithMiniHS2.java +++ b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestJdbcWithMiniHS2.java @@ -303,7 +303,7 @@ private void verifyConfProperty(Statement stmt, String property, * @throws Exception */ @Test - public void testScratchDirs() throws Exception { + public void testSessionScratchDirs() throws Exception { // Stop HiveServer2 if (miniHS2.isStarted()) { miniHS2.stop(); @@ -326,19 +326,21 @@ public void testScratchDirs() throws Exception { hs2Conn = getConnection(miniHS2.getJdbcURL(), userName, "password"); // FS FileSystem fs = miniHS2.getLocalFS(); + FsPermission expectedFSPermission = new FsPermission(HiveConf.getVar(conf, + HiveConf.ConfVars.SCRATCHDIRPERMISSION)); // Verify scratch dir paths and permission // HDFS scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR) + "/" + userName); - verifyScratchDir(conf, fs, scratchDirPath, userName, false); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, false); // Local scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.LOCALSCRATCHDIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); // Downloaded resources dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.DOWNLOADED_RESOURCES_DIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); // 2. Test with doAs=true // Restart HiveServer2 with doAs=true @@ -356,15 +358,15 @@ public void testScratchDirs() throws Exception { // Verify scratch dir paths and permission // HDFS scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR) + "/" + userName); - verifyScratchDir(conf, fs, scratchDirPath, userName, false); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, false); // Local scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.LOCALSCRATCHDIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); // Downloaded resources dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.DOWNLOADED_RESOURCES_DIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); // Test for user "trinity" userName = "trinity"; @@ -373,22 +375,49 @@ public void testScratchDirs() throws Exception { // Verify scratch dir paths and permission // HDFS scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR) + "/" + userName); - verifyScratchDir(conf, fs, scratchDirPath, userName, false); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, false); // Local scratch dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.LOCALSCRATCHDIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); // Downloaded resources dir scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.DOWNLOADED_RESOURCES_DIR)); - verifyScratchDir(conf, fs, scratchDirPath, userName, true); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, true); + } + + /** + * Tests the creation of the root hdfs scratch dir, which should be writable by all (777). + * @throws Exception + */ + @Test + public void testRootScratchDir() throws Exception { + // Stop HiveServer2 + if (miniHS2.isStarted()) { + miniHS2.stop(); + } + HiveConf conf = new HiveConf(); + String userName; + Path scratchDirPath; + conf.set("hive.exec.scratchdir", "/tmp/hs2"); + // Start an instance of HiveServer2 which uses miniMR + miniHS2 = new MiniHS2(conf); + Map confOverlay = new HashMap(); + miniHS2.start(confOverlay); + userName = System.getProperty("user.name"); + hs2Conn = getConnection(miniHS2.getJdbcURL(), userName, "password"); + // FS + FileSystem fs = miniHS2.getLocalFS(); + FsPermission expectedFSPermission = new FsPermission("777"); + // Verify scratch dir paths and permission + // HDFS scratch dir + scratchDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR)); + verifyScratchDir(conf, fs, scratchDirPath, expectedFSPermission, userName, false); } private void verifyScratchDir(HiveConf conf, FileSystem fs, Path scratchDirPath, - String userName, boolean isLocal) throws Exception { + FsPermission expectedFSPermission, String userName, boolean isLocal) throws Exception { String dirType = isLocal ? "Local" : "DFS"; - FsPermission expectedFSPermission = new FsPermission(HiveConf.getVar(conf, - HiveConf.ConfVars.SCRATCHDIRPERMISSION)); assertTrue("The expected " + dirType + " scratch dir does not exist for the user: " + userName, fs.exists(scratchDirPath)); if (fs.exists(scratchDirPath) && !isLocal) { diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java index 5bbf3f6..464f193 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java @@ -92,6 +92,7 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathFilter; +import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hive.common.HiveInterruptCallback; import org.apache.hadoop.hive.common.HiveInterruptUtils; import org.apache.hadoop.hive.common.HiveStatsUtils; @@ -3423,6 +3424,44 @@ private static void createTmpDirs(Configuration conf, } } + public static boolean createDirsWithPermission(Configuration conf, Path mkdirPath, + FsPermission fsPermission, boolean recursive) throws IOException { + String origUmask = null; + LOG.debug("Create dirs " + mkdirPath + " with permission " + fsPermission + " recursive " + + recursive); + if (recursive) { + origUmask = conf.get(FsPermission.UMASK_LABEL); + // this umask is required because by default the hdfs mask is 022 resulting in + // all parents getting the fsPermission & !(022) permission instead of fsPermission + conf.set(FsPermission.UMASK_LABEL, "000"); + } + FileSystem fs = ShimLoader.getHadoopShims().getNonCachedFileSystem(mkdirPath.toUri(), conf); + boolean retval = false; + try { + retval = fs.mkdirs(mkdirPath, fsPermission); + resetConfAndCloseFS(conf, recursive, origUmask, fs); + } catch (IOException ioe) { + try { + resetConfAndCloseFS(conf, recursive, origUmask, fs); + } catch (IOException e) { + // do nothing - double failure + } + } + return retval; + } + + private static void resetConfAndCloseFS(Configuration conf, boolean unsetUmask, String origUmask, + FileSystem fs) throws IOException { + if (unsetUmask) { + if (origUmask != null) { + conf.set(FsPermission.UMASK_LABEL, origUmask); + } else { + conf.unset(FsPermission.UMASK_LABEL); + } + } + fs.close(); + } + /** * Returns true if a plan is both configured for vectorized execution * and vectorization is allowed. The plan may be configured for vectorization diff --git a/ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java b/ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java index 47fe508..b09d2b1 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java @@ -470,10 +470,7 @@ public static SessionState start(SessionState startSs) { */ private void createSessionDirs(String userName) throws IOException { HiveConf conf = getConf(); - // First create the root scratch dir on hdfs (if it doesn't already exist) and make it writable - Path rootHDFSDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR)); - String rootHDFSDirPermission = "777"; - createPath(conf, rootHDFSDirPath, rootHDFSDirPermission, false, false); + Path rootHDFSDirPath = createRootHDFSDir(conf); // Now create session specific dirs String scratchDirPermission = HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIRPERMISSION); Path path; @@ -506,6 +503,30 @@ private void createSessionDirs(String userName) throws IOException { } /** + * Create the root scratch dir on hdfs (if it doesn't already exist) and make it writable + * @param conf + * @return + * @throws IOException + */ + private Path createRootHDFSDir(HiveConf conf) throws IOException { + Path rootHDFSDirPath = new Path(HiveConf.getVar(conf, HiveConf.ConfVars.SCRATCHDIR)); + FsPermission expectedHDFSDirPermission = new FsPermission("777"); + FileSystem fs = rootHDFSDirPath.getFileSystem(conf); + if (!fs.exists(rootHDFSDirPath)) { + Utilities.createDirsWithPermission(conf, rootHDFSDirPath, expectedHDFSDirPermission, true); + } + FsPermission currentHDFSDirPermission = fs.getFileStatus(rootHDFSDirPath).getPermission(); + LOG.debug("HDFS root scratch dir: " + rootHDFSDirPath + ", permission: " + + currentHDFSDirPermission); + // If the root HDFS scratch dir already exists, make sure the permissions are 777. + if (!expectedHDFSDirPermission.equals(fs.getFileStatus(rootHDFSDirPath).getPermission())) { + throw new RuntimeException("The root scratch dir: " + rootHDFSDirPath + + " on HDFS should be writable. Current permissions are: " + currentHDFSDirPermission); + } + return rootHDFSDirPath; + } + + /** * Create a given path if it doesn't exist. * * @param conf