0

I want to write a UDF to get something from HBase,I use this to set token to hiveconf,but I cannot connect to HBase with hiveconf,it will throw NullPointException

I tried many ways,like that : https://www.programcreek.com/java-api-examples/index.php?api=org.apache.hadoop.hbase.security.token.TokenUtil

but it still throw NullPointException

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.hadoop.hbase.client.Connection;

import org.apache.hadoop.hbase.client.ConnectionFactory;

import org.apache.hadoop.hbase.security.User;

import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;

import org.apache.hadoop.hbase.security.token.TokenUtil;

import org.apache.hadoop.hive.conf.HiveConf;

import org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext;

import org.apache.hadoop.hive.ql.hooks.HookContext;

import org.apache.hadoop.security.UserGroupInformation;

import org.apache.hadoop.security.token.Token;

public class HbaseTokenFetcherHook implements ExecuteWithHookContext{   

    private static final Log LOG = LogFactory.getLog(HbaseTokenFetcherHook.class);

    @Override

    public void run(HookContext hookContext) throws Exception {

          HiveConf hiveConf = hookContext.getConf();

          /* If required */

          hiveConf.set(“zookeeper.znode.parent”, "/hbase-secure");   

          try {               

               UserGroupInformation.setConfiguration(hiveConf);

               Connection tokenConnection = ConnectionFactory.createConnection(hiveConf);

               Token<AuthenticationTokenIdentifier> token = TokenUtil.obtainToken(tokenConnection, User.getCurrent());

               String urlString = token.encodeToUrlString();

               hiveConf.set(“HBASE_AUTH_TOKEN”, urlString);

          } catch (IOException | InterruptedException e) {

               LOG.error("Error while fetching token for hbase"

                         + e.getMessage(), e);

          }

     }

}

it throw exception in:

Token<AuthenticationTokenIdentifier> token = TokenUtil.obtainToken(tokenConnection, User.getCurrent());

Error message : Caused by: java.lang.NullPointException at org.apache.hadoop.hbase.zookeeper.ZookeeperWatcher.getMetaReplicaNodes(ZookeeperWatcher.java:497) at org.apache.hadoop.hbase.zookeeper.MetaTableLocator.blockUntilAvailable(MetaTableLocator.java:558)

HYzhao
  • 21
  • 3

2 Answers2

0

Try Propolis third-party Hive UDFs, it has various HBase get functions to get value or the whole family. Instructions how to build and use are in the README, for more information about a particular UDF type describe and function name. I tested it on the Hadoop cluster with Kerberos and it worked fine.

serge_k
  • 1,772
  • 2
  • 15
  • 21
  • Thanks for answer me,I have tried this way,but I got a warning:`parquet.hadoop.ParquetRecordRader: Can not initialize counter due to context is not a instance of TaskInputOutputContext, but is org.apache.hadoop.mapreduce.task.TaskAttempContextImpl`,and the program stop at the step of `table.get()` – HYzhao Jun 18 '19 at 07:06
  • What version of Hive and HBase are you using? try to change versions in `pom.xml` and build propolis with `-DskipTests` – serge_k Jun 18 '19 at 07:33
  • Also try to change the format from Parquet to for example ORC when reading – serge_k Jun 18 '19 at 07:36
  • I have tried ORC, but the program throwed NullPointException,`at org.apache.hadoop.hbase.security.UserProvider.instantiate(UserProvider.java:122)`,I think my environment may have some problems,but I can not find it – HYzhao Jun 18 '19 at 08:34
  • Check your Kerberos ticket by `klist`, you can also try `kinit`. Then I would suggest you to connect to Hbase via `hbase shell` to make sure that your user has an access and try to query something from table of your interest from the shell. – serge_k Jun 18 '19 at 09:18
0

To obtain a Configuration object initalized with UserGroupInformation (check out this) you may need to give a lot more information. You may think that hiveConf obtained from hookContext.getConf should have all the Kerberos needed configuration, but it may not. Perhaps this code can give you a clue:

import javax.security.auth.login.AppConfigurationEntry;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.security.UserGroupInformation;

public String obtainHBASEDataWithKerberos(String key, String namespace, String tableName, String family, String qualifier) {
    try {
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "node1:2181, node2:2181, node3:2181");
        conf.set("hadoop.security.authentication","Kerberos");
        System.setProperty("javax.security.auth.useSubjectCredsOnly","false"); // https://stackoverflow.com/questions/33829017/gssexception-no-valid-credentials-provided-mechanism-level-failed-to-find-any
        conf.set("hbase.zookeeper.property.clientPort","2181");
        conf.set("hbase.cluster.distributed","true");       
        conf.set("zookeeper.znode.parent","/hbase-secure");
        conf.set("hbase.security.authentication", "Kerberos");
        UserGroupInformation.setConfiguration(conf);
        UserGroupInformation.loginUserFromSubject(null);
        UserGroupInformation ugi=UserGroupInformation.getLoginUser();
        String kerberos_principal=ugi.getUserName();
        if (kerberos_principal!=null) {
            if (kerberos_principal.contains("@")) {
                String domain=kerberos_principal.split("@")[1];
                conf.set("hbase.master.kerberos.principal", "hbase/_HOST@"+domain);
                conf.set("hbase.regionserver.kerberos.principal", "hbase/_HOST@"+domain);
            }
            // Create in-memory jaas file
            // Create HBASE entry options.
            HashMap<String, Object> hbase_options = new HashMap<String, Object>();
            hbase_options.put("doNotPrompt", "true");
            hbase_options.put("useTicketCache", "true");
            hbase_options.put("principal",kerberos_principal);
            hbase_options.put("storeKey","true");
            hbase_options.put("debug","true");

            // Create entries.
            final AppConfigurationEntry[] hbase_entries = {
                    new AppConfigurationEntry(
                            "com.sun.security.auth.module.Krb5LoginModule",
                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
                            hbase_options)
            };

            // Create configuration.
            javax.security.auth.login.Configuration jaasConfig = new javax.security.auth.login.Configuration() {
                @Override
                public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                    if ("Client".equals(name)) {
                        return hbase_entries;
                    }
                    else return null;
                }
            };

            javax.security.auth.login.Configuration.setConfiguration(jaasConfig);
            UserGroupInformation.setConfiguration(conf);

            Connection conn = null;
            Table table = null;

            conn=CentralKerberosUGI.getHBaseConnection();
            table = conn.getTable(TableName.valueOf(namespace + ":" + tableName));
            Result result = table.get(new Get(key.getBytes()));
            byte[] value = result.getValue(Bytes.toBytes(family), Bytes.toBytes(qualifier));
            return Bytes.toString(value);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
Javier
  • 74
  • 7