You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by co...@apache.org on 2018/04/30 16:35:40 UTC

[4/9] sentry git commit: SENTRY-2207 Refactor out Sentry CLI from sentry-provider-db into own module. Steve Moist, reviewed by Colm O hEigeartaigh.

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentrySchemaTool.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentrySchemaTool.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentrySchemaTool.java
new file mode 100644
index 0000000..893f80b
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentrySchemaTool.java
@@ -0,0 +1,595 @@
+/**
+ * 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.sentry.cli.tools;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.MalformedURLException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.IllegalFormatException;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hive.beeline.BeeLine;
+import org.apache.sentry.Command;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
+import org.apache.sentry.provider.db.service.persistent.SentryStoreSchemaInfo;
+import org.apache.sentry.cli.tools.SentrySchemaHelper.NestedScriptParser;
+import org.apache.sentry.service.thrift.SentryService;
+import org.apache.sentry.service.thrift.ServiceConstants;
+
+public class SentrySchemaTool {
+  private static final String SENTRY_SCRIP_DIR = File.separatorChar + "scripts"
+      + File.separatorChar + "sentrystore" + File.separatorChar + "upgrade";
+  private String userName = null;
+  private String passWord = null;
+  private String connectionURL = null;
+  private String driver = null;
+  private boolean dryRun = false;
+  private String dbOpts = null;
+  private boolean verbose = false;
+  private final Configuration sentryConf;
+  private final String dbType;
+  private final SentryStoreSchemaInfo sentryStoreSchemaInfo;
+
+  public SentrySchemaTool(Configuration sentryConf, String dbType)
+      throws SentryUserException, IOException {
+    this(System.getenv("SENTRY_HOME") + SENTRY_SCRIP_DIR, sentryConf, dbType);
+  }
+
+  public SentrySchemaTool(String sentryScripPath, Configuration sentryConf,
+      String dbType) throws SentryUserException, IOException {
+    if (sentryScripPath == null || sentryScripPath.isEmpty()) {
+      throw new SentryUserException("No Sentry script dir provided");
+    }
+    this.sentryConf = sentryConf;
+    this.dbType = dbType;
+    this.sentryStoreSchemaInfo = new SentryStoreSchemaInfo(sentryScripPath,
+        dbType);
+    userName = sentryConf.get(ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_USER,
+        ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_USER_DEFAULT);
+    //Password will be read from Credential provider specified using property
+    // CREDENTIAL_PROVIDER_PATH("hadoop.security.credential.provider.path" in sentry-site.xml
+    // it falls back to reading directly from sentry-site.xml
+    char[] passTmp = sentryConf.getPassword(ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_PASS);
+    if(passTmp != null) {
+      passWord = new String(passTmp);
+    } else {
+      throw new SentrySiteConfigurationException("Error reading " + ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_PASS);
+    }
+
+    try {
+      connectionURL = getValidConfVar(ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_URL);
+      if(dbType.equalsIgnoreCase(SentrySchemaHelper.DB_DERBY)) {
+        driver = sentryConf.get(ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_DRIVER,
+            ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_DRIVER_DEFAULT);
+      } else {
+        driver = getValidConfVar(ServiceConstants.ServerConfig.SENTRY_STORE_JDBC_DRIVER);
+      }
+      // load required JDBC driver
+      Class.forName(driver);
+    } catch (IOException e) {
+      throw new SentryUserException("Missing property: " + e.getMessage());
+    } catch (ClassNotFoundException e) {
+      throw new SentryUserException("Failed to load driver", e);
+    }
+  }
+
+  public Configuration getConfiguration() {
+    return sentryConf;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  public void setPassWord(String passWord) {
+    this.passWord = passWord;
+  }
+
+  public void setDryRun(boolean dryRun) {
+    this.dryRun = dryRun;
+  }
+
+  public void setVerbose(boolean verbose) {
+    this.verbose = verbose;
+  }
+
+  public String getDbOpts() {
+    return dbOpts;
+  }
+
+  public void setDbOpts(String dbOpts) {
+    this.dbOpts = dbOpts;
+  }
+
+  private static void printAndExit(Options cmdLineOptions) {
+    HelpFormatter formatter = new HelpFormatter();
+    formatter.printHelp("schemaTool", cmdLineOptions);
+    System.exit(1);
+  }
+
+  /***
+   * Print Hive version and schema version
+   * @throws SentryUserException
+   */
+  public void showInfo() throws SentryUserException {
+    Connection sentryStoreConn = getConnectionToMetastore(true);
+    System.out.println("Sentry distribution version:\t "
+        + SentryStoreSchemaInfo.getSentryVersion());
+    System.out.println("SentryStore schema version:\t "
+        + getMetaStoreSchemaVersion(sentryStoreConn));
+  }
+
+  // read schema version from sentry store
+  private String getMetaStoreSchemaVersion(Connection sentryStoreConn)
+      throws SentryUserException {
+    String versionQuery;
+    if (SentrySchemaHelper.getDbCommandParser(dbType).needsQuotedIdentifier()) {
+      versionQuery = "select t.\"SCHEMA_VERSION\" from \"SENTRY_VERSION\" t";
+    } else {
+      versionQuery = "select t.SCHEMA_VERSION from SENTRY_VERSION t";
+    }
+    try (Statement stmt = sentryStoreConn.createStatement();
+      ResultSet res = stmt.executeQuery(versionQuery)) {
+      if (!res.next()) {
+        throw new SentryUserException("Didn't find version data in sentry store");
+      }
+      String currentSchemaVersion = res.getString(1);
+      sentryStoreConn.close();
+      return currentSchemaVersion;
+    } catch (SQLException e) {
+      throw new SentryUserException("Failed to get schema version.", e);
+    }
+  }
+
+  // test the connection sentry store using the config property
+  private void testConnectionToMetastore() throws SentryUserException {
+    try (Connection conn = getConnectionToMetastore(true)) {
+      conn.close();
+    } catch (SQLException e) {
+      throw new SentryUserException("Failed to close sentry store connection", e);
+    }
+  }
+
+  /***
+   * get JDBC connection to sentry store db
+   *
+   * @param printInfo print connection parameters
+   * @return
+   * @throws SentryUserException
+   */
+  private Connection getConnectionToMetastore(boolean printInfo)
+      throws SentryUserException {
+    if (printInfo) {
+      System.out.println("Sentry store connection URL:\t " + connectionURL);
+      System.out.println("Sentry store Connection Driver :\t " + driver);
+      System.out.println("Sentry store connection User:\t " + userName);
+    }
+    if (userName == null || userName.isEmpty()) {
+      throw new SentryUserException("UserName empty ");
+    }
+    try {
+      // Connect using the JDBC URL and user/pass from conf
+      return DriverManager.getConnection(connectionURL, userName, passWord);
+    } catch (SQLException e) {
+      throw new SentryUserException("Failed to make connection to Sentry store.", e);
+    }
+  }
+
+  /**
+   * check if the current schema version in sentry store matches the Hive version
+   * @throws SentryUserException
+   */
+  public void verifySchemaVersion() throws SentryUserException {
+    // don't check version if its a dry run
+    if (dryRun) {
+      return;
+    }
+    String newSchemaVersion =
+        getMetaStoreSchemaVersion(getConnectionToMetastore(false));
+    // verify that the new version is added to schema
+    if (!sentryStoreSchemaInfo.getSentrySchemaVersion().equalsIgnoreCase(
+        newSchemaVersion)) {
+      throw new SentryUserException("Found unexpected schema version "
+          + newSchemaVersion);
+    }
+  }
+
+  /**
+   * Perform sentry store schema upgrade. extract the current schema version from sentry store
+   * @throws SentryUserException
+   */
+  public void doUpgrade() throws SentryUserException {
+    String fromVersion = getMetaStoreSchemaVersion(getConnectionToMetastore(false));
+    if (fromVersion == null || fromVersion.isEmpty()) {
+      throw new SentryUserException(
+          "Schema version not stored in the sentry store. "
+              +
+          "Metastore schema is too old or corrupt. Try specifying the version manually");
+    }
+    doUpgrade(fromVersion);
+  }
+
+  /**
+   * Perform sentry store schema upgrade
+   *
+   * @param fromSchemaVer
+   *          Existing version of the sentry store. If null, then read from the sentry store
+   * @throws SentryUserException
+   */
+  public void doUpgrade(String fromSchemaVer) throws SentryUserException {
+    if (sentryStoreSchemaInfo.getSentrySchemaVersion().equals(fromSchemaVer)) {
+      System.out.println("No schema upgrade required from version " + fromSchemaVer);
+      return;
+    }
+    // Find the list of scripts to execute for this upgrade
+    List<String> upgradeScripts =
+        sentryStoreSchemaInfo.getUpgradeScripts(fromSchemaVer);
+    testConnectionToMetastore();
+    System.out.println("Starting upgrade sentry store schema from version " +
+ fromSchemaVer + " to "
+        + sentryStoreSchemaInfo.getSentrySchemaVersion());
+    String scriptDir = sentryStoreSchemaInfo.getSentryStoreScriptDir();
+    try {
+      for (String scriptFile : upgradeScripts) {
+        System.out.println("Upgrade script " + scriptFile);
+        if (!dryRun) {
+          runBeeLine(scriptDir, scriptFile);
+          System.out.println("Completed " + scriptFile);
+        }
+      }
+    } catch (IOException eIO) {
+      throw new SentryUserException(
+          "Upgrade FAILED! Metastore state would be inconsistent !!", eIO);
+    }
+
+    // Revalidated the new version after upgrade
+    verifySchemaVersion();
+  }
+
+  /**
+   * Initialize the sentry store schema to current version
+   *
+   * @throws SentryUserException
+   */
+  public void doInit() throws SentryUserException {
+    doInit(sentryStoreSchemaInfo.getSentrySchemaVersion());
+
+    // Revalidated the new version after upgrade
+    verifySchemaVersion();
+  }
+
+  /**
+   * Initialize the sentry store schema
+   *
+   * @param toVersion
+   *          If null then current hive version is used
+   * @throws SentryUserException
+   */
+  public void doInit(String toVersion) throws SentryUserException {
+    testConnectionToMetastore();
+    System.out.println("Starting sentry store schema initialization to " + toVersion);
+
+    String initScriptDir = sentryStoreSchemaInfo.getSentryStoreScriptDir();
+    String initScriptFile = sentryStoreSchemaInfo.generateInitFileName(toVersion);
+
+    try {
+      System.out.println("Initialization script " + initScriptFile);
+      if (!dryRun) {
+        runBeeLine(initScriptDir, initScriptFile);
+        System.out.println("Initialization script completed");
+      }
+    } catch (IOException e) {
+      throw new SentryUserException("Schema initialization FAILED!"
+          + " Metastore state would be inconsistent !!", e);
+    }
+  }
+
+  // Flatten the nested upgrade script into a buffer
+  public static String buildCommand(NestedScriptParser dbCommandParser,
+        String scriptDir, String scriptFile) throws IllegalFormatException, IOException {
+
+    BufferedReader bfReader =
+        new BufferedReader(new FileReader(scriptDir + File.separatorChar + scriptFile));
+    String currLine;
+    StringBuilder sb = new StringBuilder();
+    String currentCommand = null;
+    while ((currLine = bfReader.readLine()) != null) {
+      currLine = currLine.trim();
+      if (currLine.isEmpty()) {
+        continue; // skip empty lines
+      }
+
+      if (currentCommand == null) {
+        currentCommand = currLine;
+      } else {
+        currentCommand = currentCommand + " " + currLine;
+      }
+      if (dbCommandParser.isPartialCommand(currLine)) {
+        // if its a partial line, continue collecting the pieces
+        continue;
+      }
+
+      // if this is a valid executable command then add it to the buffer
+      if (!dbCommandParser.isNonExecCommand(currentCommand)) {
+        currentCommand = dbCommandParser.cleanseCommand(currentCommand);
+
+        if (dbCommandParser.isNestedScript(currentCommand)) {
+          // if this is a nested sql script then flatten it
+          String currScript = dbCommandParser.getScriptName(currentCommand);
+          sb.append(buildCommand(dbCommandParser, scriptDir, currScript));
+        } else {
+          // Now we have a complete statement, process it
+          // write the line to buffer
+          sb.append(currentCommand);
+          sb.append(System.getProperty("line.separator"));
+        }
+      }
+      currentCommand = null;
+    }
+    bfReader.close();
+    return sb.toString();
+  }
+
+  // run beeline on the given sentry store scrip, flatten the nested scripts into single file
+  private void runBeeLine(String scriptDir, String scriptFile) throws IOException {
+    NestedScriptParser dbCommandParser =
+        SentrySchemaHelper.getDbCommandParser(dbType);
+    dbCommandParser.setDbOpts(getDbOpts());
+    // expand the nested script
+    String sqlCommands = buildCommand(dbCommandParser, scriptDir, scriptFile);
+    File tmpFile = File.createTempFile("schematool", ".sql");
+    tmpFile.deleteOnExit();
+
+    // write out the buffer into a file. Add beeline commands for autocommit and close
+    try (FileWriter fstream = new FileWriter(tmpFile.getPath());
+      BufferedWriter out = new BufferedWriter(fstream)) {
+
+      out.write("!set Silent " + verbose + System.getProperty("line.separator"));
+      out.write("!autocommit on" + System.getProperty("line.separator"));
+      out.write("!set Isolation TRANSACTION_READ_COMMITTED"
+          + System.getProperty("line.separator"));
+      out.write("!set AllowMultiLineCommand false"
+          + System.getProperty("line.separator"));
+      out.write(sqlCommands);
+      out.write("!closeall" + System.getProperty("line.separator"));
+      out.close();
+    }
+    runBeeLine(tmpFile.getPath());
+  }
+
+  // Generate the beeline args per hive conf and execute the given script
+  public void runBeeLine(String sqlScriptFile) throws IOException {
+    List<String> argList = new ArrayList<String>();
+    argList.add("-u");
+    argList.add(connectionURL);
+    argList.add("-d");
+    argList
+        .add(driver);
+    argList.add("-n");
+    argList.add(userName);
+    argList.add("-p");
+    argList.add(passWord);
+    argList.add("-f");
+    argList.add(sqlScriptFile);
+
+    BeeLine beeLine = new BeeLine();
+    if (!verbose) {
+      beeLine.setOutputStream(new PrintStream(new NullOutputStream()));
+      // beeLine.getOpts().setSilent(true);
+    }
+    // beeLine.getOpts().setAllowMultiLineCommand(false);
+    // beeLine.getOpts().setIsolation("TRANSACTION_READ_COMMITTED");
+    int status = beeLine.begin(argList.toArray(new String[0]), null);
+    if (status != 0) {
+      throw new IOException("Schema script failed, errorcode " + status);
+    }
+  }
+
+  private String getValidConfVar(String confVar) throws IOException {
+    String confVarKey = confVar;
+    String confVarValue = sentryConf.get(confVarKey);
+    if (confVarValue == null || confVarValue.isEmpty()) {
+      throw new IOException("Empty " + confVar);
+    }
+    return confVarValue;
+  }
+
+  // Create the required command line options
+  @SuppressWarnings("static-access")
+  private static void initOptions(Options cmdLineOptions) {
+    Option help = new Option("help", "print this message");
+    Option upgradeOpt = new Option("upgradeSchema", "Schema upgrade");
+    Option upgradeFromOpt = OptionBuilder.withArgName("upgradeFrom").hasArg().
+                withDescription("Schema upgrade from a version").
+                create("upgradeSchemaFrom");
+    Option initOpt = new Option("initSchema", "Schema initialization");
+    Option initToOpt = OptionBuilder.withArgName("initTo").hasArg().
+                withDescription("Schema initialization to a version").
+                create("initSchemaTo");
+    Option infoOpt = new Option("info", "Show config and schema details");
+
+    OptionGroup optGroup = new OptionGroup();
+    optGroup.addOption(upgradeOpt).addOption(initOpt).
+                addOption(help).addOption(upgradeFromOpt).
+                addOption(initToOpt).addOption(infoOpt);
+    optGroup.setRequired(true);
+
+    Option userNameOpt = OptionBuilder.withArgName("user")
+                .hasArg()
+                .withDescription("Override config file user name")
+                .create("userName");
+    Option passwdOpt = OptionBuilder.withArgName("password")
+                .hasArg()
+                 .withDescription("Override config file password")
+                 .create("passWord");
+    Option dbTypeOpt = OptionBuilder.withArgName("databaseType")
+                .hasArg().withDescription("Metastore database type [" +
+                SentrySchemaHelper.DB_DERBY + "," +
+                SentrySchemaHelper.DB_MYSQL + "," +
+                SentrySchemaHelper.DB_ORACLE + "," +
+                SentrySchemaHelper.DB_POSTGRACE + "," +
+                SentrySchemaHelper.DB_DB2 + "]")
+                .create("dbType");
+    Option dbOpts = OptionBuilder.withArgName("databaseOpts")
+                .hasArgs().withDescription("Backend DB specific options")
+                .create("dbOpts");
+
+    Option dryRunOpt = new Option("dryRun", "list SQL scripts (no execute)");
+    Option verboseOpt = new Option("verbose", "only print SQL statements");
+
+    Option configOpt = OptionBuilder.withArgName("confName").hasArgs()
+        .withDescription("Sentry Service configuration file").isRequired(true)
+        .create(ServiceConstants.ServiceArgs.CONFIG_FILE_LONG);
+
+    cmdLineOptions.addOption(help);
+    cmdLineOptions.addOption(dryRunOpt);
+    cmdLineOptions.addOption(userNameOpt);
+    cmdLineOptions.addOption(passwdOpt);
+    cmdLineOptions.addOption(dbTypeOpt);
+    cmdLineOptions.addOption(verboseOpt);
+    cmdLineOptions.addOption(dbOpts);
+    cmdLineOptions.addOption(configOpt);
+    cmdLineOptions.addOptionGroup(optGroup);
+  }
+
+  public static class CommandImpl implements Command {
+    @Override
+    public void run(String[] args) throws Exception {
+      CommandLineParser parser = new GnuParser();
+      CommandLine line = null;
+      String dbType = null;
+      String schemaVer = null;
+      Options cmdLineOptions = new Options();
+      String configFileName = null;
+
+      // Argument handling
+      initOptions(cmdLineOptions);
+      try {
+        line = parser.parse(cmdLineOptions, args);
+      } catch (ParseException e) {
+        System.err.println("SentrySchemaTool:Parsing failed.  Reason: "
+            + e.getLocalizedMessage());
+        printAndExit(cmdLineOptions);
+      }
+
+      if (line.hasOption("help")) {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("schemaTool", cmdLineOptions);
+        return;
+      }
+
+      if (line.hasOption("dbType")) {
+        dbType = line.getOptionValue("dbType");
+        if (!dbType.equalsIgnoreCase(SentrySchemaHelper.DB_DERBY)
+            && !dbType.equalsIgnoreCase(SentrySchemaHelper.DB_MYSQL)
+            && !dbType.equalsIgnoreCase(SentrySchemaHelper.DB_POSTGRACE)
+            && !dbType.equalsIgnoreCase(SentrySchemaHelper.DB_ORACLE)
+            && !dbType.equalsIgnoreCase(SentrySchemaHelper.DB_DB2)) {
+          System.err.println("Unsupported dbType " + dbType);
+          printAndExit(cmdLineOptions);
+        }
+      } else {
+        System.err.println("no dbType supplied");
+        printAndExit(cmdLineOptions);
+      }
+      if (line.hasOption(ServiceConstants.ServiceArgs.CONFIG_FILE_LONG)) {
+        configFileName = line
+            .getOptionValue(ServiceConstants.ServiceArgs.CONFIG_FILE_LONG);
+      } else {
+        System.err.println("no config file specified");
+        printAndExit(cmdLineOptions);
+      }
+      try {
+        SentrySchemaTool schemaTool = new SentrySchemaTool(
+            SentryService.loadConfig(configFileName), dbType);
+
+        if (line.hasOption("userName")) {
+          schemaTool.setUserName(line.getOptionValue("userName"));
+        }
+        if (line.hasOption("passWord")) {
+          schemaTool.setPassWord(line.getOptionValue("passWord"));
+        }
+        if (line.hasOption("dryRun")) {
+          schemaTool.setDryRun(true);
+        }
+        if (line.hasOption("verbose")) {
+          schemaTool.setVerbose(true);
+        }
+        if (line.hasOption("dbOpts")) {
+          schemaTool.setDbOpts(line.getOptionValue("dbOpts"));
+        }
+
+        if (line.hasOption("info")) {
+          schemaTool.showInfo();
+        } else if (line.hasOption("upgradeSchema")) {
+          schemaTool.doUpgrade();
+        } else if (line.hasOption("upgradeSchemaFrom")) {
+          schemaVer = line.getOptionValue("upgradeSchemaFrom");
+          schemaTool.doUpgrade(schemaVer);
+        } else if (line.hasOption("initSchema")) {
+          schemaTool.doInit();
+        } else if (line.hasOption("initSchemaTo")) {
+          schemaVer = line.getOptionValue("initSchemaTo");
+          schemaTool.doInit(schemaVer);
+        } else {
+          System.err.println("no valid option supplied");
+          printAndExit(cmdLineOptions);
+        }
+      } catch (SentryUserException e) {
+        System.err.println(e);
+        if (line.hasOption("verbose")) {
+          e.printStackTrace();
+        }
+        System.err.println("*** Sentry schemaTool failed ***");
+        System.exit(1);
+      } catch (MalformedURLException e) {
+        System.err.println(e);
+        if (line.hasOption("verbose")) {
+          e.printStackTrace();
+        }
+        System.err.println("*** Sentry schemaTool failed ***");
+        System.exit(1);
+      }
+      System.out.println("Sentry schemaTool completed");
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellCommon.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellCommon.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellCommon.java
new file mode 100644
index 0000000..94800a4
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellCommon.java
@@ -0,0 +1,284 @@
+/**
+ * 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.sentry.cli.tools;
+
+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.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * SentryShellCommon provides the function for parsing the argument.
+ * For hive model and generic model, child class should be implemented as a sentry admin tool.
+ */
+abstract public class SentryShellCommon {
+
+  public enum TYPE { kafka, hive, solr, sqoop };
+
+  public static final String OPTION_DESC_HELP = "Shell usage";
+  public static final String OPTION_DESC_CONF = "sentry-site file path";
+  public static final String OPTION_DESC_ROLE_NAME = "Role name";
+  public static final String OPTION_DESC_GROUP_NAME = "Group name";
+  public static final String OPTION_DESC_PRIVILEGE = "Privilege string";
+  public final static String OPTION_DESC_SERVICE = "Name of the service being managed";
+  public static final String PREFIX_MESSAGE_MISSING_OPTION = "Missing required option: ";
+
+  public static final String GROUP_SPLIT_CHAR = ",";
+
+  protected String roleName;
+  protected String serviceName;
+  protected String groupName;
+  protected String privilegeStr;
+  protected String confPath;
+  // flag for the command
+  protected boolean isCreateRole;
+  protected boolean isDropRole;
+  protected boolean isAddRoleGroup;
+  protected boolean isDeleteRoleGroup;
+  protected boolean isGrantPrivilegeRole;
+  protected boolean isRevokePrivilegeRole;
+  protected boolean isListRole;
+  protected boolean isListPrivilege;
+  protected boolean isListGroup;
+  protected boolean isPrintHelp;
+  // flag for the parameter check
+  protected boolean roleNameRequired;
+  protected boolean groupNameRequired;
+  protected boolean privilegeStrRequired;
+  protected TYPE type;
+
+  /**
+   * parse arguments
+   *
+   * <pre>
+   *   -conf,--sentry_conf             <filepath>                 sentry config file path
+   *   -cr,--create_role            -r <rolename>                 create role
+   *   -dr,--drop_role              -r <rolename>                 drop role
+   *   -arg,--add_role_group        -r <rolename>  -g <groupname> add role to group
+   *   -drg,--delete_role_group     -r <rolename>  -g <groupname> delete role from group
+   *   -gpr,--grant_privilege_role  -r <rolename>  -p <privilege> grant privilege to role
+   *   -rpr,--revoke_privilege_role -r <rolename>  -p <privilege> revoke privilege from role
+   *   -lr,--list_role              -g <groupname>                list roles for group
+   *   -lp,--list_privilege         -r <rolename>                 list privilege for role
+   *   -lg,--list_group                                           list all groups associated with all roles
+   *   -t,--type                    <typename>                    the shell for hive model or generic model
+   * </pre>
+   *
+   * @param args
+   */
+  protected boolean parseArgs(String[] args) {
+    Options simpleShellOptions = new Options();
+
+    setupOptions(simpleShellOptions);
+
+
+
+    // help option
+    Option helpOpt = new Option("h", "help", false, OPTION_DESC_HELP);
+    helpOpt.setRequired(false);
+    simpleShellOptions.addOption(helpOpt);
+
+    // this Options is parsed first for help option
+    Options helpOptions = new Options();
+    helpOptions.addOption(helpOpt);
+
+    try {
+      Parser parser = new GnuParser();
+
+      // parse help option first
+      CommandLine cmd = parser.parse(helpOptions, args, true);
+      for (Option opt : cmd.getOptions()) {
+        if (opt.getOpt().equals("h")) {
+          // get the help option, print the usage and exit
+          usage(simpleShellOptions);
+          return false;
+        }
+      }
+
+      // without help option
+      cmd = parser.parse(simpleShellOptions, args);
+
+      parseOptions(cmd);
+    } catch (ParseException pe) {
+      System.out.println(pe.getMessage());
+      usage(simpleShellOptions);
+      return false;
+    }
+    return true;
+  }
+
+  protected void setupOptions(Options simpleShellOptions) {
+    OptionGroup simpleShellOptGroup = getMainOptions();
+    simpleShellOptions.addOptionGroup(simpleShellOptGroup);
+
+    Option sOpt = new Option("s", "service", true, OPTION_DESC_SERVICE);
+    sOpt.setRequired(false);
+    simpleShellOptions.addOption(sOpt);
+
+    // optional args
+    Option pOpt = new Option("p", "privilege", true, OPTION_DESC_PRIVILEGE);
+    pOpt.setRequired(false);
+    simpleShellOptions.addOption(pOpt);
+
+    Option gOpt = new Option("g", "groupname", true, OPTION_DESC_GROUP_NAME);
+    gOpt.setRequired(false);
+    simpleShellOptions.addOption(gOpt);
+
+    Option rOpt = new Option("r", "rolename", true, OPTION_DESC_ROLE_NAME);
+    rOpt.setRequired(false);
+    simpleShellOptions.addOption(rOpt);
+
+    // this argument should also be parsed in the bin/sentryShell
+    Option tOpt = new Option("t", "type", true, "[hive|solr|sqoop|.....]");
+    tOpt.setRequired(false);
+    simpleShellOptions.addOption(tOpt);
+
+    // file path of sentry-site
+    Option sentrySitePathOpt = new Option("conf", "sentry_conf", true, OPTION_DESC_CONF);
+    sentrySitePathOpt.setRequired(true);
+    simpleShellOptions.addOption(sentrySitePathOpt);
+  }
+
+  protected OptionGroup getMainOptions() {
+    OptionGroup simpleShellOptGroup = new OptionGroup();
+    Option crOpt = new Option("cr", "create_role", false, "Create role");
+    crOpt.setRequired(false);
+
+    Option drOpt = new Option("dr", "drop_role", false, "Drop role");
+    drOpt.setRequired(false);
+
+    Option argOpt = new Option("arg", "add_role_group", false, "Add role to group");
+    argOpt.setRequired(false);
+
+    Option drgOpt = new Option("drg", "delete_role_group", false, "Delete role from group");
+    drgOpt.setRequired(false);
+
+    Option gprOpt = new Option("gpr", "grant_privilege_role", false, "Grant privilege to role");
+    gprOpt.setRequired(false);
+
+    Option rprOpt = new Option("rpr", "revoke_privilege_role", false, "Revoke privilege from role");
+    rprOpt.setRequired(false);
+
+    Option lrOpt = new Option("lr", "list_role", false, "List role");
+    lrOpt.setRequired(false);
+
+    Option lpOpt = new Option("lp", "list_privilege", false, "List privilege");
+    lpOpt.setRequired(false);
+
+    Option lgOpt = new Option("lg", "list_group", false, "List groups");
+    lgOpt.setRequired(false);
+
+
+    // required args group
+    simpleShellOptGroup.addOption(crOpt);
+    simpleShellOptGroup.addOption(drOpt);
+    simpleShellOptGroup.addOption(argOpt);
+    simpleShellOptGroup.addOption(drgOpt);
+    simpleShellOptGroup.addOption(gprOpt);
+    simpleShellOptGroup.addOption(rprOpt);
+    simpleShellOptGroup.addOption(lrOpt);
+    simpleShellOptGroup.addOption(lpOpt);
+    simpleShellOptGroup.addOption(lgOpt);
+    simpleShellOptGroup.setRequired(true);
+    return simpleShellOptGroup;
+  }
+
+  protected void parseOptions(CommandLine cmd) throws ParseException {
+    for (Option opt : cmd.getOptions()) {
+      if (opt.getOpt().equals("p")) {
+        privilegeStr = opt.getValue();
+      } else if (opt.getOpt().equals("g")) {
+        groupName = opt.getValue();
+      } else if (opt.getOpt().equals("r")) {
+        roleName = opt.getValue();
+      } else if (opt.getOpt().equals("s")) {
+        serviceName = opt.getValue();
+      } else if (opt.getOpt().equals("cr")) {
+        isCreateRole = true;
+        roleNameRequired = true;
+      } else if (opt.getOpt().equals("dr")) {
+        isDropRole = true;
+        roleNameRequired = true;
+      } else if (opt.getOpt().equals("arg")) {
+        isAddRoleGroup = true;
+        roleNameRequired = true;
+        groupNameRequired = true;
+      } else if (opt.getOpt().equals("drg")) {
+        isDeleteRoleGroup = true;
+        roleNameRequired = true;
+        groupNameRequired = true;
+      } else if (opt.getOpt().equals("gpr")) {
+        isGrantPrivilegeRole = true;
+        roleNameRequired = true;
+        privilegeStrRequired = true;
+      } else if (opt.getOpt().equals("rpr")) {
+        isRevokePrivilegeRole = true;
+        roleNameRequired = true;
+        privilegeStrRequired = true;
+      } else if (opt.getOpt().equals("lr")) {
+        isListRole = true;
+      } else if (opt.getOpt().equals("lp")) {
+        isListPrivilege = true;
+        roleNameRequired = true;
+      } else if (opt.getOpt().equals("lg")) {
+        isListGroup = true;
+      } else if (opt.getOpt().equals("conf")) {
+        confPath = opt.getValue();
+      } else if (opt.getOpt().equals("t")) {
+        type = TYPE.valueOf(opt.getValue());
+      }
+    }
+    checkRequiredParameter(roleNameRequired, roleName, OPTION_DESC_ROLE_NAME);
+    checkRequiredParameter(groupNameRequired, groupName, OPTION_DESC_GROUP_NAME);
+    checkRequiredParameter(privilegeStrRequired, privilegeStr, OPTION_DESC_PRIVILEGE);
+  }
+
+  protected void checkRequiredParameter(boolean isRequired, String paramValue, String paramName) throws ParseException {
+    if (isRequired && StringUtils.isEmpty(paramValue)) {
+      throw new ParseException(PREFIX_MESSAGE_MISSING_OPTION + paramName);
+    }
+  }
+
+  // print usage
+  private void usage(Options sentryOptions) {
+    HelpFormatter formatter = new HelpFormatter();
+    formatter.printHelp("sentryShell", sentryOptions);
+  }
+
+  // hive model and generic model should implement this method
+  public abstract void run() throws Exception;
+
+  @VisibleForTesting
+  public boolean executeShell(String[] args) throws Exception {
+    boolean result = true;
+    if (parseArgs(args)) {
+      run();
+    } else {
+      result = false;
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellGeneric.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellGeneric.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellGeneric.java
new file mode 100644
index 0000000..6d25617
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellGeneric.java
@@ -0,0 +1,157 @@
+/**
+ * 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.sentry.cli.tools;
+
+import com.google.common.collect.Sets;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.provider.common.AuthorizationComponent;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClientFactory;
+import org.apache.sentry.cli.tools.command.GenericShellCommand;
+import org.apache.sentry.provider.db.generic.tools.GenericPrivilegeConverter;
+import org.apache.sentry.provider.db.generic.tools.TSentryPrivilegeConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * SentryShellGeneric is an admin tool, and responsible for the management of repository.
+ * The following commands are supported:
+ * create role, drop role, add group to role, grant privilege to role,
+ * revoke privilege from role, list roles, list privilege for role.
+ */
+public class SentryShellGeneric extends SentryShellCommon {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellGeneric.class);
+  private static final String KAFKA_SERVICE_NAME = "sentry.service.client.kafka.service.name";
+  private static final String SOLR_SERVICE_NAME = "sentry.service.client.solr.service.name";
+  private static final String SQOOP_SERVICE_NAME = "sentry.service.client.sqoop.service.name";
+
+  @Override
+  public void run() throws Exception {
+    String component = getComponent();
+    Configuration conf = getSentryConf();
+
+    String service = getService(conf);
+    try (SentryGenericServiceClient client =
+                SentryGenericServiceClientFactory.create(conf)) {
+      UserGroupInformation ugi = UserGroupInformation.getLoginUser();
+      String requestorName = ugi.getShortUserName();
+      TSentryPrivilegeConverter converter = getPrivilegeConverter(component, service);
+      ShellCommand command = new GenericShellCommand(client, component, service, converter);
+
+      // check the requestor name
+      if (StringUtils.isEmpty(requestorName)) {
+        // The exception message will be recorded in log file.
+        throw new Exception("The requestor name is empty.");
+      }
+
+      if (isCreateRole) {
+        command.createRole(requestorName, roleName);
+      } else if (isDropRole) {
+        command.dropRole(requestorName, roleName);
+      } else if (isAddRoleGroup) {
+        Set<String> groups = Sets.newHashSet(groupName.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+        command.grantRoleToGroups(requestorName, roleName, groups);
+      } else if (isDeleteRoleGroup) {
+        Set<String> groups = Sets.newHashSet(groupName.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+        command.revokeRoleFromGroups(requestorName, roleName, groups);
+      } else if (isGrantPrivilegeRole) {
+        command.grantPrivilegeToRole(requestorName, roleName, privilegeStr);
+      } else if (isRevokePrivilegeRole) {
+        command.revokePrivilegeFromRole(requestorName, roleName, privilegeStr);
+      } else if (isListRole) {
+        List<String> roles = command.listRoles(requestorName, groupName);
+        for (String role : roles) {
+          System.out.println(role);
+        }
+      } else if (isListPrivilege) {
+        List<String> privileges = command.listPrivileges(requestorName, roleName);
+        for (String privilege : privileges) {
+          System.out.println(privilege);
+        }
+      } else if (isListGroup) {
+        List<String> groups = command.listGroupRoles(requestorName);
+        for (String group : groups) {
+          System.out.println(group);
+        }
+      }
+    }
+  }
+
+  protected GenericPrivilegeConverter getPrivilegeConverter(String component, String service) {
+    return new GenericPrivilegeConverter(component, service);
+  }
+
+  protected String getComponent() throws Exception {
+    if (type == TYPE.kafka) {
+      return AuthorizationComponent.KAFKA;
+    } else if (type == TYPE.solr) {
+      return "SOLR";
+    } else if (type == TYPE.sqoop) {
+      return AuthorizationComponent.SQOOP;
+    }
+
+    throw new Exception("Invalid type specified for SentryShellGeneric: " + type);
+  }
+
+  protected String getService(Configuration conf) throws Exception {
+    if (type == TYPE.kafka) {
+      return conf.get(KAFKA_SERVICE_NAME, AuthorizationComponent.KAFKA);
+    } else if (type == TYPE.solr) {
+      return conf.get(SOLR_SERVICE_NAME, "service1");
+    } else if (type == TYPE.sqoop) {
+      return conf.get(SQOOP_SERVICE_NAME, "sqoopServer1");
+    }
+
+    throw new Exception("Invalid type specified for SentryShellGeneric: " + type);
+  }
+
+  private Configuration getSentryConf() {
+    Configuration conf = new Configuration();
+    conf.addResource(new Path(confPath), true);
+    return conf;
+  }
+
+  public static void main(String[] args) throws Exception {
+    SentryShellGeneric sentryShell = new SentryShellGeneric();
+    try {
+      sentryShell.executeShell(args);
+    } catch (Exception e) {
+      LOGGER.error(e.getMessage(), e);
+      Throwable current = e;
+      // find the first printable message;
+      while (current != null && current.getMessage() == null) {
+        current = current.getCause();
+      }
+      String error = "";
+      if (current != null && current.getMessage() != null) {
+        error = "Message: " + current.getMessage();
+      }
+      System.out.println("The operation failed. " + error);
+      System.exit(1);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellHive.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellHive.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellHive.java
new file mode 100644
index 0000000..884ed91
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellHive.java
@@ -0,0 +1,118 @@
+/**
+ * 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.sentry.cli.tools;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.cli.tools.command.hive.*;
+import org.apache.sentry.service.thrift.SentryServiceClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+/**
+ * SentryShellHive is an admin tool, and responsible for the management of repository.
+ * The following function are supported:
+ * create role, drop role, add group to role, delete group from role, grant privilege to role,
+ * revoke privilege from role, list roles for group, list privilege for role.
+ */
+public class SentryShellHive extends SentryShellCommon {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellHive.class);
+
+  public void run() throws Exception {
+
+    try(SentryPolicyServiceClient client =
+                SentryServiceClientFactory.create(getSentryConf())) {
+      UserGroupInformation ugi = UserGroupInformation.getLoginUser();
+      String requestorName = ugi.getShortUserName();
+      ShellCommand command = new HiveShellCommand(client);
+
+      // check the requestor name
+      if (StringUtils.isEmpty(requestorName)) {
+        // The exception message will be recorded in the log file.
+        throw new Exception("The requestor name is empty.");
+      }
+
+      if (isCreateRole) {
+        command.createRole(requestorName, roleName);
+      } else if (isDropRole) {
+        command.dropRole(requestorName, roleName);
+      } else if (isAddRoleGroup) {
+        Set<String> groups = Sets.newHashSet(groupName.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+        command.grantRoleToGroups(requestorName, roleName, groups);
+      } else if (isDeleteRoleGroup) {
+        Set<String> groups = Sets.newHashSet(groupName.split(SentryShellCommon.GROUP_SPLIT_CHAR));
+        command.revokeRoleFromGroups(requestorName, roleName, groups);
+      } else if (isGrantPrivilegeRole) {
+        command.grantPrivilegeToRole(requestorName, roleName, privilegeStr);
+      } else if (isRevokePrivilegeRole) {
+        command.revokePrivilegeFromRole(requestorName, roleName, privilegeStr);
+      } else if (isListRole) {
+        List<String> roles = command.listRoles(requestorName, groupName);
+        for (String role : roles) {
+          System.out.println(role);
+        }
+      } else if (isListPrivilege) {
+        List<String> privileges = command.listPrivileges(requestorName, roleName);
+        for (String privilege : privileges) {
+          System.out.println(privilege);
+        }
+      } else if (isListGroup) {
+        List<String> groups = command.listGroupRoles(requestorName);
+        for (String group : groups) {
+          System.out.println(group);
+        }
+      }
+    }
+  }
+
+  private Configuration getSentryConf() {
+    Configuration conf = new Configuration();
+    conf.addResource(new Path(confPath), true);
+    return conf;
+  }
+
+  public static void main(String[] args) throws Exception {
+    SentryShellHive sentryShell = new SentryShellHive();
+    try {
+      sentryShell.executeShell(args);
+    } catch (Exception e) {
+      LOGGER.error(e.getMessage(), e);
+      Throwable current =  e;
+      // find the first printable message;
+      while (current != null && current.getMessage() == null) {
+        current = current.getCause();
+      }
+
+      if (current != null) {
+        System.out.println("The operation failed." +
+           (current.getMessage() == null ? "" : "  Message: " + current.getMessage()));
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellIndexer.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellIndexer.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellIndexer.java
new file mode 100644
index 0000000..c7f854f
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/SentryShellIndexer.java
@@ -0,0 +1,124 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.sentry.cli.tools;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.hadoop.conf.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.sentry.provider.common.AuthorizationComponent.HBASE_INDEXER;
+import static org.apache.sentry.service.thrift.ServiceConstants.ClientConfig.SERVICE_NAME;
+
+/**
+ * SentryShellIndexer is an admin tool, and responsible for the management of repository.
+ * The following commands are supported:
+ * create role, drop role, add group to role, grant privilege to role,
+ * revoke privilege from role, list roles, list privilege for role.
+ */
+public class SentryShellIndexer extends SentryShellGeneric {
+
+  protected boolean isMigration = false;
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(SentryShellIndexer.class);
+
+  private final SentryConfigToolIndexer configTool = new SentryConfigToolIndexer();
+
+  @Override
+  protected void setupOptions(Options simpleShellOptions) {
+    super.setupOptions(simpleShellOptions);
+    configTool.setupOptions(simpleShellOptions);
+  }
+
+  @Override
+  protected void parseOptions(CommandLine cmd) throws ParseException {
+    super.parseOptions(cmd);
+    configTool.parseOptions(cmd);
+    for (Option opt : cmd.getOptions()) {
+      if (opt.getOpt().equals("mgr")) {
+        isMigration = true;
+      }
+    }
+  }
+
+  @Override
+  protected OptionGroup getMainOptions() {
+    OptionGroup mainOptions = super.getMainOptions();
+    Option mgrOpt = new Option("mgr", "migrate", false, "Migrate ini file to Sentry service");
+    mgrOpt.setRequired(false);
+    mainOptions.addOption(mgrOpt);
+    return mainOptions;
+  }
+
+  /**
+   * Processes the necessary command based on the arguments parsed earlier.
+   * @throws Exception
+   */
+  @Override
+  public void run() throws Exception {
+
+    if (isMigration) {
+      configTool.run();
+      return;
+    }
+
+    super.run();
+  }
+
+  @Override
+  protected String getComponent() throws Exception {
+    return HBASE_INDEXER;
+  }
+
+  @Override
+  protected String getService(Configuration conf) throws Exception {
+    String service = conf.get(SERVICE_NAME, serviceName);
+    if (service == null) {
+      throw new IllegalArgumentException("Service was not defined. Please, use -s command option, or sentry.provider.backend.generic.service-name configuration entry.");
+    }
+    return service;
+  }
+
+  /**
+   * Entry-point for Hbase indexer cli tool.
+   * @param args
+   * @throws Exception
+   */
+  public static void main(String[] args) throws Exception {
+    SentryShellIndexer sentryShell = new SentryShellIndexer();
+    try {
+      sentryShell.executeShell(args);
+    } catch (Exception e) {
+      LOGGER.error(e.getMessage(), e);
+      Throwable current = e;
+      // find the first printable message;
+      while (current != null && current.getMessage() == null) {
+        current = current.getCause();
+      }
+      System.out.println("The operation failed." +
+              (current.getMessage() == null ? "" : "  Message: " + current.getMessage()));
+      System.exit(1);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/ShellCommand.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/ShellCommand.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/ShellCommand.java
new file mode 100644
index 0000000..9a141c3
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/ShellCommand.java
@@ -0,0 +1,47 @@
+/**
+ * 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.sentry.cli.tools;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.sentry.core.common.exception.SentryUserException;
+
+/**
+ * The interface for all admin commands, eg, CreateRoleCmd. It is independent of the underlying mechanism (i.e. Generic or Hive)
+ */
+public interface ShellCommand {
+
+  void createRole(String requestorName, String roleName) throws SentryUserException;
+
+  void dropRole(String requestorName, String roleName) throws SentryUserException;
+
+  void grantPrivilegeToRole(String requestorName, String roleName, String privilege) throws SentryUserException;
+
+  void grantRoleToGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException;
+
+  void revokePrivilegeFromRole(String requestorName, String roleName, String privilege) throws SentryUserException;
+
+  void revokeRoleFromGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException;
+
+  List<String> listRoles(String requestorName, String group) throws SentryUserException;
+
+  List<String> listPrivileges(String requestorName, String roleName) throws SentryUserException;
+
+  List<String> listGroupRoles(String requestorName) throws SentryUserException;
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/GenericShellCommand.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/GenericShellCommand.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/GenericShellCommand.java
new file mode 100644
index 0000000..3e0da50
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/GenericShellCommand.java
@@ -0,0 +1,156 @@
+/**
+ * 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.sentry.cli.tools.command;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole;
+import org.apache.sentry.cli.tools.ShellCommand;
+import org.apache.sentry.provider.db.generic.tools.TSentryPrivilegeConverter;
+
+/**
+ * The ShellCommand implementation for the Generic clients
+ */
+public class GenericShellCommand implements ShellCommand {
+
+  private final SentryGenericServiceClient client;
+  private final String component;
+  private final TSentryPrivilegeConverter converter;
+  private final String serviceName;
+
+  public GenericShellCommand(SentryGenericServiceClient client, String component, String serviceName,
+                             TSentryPrivilegeConverter converter) {
+    this.client = client;
+    this.component = component;
+    this.serviceName = serviceName;
+    this.converter = converter;
+  }
+
+  public void createRole(String requestorName, String roleName) throws SentryUserException {
+    client.createRole(requestorName, roleName, component);
+  }
+
+  public void dropRole(String requestorName, String roleName) throws SentryUserException {
+    client.dropRole(requestorName, roleName, component);
+  }
+
+  public void grantPrivilegeToRole(String requestorName, String roleName, String privilege) throws SentryUserException {
+    TSentryPrivilege sentryPrivilege = converter.fromString(privilege);
+    client.grantPrivilege(requestorName, roleName, component, sentryPrivilege);
+  }
+
+  public void grantRoleToGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException {
+    client.grantRoleToGroups(requestorName, roleName, component, groups);
+  }
+
+  public void revokePrivilegeFromRole(String requestorName, String roleName, String privilege) throws SentryUserException {
+    TSentryPrivilege sentryPrivilege = converter.fromString(privilege);
+    client.revokePrivilege(requestorName, roleName, component, sentryPrivilege);
+  }
+
+  public void revokeRoleFromGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException {
+    client.revokeRoleFromGroups(requestorName, roleName, component, groups);
+  }
+
+  public List<String> listRoles(String requestorName, String group) throws SentryUserException {
+    Set<TSentryRole> roles;
+    if (StringUtils.isEmpty(group)) {
+      roles = client.listAllRoles(requestorName, component);
+    } else {
+      roles = client.listRolesByGroupName(requestorName, group, component);
+    }
+
+    List<String> result = new ArrayList<>();
+    if (roles != null) {
+      for (TSentryRole role : roles) {
+        result.add(role.getRoleName());
+      }
+    }
+
+    return result;
+  }
+
+  public List<String> listPrivileges(String requestorName, String roleName) throws SentryUserException {
+    Set<TSentryPrivilege> privileges = client
+        .listAllPrivilegesByRoleName(requestorName, roleName, component, serviceName);
+
+    List<String> result = new ArrayList<>();
+    if (privileges != null) {
+      for (TSentryPrivilege privilege : privileges) {
+        String privilegeStr = converter.toString(privilege);
+        result.add(privilegeStr);
+      }
+    }
+
+    return result;
+  }
+
+  public List<String> listGroupRoles(String requestorName) throws SentryUserException {
+    Set<TSentryRole> roles = client.listAllRoles(requestorName, component);
+    if (roles == null || roles.isEmpty()) {
+      return Collections.emptyList();
+    }
+
+    // Set of all group names
+    Set<String> groupNames = new HashSet<>();
+
+    // Map group to set of roles
+    Map<String, Set<String>> groupInfo = new HashMap<>();
+
+    // Get all group names
+    for (TSentryRole role: roles) {
+      for (String group : role.getGroups()) {
+        groupNames.add(group);
+        Set<String> groupRoles = groupInfo.get(group);
+        if (groupRoles != null) {
+          // Add a new or existing role
+          groupRoles.add(role.getRoleName());
+          continue;
+        }
+        // Never seen this group before
+        groupRoles = new HashSet<>();
+        groupRoles.add(role.getRoleName());
+        groupInfo.put(group, groupRoles);
+      }
+    }
+
+    List<String> groups = new ArrayList<>(groupNames);
+
+    // Produce printable result as
+    // group1 = role1, role2, ...
+    // group2 = ...
+    List<String> result = new LinkedList<>();
+    for (String groupName: groups) {
+      result.add(groupName + " = " + StringUtils.join(groupInfo.get(groupName), ", "));
+    }
+
+    return result;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/CommandUtil.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/CommandUtil.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/CommandUtil.java
new file mode 100644
index 0000000..b06732e
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/CommandUtil.java
@@ -0,0 +1,63 @@
+/**
+ * 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.sentry.cli.tools.command.hive;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.service.thrift.ServiceConstants;
+
+public final class CommandUtil {
+
+  public static final String SPLIT_CHAR = ",";
+
+  private CommandUtil() {
+    // Make constructor private to avoid instantiation
+  }
+
+  // check the privilege value for the specific privilege scope
+  // eg, for the table scope, server and database can't be empty
+  public static void validatePrivilegeHierarchy(TSentryPrivilege tSentryPrivilege) throws IllegalArgumentException {
+    String serverName = tSentryPrivilege.getServerName();
+    String dbName = tSentryPrivilege.getDbName();
+    String tableName = tSentryPrivilege.getTableName();
+    String columnName = tSentryPrivilege.getColumnName();
+    String uri = tSentryPrivilege.getURI();
+    if (ServiceConstants.PrivilegeScope.SERVER.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      if (StringUtils.isEmpty(serverName)) {
+        throw new IllegalArgumentException("The hierarchy of privilege is not correct.");
+      }
+    } else if (ServiceConstants.PrivilegeScope.URI.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      if (StringUtils.isEmpty(serverName) || StringUtils.isEmpty(uri)) {
+        throw new IllegalArgumentException("The hierarchy of privilege is not correct.");
+      }
+    } else if (ServiceConstants.PrivilegeScope.DATABASE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      if (StringUtils.isEmpty(serverName) || StringUtils.isEmpty(dbName)) {
+        throw new IllegalArgumentException("The hierarchy of privilege is not correct.");
+      }
+    } else if (ServiceConstants.PrivilegeScope.TABLE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      if (StringUtils.isEmpty(serverName) || StringUtils.isEmpty(dbName)
+              || StringUtils.isEmpty(tableName)) {
+        throw new IllegalArgumentException("The hierarchy of privilege is not correct.");
+      }
+    } else if (ServiceConstants.PrivilegeScope.COLUMN.toString().equals(tSentryPrivilege.getPrivilegeScope())
+      && (StringUtils.isEmpty(serverName) || StringUtils.isEmpty(dbName)
+              || StringUtils.isEmpty(tableName) || StringUtils.isEmpty(columnName))) {
+        throw new IllegalArgumentException("The hierarchy of privilege is not correct.");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/HiveShellCommand.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/HiveShellCommand.java b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/HiveShellCommand.java
new file mode 100644
index 0000000..1d11c3b
--- /dev/null
+++ b/sentry-tools/src/main/java/org/apache/sentry/cli/tools/command/hive/HiveShellCommand.java
@@ -0,0 +1,152 @@
+/**
+ * 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.sentry.cli.tools.command.hive;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.apache.sentry.cli.tools.ShellCommand;
+import org.apache.sentry.service.thrift.SentryServiceUtil;
+
+/**
+ * The ShellCommand implementation for Hive.
+ */
+public class HiveShellCommand implements ShellCommand {
+
+  private final SentryPolicyServiceClient client;
+
+  public HiveShellCommand(SentryPolicyServiceClient client) {
+    this.client = client;
+  }
+
+  public void createRole(String requestorName, String roleName) throws SentryUserException {
+    client.createRole(requestorName, roleName);
+  }
+
+  public void dropRole(String requestorName, String roleName) throws SentryUserException {
+    client.dropRole(requestorName, roleName);
+  }
+
+  public void grantPrivilegeToRole(String requestorName, String roleName, String privilege) throws SentryUserException {
+    TSentryPrivilege tSentryPrivilege = SentryServiceUtil.convertToTSentryPrivilege(privilege);
+    CommandUtil.validatePrivilegeHierarchy(tSentryPrivilege);
+    client.grantPrivilege(requestorName, roleName, tSentryPrivilege);
+  }
+
+  public void grantRoleToGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException {
+    client.grantRoleToGroups(requestorName, roleName, groups);
+  }
+
+  public void revokePrivilegeFromRole(String requestorName, String roleName, String privilege) throws SentryUserException {
+    TSentryPrivilege tSentryPrivilege = SentryServiceUtil.convertToTSentryPrivilege(privilege);
+    CommandUtil.validatePrivilegeHierarchy(tSentryPrivilege);
+    client.revokePrivilege(requestorName, roleName, tSentryPrivilege);
+  }
+
+  public void revokeRoleFromGroups(String requestorName, String roleName, Set<String> groups) throws SentryUserException {
+    client.revokeRoleFromGroups(requestorName, roleName, groups);
+  }
+
+  public List<String> listRoles(String requestorName, String group) throws SentryUserException {
+    Set<TSentryRole> roles;
+    if (StringUtils.isEmpty(group)) {
+      roles = client.listAllRoles(requestorName);
+    } else {
+      roles = client.listRolesByGroupName(requestorName, group);
+    }
+
+    List<String> result = new ArrayList<>();
+    if (roles != null) {
+      for (TSentryRole role : roles) {
+        result.add(role.getRoleName());
+      }
+    }
+
+    return result;
+  }
+
+  public List<String> listPrivileges(String requestorName, String roleName) throws SentryUserException {
+    Set<TSentryPrivilege> privileges = client
+        .listAllPrivilegesByRoleName(requestorName, roleName);
+
+    List<String> result = new ArrayList<>();
+    if (privileges != null) {
+      for (TSentryPrivilege privilege : privileges) {
+        String privilegeStr = SentryServiceUtil.convertTSentryPrivilegeToStr(privilege);
+        result.add(privilegeStr);
+      }
+    }
+    return result;
+  }
+
+  public List<String> listGroupRoles(String requestorName) throws SentryUserException {
+    Set<TSentryRole> roles = client.listAllRoles(requestorName);
+    if (roles == null || roles.isEmpty()) {
+      return Collections.emptyList();
+    }
+
+    // Set of all group names
+    Set<String> groupNames = new HashSet<>();
+
+    // Map group to set of roles
+    Map<String, Set<String>> groupInfo = new HashMap<>();
+
+    // Get all group names
+    for (TSentryRole role: roles) {
+      for (TSentryGroup group : role.getGroups()) {
+        String groupName = group.getGroupName();
+        groupNames.add(groupName);
+        Set<String> groupRoles = groupInfo.get(groupName);
+        if (groupRoles != null) {
+          // Add a new or existing role
+          groupRoles.add(role.getRoleName());
+          continue;
+        }
+        // Never seen this group before
+        groupRoles = new HashSet<>();
+        groupRoles.add(role.getRoleName());
+        groupInfo.put(groupName, groupRoles);
+      }
+    }
+
+    List<String> groups = new ArrayList<>(groupNames);
+
+    // Produce printable result as
+    // group1 = role1, role2, ...
+    // group2 = ...
+    List<String> result = new LinkedList<>();
+    for (String groupName: groups) {
+      result.add(groupName + " = " + StringUtils.join(groupInfo.get(groupName), ", "));
+    }
+
+    return result;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/shell/GroupShell.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/shell/GroupShell.java b/sentry-tools/src/main/java/org/apache/sentry/shell/GroupShell.java
index b7652a5..863f992 100644
--- a/sentry-tools/src/main/java/org/apache/sentry/shell/GroupShell.java
+++ b/sentry-tools/src/main/java/org/apache/sentry/shell/GroupShell.java
@@ -23,7 +23,7 @@ import com.budhash.cliche.Shell;
 import com.budhash.cliche.ShellDependent;
 
 import org.apache.sentry.core.common.exception.SentryUserException;
-import org.apache.sentry.provider.db.tools.ShellCommand;
+import org.apache.sentry.cli.tools.ShellCommand;
 
 import java.util.Arrays;
 import java.util.Collections;

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/shell/PrivsShell.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/shell/PrivsShell.java b/sentry-tools/src/main/java/org/apache/sentry/shell/PrivsShell.java
index 8b8898f..3ff6737 100644
--- a/sentry-tools/src/main/java/org/apache/sentry/shell/PrivsShell.java
+++ b/sentry-tools/src/main/java/org/apache/sentry/shell/PrivsShell.java
@@ -24,7 +24,7 @@ import com.budhash.cliche.Shell;
 import com.budhash.cliche.ShellDependent;
 
 import org.apache.sentry.core.common.exception.SentryUserException;
-import org.apache.sentry.provider.db.tools.ShellCommand;
+import org.apache.sentry.cli.tools.ShellCommand;
 
 import java.util.Collections;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/shell/RolesShell.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/shell/RolesShell.java b/sentry-tools/src/main/java/org/apache/sentry/shell/RolesShell.java
index c014a30..42bce19 100644
--- a/sentry-tools/src/main/java/org/apache/sentry/shell/RolesShell.java
+++ b/sentry-tools/src/main/java/org/apache/sentry/shell/RolesShell.java
@@ -24,7 +24,7 @@ import com.budhash.cliche.Shell;
 import com.budhash.cliche.ShellDependent;
 
 import org.apache.sentry.core.common.exception.SentryUserException;
-import org.apache.sentry.provider.db.tools.ShellCommand;
+import org.apache.sentry.cli.tools.ShellCommand;
 
 import java.util.Collections;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/sentry/blob/6752f14a/sentry-tools/src/main/java/org/apache/sentry/shell/TopLevelShell.java
----------------------------------------------------------------------
diff --git a/sentry-tools/src/main/java/org/apache/sentry/shell/TopLevelShell.java b/sentry-tools/src/main/java/org/apache/sentry/shell/TopLevelShell.java
index d9952a9..04d65bd 100644
--- a/sentry-tools/src/main/java/org/apache/sentry/shell/TopLevelShell.java
+++ b/sentry-tools/src/main/java/org/apache/sentry/shell/TopLevelShell.java
@@ -22,11 +22,11 @@ import org.apache.sentry.core.common.exception.SentryUserException;
 import org.apache.sentry.provider.common.AuthorizationComponent;
 import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceClient;
 import org.apache.sentry.provider.db.generic.tools.GenericPrivilegeConverter;
-import org.apache.sentry.provider.db.generic.tools.command.GenericShellCommand;
-import org.apache.sentry.provider.db.generic.tools.command.TSentryPrivilegeConverter;
+import org.apache.sentry.cli.tools.command.GenericShellCommand;
+import org.apache.sentry.provider.db.generic.tools.TSentryPrivilegeConverter;
 import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
-import org.apache.sentry.provider.db.tools.ShellCommand;
-import org.apache.sentry.provider.db.tools.command.hive.HiveShellCommand;
+import org.apache.sentry.cli.tools.ShellCommand;
+import org.apache.sentry.cli.tools.command.hive.HiveShellCommand;
 
 import com.budhash.cliche.Command;
 import com.budhash.cliche.Param;