Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hive.service; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; import org.apache.hadoop.hive.ql.ErrorMsg; import org.apache.hadoop.hive.shims.HadoopShims.MiniDFSShim; import org.apache.hive.jdbc.miniHS2.MiniHS2; import org.apache.hive.service.cli.HiveSQLException; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; /** * If the operation fails because of a DFS error, it used to result in an ugly stack at the client. * HIVE-16960 fixes that issue. This test case checks one DFS error related to sticky bit. When * the sticky bit is set, a user error indicating access denied will the thrown. * * Setup: HIVE_SERVER2_ENABLE_DOAS set to true: HS2 performs the operation as connected user. * Connect to HS2 as "hive". * Create a file and set the sticky bit on the directory. This will not allow the file to move * out of the directory. * Perform "LOAD" operation. This operation will attempt to move the file, resulting in an error * from DFS. The DFS error will translate to an Hive Error with number 20009, that corresponds to * "ACCESS DENIED". The test checks that 20009 is thrown. * * Additional tests can be added to cover Quota related exceptions. */ public class TestDFSErrorHandling { private static MiniHS2 miniHS2 = null; private static HiveConf hiveConf = null; @BeforeClass public static void startServices() throws Exception { hiveConf = new HiveConf(); hiveConf.setIntVar(ConfVars.HIVE_SERVER2_THRIFT_MIN_WORKER_THREADS, 1); hiveConf.setIntVar(ConfVars.HIVE_SERVER2_THRIFT_MAX_WORKER_THREADS, 1); hiveConf.setBoolVar(ConfVars.METASTORE_EXECUTE_SET_UGI, true); hiveConf.setBoolVar(ConfVars.HIVE_SUPPORT_CONCURRENCY, false); // Setting hive.server2.enable.doAs to True ensures that HS2 performs the query operation as // the connected user instead of the user running HS2. hiveConf.setBoolVar(ConfVars.HIVE_SERVER2_ENABLE_DOAS, true); miniHS2 = new MiniHS2.Builder().withMiniMR().withRemoteMetastore().withConf(hiveConf).build(); miniHS2.start(new HashMap<String, String>()); } @AfterClass public static void stopServices() throws Exception { if (miniHS2 != null && miniHS2.isStarted()) { miniHS2.stop(); } } @Test public void testAccessDenied() throws Exception { assertTrue("Test setup failed. MiniHS2 is not initialized", miniHS2 != null && miniHS2.isStarted()); Class.forName(MiniHS2.getJdbcDriverName()); Path scratchDir = new Path(HiveConf.getVar(hiveConf, HiveConf.ConfVars.SCRATCHDIR)); MiniDFSShim dfs = miniHS2.getDfs(); FileSystem fs = dfs.getFileSystem(); Path stickyBitDir = new Path(scratchDir, "stickyBitDir"); fs.mkdirs(stickyBitDir); String dataFileDir = hiveConf.get("test.data.files").replace('\\', '/').replace("c:", "").replace("C:", "") .replace("D:", "").replace("d:", ""); Path dataFilePath = new Path(dataFileDir, "kv1.txt"); fs.copyFromLocalFile(dataFilePath, stickyBitDir); FsPermission fsPermission = new FsPermission(FsAction.ALL, FsAction.ALL, FsAction.ALL, true); // Sets the sticky bit on stickyBitDir - now removing file kv1.txt from stickyBitDir by // unprivileged user will result in a DFS error. fs.setPermission(stickyBitDir, fsPermission); FileStatus[] files = fs.listStatus(stickyBitDir); // Connecting to HS2 as foo. Connection hs2Conn = DriverManager.getConnection(miniHS2.getJdbcURL(), "foo", "bar"); Statement stmt = hs2Conn.createStatement(); String tableName = "stickyBitTable"; stmt.execute("drop table if exists " + tableName); stmt.execute("create table " + tableName + " (foo int, bar string)"); try { // This statement will attempt to move kv1.txt out of stickyBitDir as user foo. HS2 is // expected to return 20009. stmt.execute("LOAD DATA INPATH '" + stickyBitDir.toUri().getPath() + "/kv1.txt' " + "OVERWRITE INTO TABLE " + tableName); } catch (Exception e) { if (e instanceof SQLException) { SQLException se = (SQLException) e; Assert.assertEquals("Unexpected error code", 20009, se.getErrorCode()); System.out.println(String.format("Error Message: %s", se.getMessage())); } else throw e; } stmt.execute("drop table if exists " + tableName); stmt.close(); hs2Conn.close(); } }