/** * 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.hadoop.hive.metastore.hbase; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.conf.Configuration; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * A tool to dump contents from the HBase store in a human readable form */ public class HBaseSchemaTool { public static void main(String[] args) { Options options = new Options(); options.addOption(OptionBuilder .withLongOpt("help") .withDescription("You're looking at it") .create('h')); options.addOption(OptionBuilder .withLongOpt("install") .withDescription("Install the schema onto an HBase cluster.") .create('i')); options.addOption(OptionBuilder .withLongOpt("key") .withDescription("Key to scan with. This should be an exact key (not a regular expression") .hasArg() .create('k')); options.addOption(OptionBuilder .withLongOpt("list-tables") .withDescription("List tables in HBase metastore") .create('l')); options.addOption(OptionBuilder .withLongOpt("regex-key") .withDescription("Regular expression to scan keys with.") .hasArg() .create('r')); options.addOption(OptionBuilder .withLongOpt("table") .withDescription("HBase metastore table to scan") .hasArg() .create('t')); CommandLine cli = null; try { cli = new GnuParser().parse(options, args); } catch (ParseException e) { System.err.println("Parse Exception: " + e.getMessage()); usage(options); return; } if (cli.hasOption('h')) { usage(options); return; } Configuration conf = new Configuration(); if (cli.hasOption('i')) { new HBaseSchemaTool().install(conf, System.err); return; } String key = null; if (cli.hasOption('k')) key = cli.getOptionValue('k'); String regex = null; if (cli.hasOption('r')) regex = cli.getOptionValue('r'); if (key != null && regex != null) { usage(options); return; } if (key == null && regex == null) regex = ".*"; // I do this in the object rather than in the static main so that it's easier to test. new HBaseSchemaTool().go(cli.hasOption('l'), cli.getOptionValue('t'), key, regex, conf, System.out, System.err); } private static void usage(Options options) { HelpFormatter formatter = new HelpFormatter(); String header = "This tool dumps contents of your hbase metastore. You need to specify\n" + "the table to dump. You can optionally specify a regular expression on the key for\n" + "the table. Keep in mind that the key is often a compound. For partitions regular\n" + "expressions are not used because non-string values are\nstored in binary. Instead for " + "partition you can specify as much of the exact prefix as you want. So you can give " + "dbname.tablename or dbname.tablename.pval1..."; String footer = "If neither key or regex is provided a regex of .* will be assumed. You\n" + "cannot set both key and regex."; formatter.printHelp("hbaseschematool", header, options, footer); return; } @VisibleForTesting void go(boolean listTables, String table, String key, String regex, Configuration conf, PrintStream out, PrintStream err) { List<String> lines = new ArrayList<>(); if (listTables) { lines = Arrays.asList(HBaseReadWrite.tableNames); } else { // If they've used '.' as a key separator we need to replace it with the separator used by // HBaseUtils if (key != null) key = key.replace('.', HBaseUtils.KEY_SEPARATOR); try { HBaseReadWrite.setConf(conf); HBaseReadWrite hrw = HBaseReadWrite.getInstance(); if (table.equalsIgnoreCase(HBaseReadWrite.DB_TABLE)) { if (key != null) lines.add(hrw.printDatabase(key)); else lines.addAll(hrw.printDatabases(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.FUNC_TABLE)) { if (key != null) lines.add(hrw.printFunction(key)); else lines.addAll(hrw.printFunctions(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.GLOBAL_PRIVS_TABLE)) { // Ignore whatever they passed, there's always only either one or zero global privileges lines.add(hrw.printGlobalPrivs()); } else if (table.equalsIgnoreCase(HBaseReadWrite.PART_TABLE)) { if (key != null) lines.add(hrw.printPartition(key)); else lines.addAll(hrw.printPartitions(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.USER_TO_ROLE_TABLE)) { if (key != null) lines.add(hrw.printRolesForUser(key)); else lines.addAll(hrw.printRolesForUsers(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.ROLE_TABLE)) { if (key != null) lines.add(hrw.printRole(key)); else lines.addAll(hrw.printRoles(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.TABLE_TABLE)) { if (key != null) lines.add(hrw.printTable(key)); else lines.addAll(hrw.printTables(regex)); } else if (table.equalsIgnoreCase(HBaseReadWrite.SD_TABLE)) { if (key != null) lines.add(hrw.printStorageDescriptor(Base64.decodeBase64(key))); else lines.addAll(hrw.printStorageDescriptors()); } else if (table.equalsIgnoreCase(HBaseReadWrite.SECURITY_TABLE)) { // We always print all of security, we don't worry about finding particular entries. lines.addAll(hrw.printSecurity()); } else if (table.equalsIgnoreCase(HBaseReadWrite.SEQUENCES_TABLE)) { // We always print all of sequences, we don't worry about finding particular entries. lines.addAll(hrw.printSequences()); } else { err.println("Unknown table: " + table); return; } } catch (Exception e) { err.println("Caught exception " + e.getClass() + " with message: " + e.getMessage()); return; } } for (String line : lines) out.println(line); } @VisibleForTesting void install(Configuration conf, PrintStream err) { try { // We need to set the conf because createTablesIfNotExist will get a thread local version // which requires that the configuration object be set. HBaseReadWrite.setConf(conf); HBaseReadWrite.createTablesIfNotExist(); } catch (Exception e) { err.println("Caught exception " + e.getClass() + " with message: " + e.getMessage()); return; } } }