org.apache.hive.service.TestDFSErrorHandling.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hive.service.TestDFSErrorHandling.java

Source

/**
 * 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();
    }
}