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 2016/01/04 07:13:23 UTC

incubator-sentry git commit: SENTRY-749: Create simple shell for sentry(Colin Ma, reviewed by Hao Hao, Gregory Chanan, Lenni Kuff)

Repository: incubator-sentry
Updated Branches:
  refs/heads/master a661c1828 -> 0adfc7384


SENTRY-749: Create simple shell for sentry(Colin Ma, reviewed by Hao Hao, Gregory Chanan, Lenni Kuff)


Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/0adfc738
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/0adfc738
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/0adfc738

Branch: refs/heads/master
Commit: 0adfc7384f531f93ff0a5d2a0b1470876fc10855
Parents: a661c18
Author: Colin Ma <co...@apache.org>
Authored: Mon Jan 4 14:56:50 2016 +0800
Committer: Colin Ma <co...@apache.org>
Committed: Mon Jan 4 14:56:50 2016 +0800

----------------------------------------------------------------------
 bin/sentryShell                                 |  71 +++
 .../provider/db/tools/SentryShellCommon.java    | 242 ++++++++
 .../provider/db/tools/SentryShellHive.java      |  92 +++
 .../provider/db/tools/command/hive/Command.java |  27 +
 .../db/tools/command/hive/CommandUtil.java      | 114 ++++
 .../db/tools/command/hive/CreateRoleCmd.java    |  37 ++
 .../db/tools/command/hive/DropRoleCmd.java      |  37 ++
 .../command/hive/GrantPrivilegeToRoleCmd.java   |  61 ++
 .../command/hive/GrantRoleToGroupsCmd.java      |  43 ++
 .../tools/command/hive/ListPrivilegesCmd.java   |  97 +++
 .../db/tools/command/hive/ListRolesCmd.java     |  51 ++
 .../hive/RevokePrivilegeFromRoleCmd.java        |  62 ++
 .../command/hive/RevokeRoleFromGroupsCmd.java   |  43 ++
 .../provider/db/tools/TestSentryShellHive.java  | 583 +++++++++++++++++++
 .../thrift/SentryServiceIntegrationBase.java    |   6 -
 15 files changed, 1560 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/bin/sentryShell
----------------------------------------------------------------------
diff --git a/bin/sentryShell b/bin/sentryShell
new file mode 100755
index 0000000..d6e8055
--- /dev/null
+++ b/bin/sentryShell
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# 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.
+
+bin=`dirname "$0"`
+myhome=`cd "$bin/.."; pwd`
+
+if [[ -z $SENTRY_HOME ]] ; then
+  export SENTRY_HOME=$myhome
+fi
+
+# check for hadoop in the path
+HADOOP_IN_PATH=`which hadoop 2>/dev/null`
+if [ -f ${HADOOP_IN_PATH} ]; then
+  HADOOP_DIR=`dirname "$HADOOP_IN_PATH"`/..
+fi
+# HADOOP_HOME env variable overrides hadoop in the path
+HADOOP_HOME=${HADOOP_HOME:-${HADOOP_PREFIX:-$HADOOP_DIR}}
+if [ "$HADOOP_HOME" == "" ]; then
+  echo "Cannot find hadoop installation: \$HADOOP_HOME or \$HADOOP_PREFIX must be set or hadoop must be in the path";
+  exit 4;
+fi
+
+HADOOP=$HADOOP_HOME/bin/hadoop
+if [ ! -f ${HADOOP} ]; then
+  echo "Cannot find hadoop installation: \$HADOOP_HOME or \$HADOOP_PREFIX must be set or hadoop must be in the path";
+  exit 4;
+fi
+
+export _CMD_JAR=${SENTRY_SHELL_JAR}:sentry-provider-db-*.jar
+for f in ${SENTRY_HOME}/lib/*.jar; do
+  HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:${f}
+done
+export HADOOP_CLASSPATH
+
+for f in ${SENTRY_HOME}/lib/server/*.jar; do
+  HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:${f}
+done
+for f in ${SENTRY_HOME}/lib/plugins/*.jar; do
+  HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:${f}
+done
+
+args=()
+# get the type argument for the command, and check use the shell for hive model or for generic model.
+# todo: currently, supoort hive only, need add generic model support
+while [ $# -gt 0 ]; do    # Until you run out of parameters . . .
+  if [[ "$1" = "-t" || "$1" = "--type" ]]; then
+    # currently, only support the hive model
+    if ! [[ $2 =~ ^[H|h][I|i][V|v][E|e]$ ]]; then
+      echo "Doesn't support the type $2!"
+      exit 1
+    fi
+  fi
+  args+=" $1"
+  shift
+done
+
+exec $HADOOP jar ${SENTRY_HOME}/lib/${_CMD_JAR} org.apache.sentry.SentryShellHive ${args[@]}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java
new file mode 100644
index 0000000..b1353c5
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellCommon.java
@@ -0,0 +1,242 @@
+/**
+ * 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.provider.db.tools;
+
+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 {
+
+  protected String roleName;
+  protected String groupName;
+  protected String privilegeStr;
+  protected String confPath;
+  // flag for the command
+  protected boolean isCreateRole = false;
+  protected boolean isDropRole = false;
+  protected boolean isAddRoleGroup = false;
+  protected boolean isDeleteRoleGroup = false;
+  protected boolean isGrantPrivilegeRole = false;
+  protected boolean isRevokePrivilegeRole = false;
+  protected boolean isListRole = false;
+  protected boolean isListPrivilege = false;
+  protected boolean isPrintHelp = false;
+  // flag for the parameter check
+  protected boolean roleNameRequired = false;
+  protected boolean groupNameRequired = false;
+  protected boolean privilegeStrRequired = false;
+
+  public final static String OPTION_DESC_HELP = "Shell usage";
+  public final static String OPTION_DESC_CONF = "sentry-site file path";
+  public final static String OPTION_DESC_ROLE_NAME = "Role name";
+  public final static String OPTION_DESC_GROUP_NAME = "Group name";
+  public final static String OPTION_DESC_PRIVILEGE = "Privilege string";
+  public final static String PREFIX_MESSAGE_MISSING_OPTION = "Missing required option: ";
+
+  /**
+   * 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 group to role
+   *   -drg,--delete_role_group     -r <rolename>  -g <groupname> delete group from role
+   *   -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
+   *   -t,--type                    <typeame>                     the shell for hive model or generic model
+   * </pre>
+   *
+   * @param args
+   */
+  protected boolean parseArgs(String[] args) {
+    Options simpleShellOptions = new Options();
+
+    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 group to role");
+    argOpt.setRequired(false);
+
+    Option drgOpt = new Option("drg", "delete_role_group", false, "Delete group from role");
+    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);
+
+    // required args group
+    OptionGroup simpleShellOptGroup = new OptionGroup();
+    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.setRequired(true);
+    simpleShellOptions.addOptionGroup(simpleShellOptGroup);
+
+    // 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 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);
+
+    // 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);
+
+      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("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("conf")) {
+          confPath = opt.getValue();
+        }
+      }
+      checkRequiredParameter(roleNameRequired, roleName, OPTION_DESC_ROLE_NAME);
+      checkRequiredParameter(groupNameRequired, groupName, OPTION_DESC_GROUP_NAME);
+      checkRequiredParameter(privilegeStrRequired, privilegeStr, OPTION_DESC_PRIVILEGE);
+    } catch (ParseException pe) {
+      System.out.println(pe.getMessage());
+      usage(simpleShellOptions);
+      return false;
+    }
+    return true;
+  }
+
+  private 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
+  abstract void run() throws Exception;
+
+  protected 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/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellHive.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellHive.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellHive.java
new file mode 100644
index 0000000..80c8442
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/SentryShellHive.java
@@ -0,0 +1,92 @@
+/**
+ * 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.provider.db.tools;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.tools.command.hive.*;
+import org.apache.sentry.service.thrift.SentryServiceClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 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 {
+    Command command = null;
+    String requestorName = System.getProperty("user.name", "");
+    SentryPolicyServiceClient client = SentryServiceClientFactory.create(getSentryConf());
+
+    if (isCreateRole) {
+      command = new CreateRoleCmd(roleName);
+    } else if (isDropRole) {
+      command = new DropRoleCmd(roleName);
+    } else if (isAddRoleGroup) {
+      command = new GrantRoleToGroupsCmd(roleName, groupName);
+    } else if (isDeleteRoleGroup) {
+      command = new RevokeRoleFromGroupsCmd(roleName, groupName);
+    } else if (isGrantPrivilegeRole) {
+      command = new GrantPrivilegeToRoleCmd(roleName, privilegeStr);
+    } else if (isRevokePrivilegeRole) {
+      command = new RevokePrivilegeFromRoleCmd(roleName, privilegeStr);
+    } else if (isListRole) {
+      command = new ListRolesCmd(groupName);
+    } else if (isListPrivilege) {
+      command = new ListPrivilegesCmd(roleName);
+    }
+
+    // check the requestor name
+    if (StringUtils.isEmpty(requestorName)) {
+      // The exception message will be recoreded in log file.
+      throw new Exception("The requestor name is empty.");
+    }
+
+    if (command != null) {
+      command.execute(client, requestorName);
+    }
+  }
+
+  private Configuration getSentryConf() {
+    Configuration conf = new Configuration();
+    conf.addResource(new Path(confPath));
+    return conf;
+  }
+
+  public static void main(String[] args) throws Exception {
+    SentryShellHive sentryShell = new SentryShellHive();
+    try {
+      if (sentryShell.executeShell(args)) {
+        System.out.println("The operation is compeleted successfully.");
+      }
+    } catch (Exception e) {
+      LOGGER.error(e.getMessage(), e);
+      System.out.println("The operation is failed, please refer to log file for the root cause.");
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/Command.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/Command.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/Command.java
new file mode 100644
index 0000000..ae9809a
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/Command.java
@@ -0,0 +1,27 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+/**
+ * The interface for all admin commands, eg, CreateRoleCmd.
+ */
+public interface Command {
+  abstract void execute(SentryPolicyServiceClient client, String requestorName) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CommandUtil.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CommandUtil.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CommandUtil.java
new file mode 100644
index 0000000..0a73d9f
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CommandUtil.java
@@ -0,0 +1,114 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.provider.common.KeyValue;
+import org.apache.sentry.provider.common.PolicyFileConstants;
+import org.apache.sentry.provider.common.ProviderConstants;
+import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.service.thrift.ServiceConstants;
+
+public class CommandUtil {
+
+  public static final String SPLIT_CHAR = ",";
+
+  // parse the privilege in String and get the TSentryPrivilege as result
+  public static TSentryPrivilege convertToTSentryPrivilege(String privilegeStr) throws Exception {
+    TSentryPrivilege tSentryPrivilege = new TSentryPrivilege();
+    for (String authorizable : ProviderConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) {
+      KeyValue tempKV = new KeyValue(authorizable);
+      String key = tempKV.getKey();
+      String value = tempKV.getValue();
+
+      if (PolicyFileConstants.PRIVILEGE_SERVER_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setServerName(value);
+      } else if (PolicyFileConstants.PRIVILEGE_DATABASE_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setDbName(value);
+      } else if (PolicyFileConstants.PRIVILEGE_TABLE_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setTableName(value);
+      } else if (PolicyFileConstants.PRIVILEGE_COLUMN_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setColumnName(value);
+      } else if (PolicyFileConstants.PRIVILEGE_URI_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setURI(value);
+      } else if (PolicyFileConstants.PRIVILEGE_ACTION_NAME.equalsIgnoreCase(key)) {
+        tSentryPrivilege.setAction(value);
+      } else if (PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME.equalsIgnoreCase(key)) {
+        TSentryGrantOption grantOption = "true".equalsIgnoreCase(value) ? TSentryGrantOption.TRUE
+                : TSentryGrantOption.FALSE;
+        tSentryPrivilege.setGrantOption(grantOption);
+      }
+    }
+    tSentryPrivilege.setPrivilegeScope(getPrivilegeScope(tSentryPrivilege));
+    validatePrivilegeHierarchy(tSentryPrivilege);
+    return tSentryPrivilege;
+  }
+
+  // for the different hierarchy for hive:
+  // 1: server->url
+  // 2: server->database->table->column
+  // if both of them are found in the privilege string, the privilege scope will be set as
+  // PrivilegeScope.URI
+  private static String getPrivilegeScope(TSentryPrivilege tSentryPrivilege) {
+    ServiceConstants.PrivilegeScope privilegeScope = ServiceConstants.PrivilegeScope.SERVER;
+    if (!StringUtils.isEmpty(tSentryPrivilege.getURI())) {
+      privilegeScope = ServiceConstants.PrivilegeScope.URI;
+    } else if (!StringUtils.isEmpty(tSentryPrivilege.getColumnName())) {
+      privilegeScope = ServiceConstants.PrivilegeScope.COLUMN;
+    } else if (!StringUtils.isEmpty(tSentryPrivilege.getTableName())) {
+      privilegeScope = ServiceConstants.PrivilegeScope.TABLE;
+    } else if (!StringUtils.isEmpty(tSentryPrivilege.getDbName())) {
+      privilegeScope = ServiceConstants.PrivilegeScope.DATABASE;
+    }
+    return privilegeScope.toString();
+  }
+
+  // check the privilege value for the specific privilege scope
+  // eg, for the table scope, server and database can't be empty
+  private static void validatePrivilegeHierarchy(TSentryPrivilege tSentryPrivilege) throws Exception {
+    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())) {
+      if (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/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CreateRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CreateRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CreateRoleCmd.java
new file mode 100644
index 0000000..5a4834a
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/CreateRoleCmd.java
@@ -0,0 +1,37 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+/**
+ * The class for admin command to create role.
+ */
+public class CreateRoleCmd implements Command {
+
+  private String roleName;
+
+  public CreateRoleCmd(String roleName) {
+    this.roleName = roleName;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    client.createRole(requestorName, roleName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/DropRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/DropRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/DropRoleCmd.java
new file mode 100644
index 0000000..facec0e
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/DropRoleCmd.java
@@ -0,0 +1,37 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+/**
+ * The class for admin command to drop role.
+ */
+public class DropRoleCmd implements Command {
+
+  private String roleName;
+
+  public DropRoleCmd(String roleName) {
+    this.roleName = roleName;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    client.dropRole(requestorName, roleName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantPrivilegeToRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantPrivilegeToRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantPrivilegeToRoleCmd.java
new file mode 100644
index 0000000..a1ef2f9
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantPrivilegeToRoleCmd.java
@@ -0,0 +1,61 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.service.thrift.ServiceConstants;
+
+/**
+ * The class for admin command to grant privilege to role.
+ */
+public class GrantPrivilegeToRoleCmd implements Command {
+
+  private String roleName;
+  private String privilegeStr;
+
+  public GrantPrivilegeToRoleCmd(String roleName, String privilegeStr) {
+    this.roleName = roleName;
+    this.privilegeStr = privilegeStr;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    TSentryPrivilege tSentryPrivilege = CommandUtil.convertToTSentryPrivilege(privilegeStr);
+    boolean grantOption = tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE) ? true : false;
+    if (ServiceConstants.PrivilegeScope.SERVER.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.grantServerPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.DATABASE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.grantDatabasePrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.TABLE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.grantTablePrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getTableName(),
+              tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.COLUMN.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.grantColumnPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getTableName(),
+              tSentryPrivilege.getColumnName(), tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.URI.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.grantURIPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getURI(), grantOption);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantRoleToGroupsCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantRoleToGroupsCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantRoleToGroupsCmd.java
new file mode 100644
index 0000000..39d3591
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/GrantRoleToGroupsCmd.java
@@ -0,0 +1,43 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import com.google.common.collect.Sets;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+import java.util.Set;
+
+/**
+ * The class for admin command to grant role to group.
+ */
+public class GrantRoleToGroupsCmd implements Command {
+
+  private String roleName;
+  private String groupNamesStr;
+
+  public GrantRoleToGroupsCmd(String roleName, String groupNamesStr) {
+    this.roleName = roleName;
+    this.groupNamesStr = groupNamesStr;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    Set<String> groups = Sets.newHashSet(groupNamesStr.split(CommandUtil.SPLIT_CHAR));
+    client.grantRoleToGroups(requestorName, roleName, groups);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListPrivilegesCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListPrivilegesCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListPrivilegesCmd.java
new file mode 100644
index 0000000..98fae95
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListPrivilegesCmd.java
@@ -0,0 +1,97 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.provider.common.PolicyFileConstants;
+import org.apache.sentry.provider.common.ProviderConstants;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The class for admin command to list privileges.
+ */
+public class ListPrivilegesCmd implements Command {
+
+  private String roleName;
+
+  public ListPrivilegesCmd(String roleName) {
+    this.roleName = roleName;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    Set<TSentryPrivilege> privileges = client
+            .listAllPrivilegesByRoleName(requestorName, roleName);
+    if (privileges != null) {
+      for (TSentryPrivilege privilege : privileges) {
+        String privilegeStr = convertToPrivilegeStr(privilege);
+        System.out.println(privilegeStr);
+      }
+    }
+  }
+
+  // convert TSentryPrivilege to privilege in string
+  private String convertToPrivilegeStr(TSentryPrivilege tSentryPrivilege) {
+    List<String> privileges = Lists.newArrayList();
+    if (tSentryPrivilege != null) {
+      String serverName = tSentryPrivilege.getServerName();
+      String dbName = tSentryPrivilege.getDbName();
+      String tableName = tSentryPrivilege.getTableName();
+      String columnName = tSentryPrivilege.getColumnName();
+      String uri = tSentryPrivilege.getURI();
+      String action = tSentryPrivilege.getAction();
+      String grantOption = (tSentryPrivilege.getGrantOption() == TSentryGrantOption.TRUE ? "true"
+              : "false");
+      if (!StringUtils.isEmpty(serverName)) {
+        privileges.add(ProviderConstants.KV_JOINER.join(PolicyFileConstants.PRIVILEGE_SERVER_NAME,
+                serverName));
+        if (!StringUtils.isEmpty(uri)) {
+          privileges.add(ProviderConstants.KV_JOINER.join(PolicyFileConstants.PRIVILEGE_URI_NAME,
+                  uri));
+        } else if (!StringUtils.isEmpty(dbName)) {
+          privileges.add(ProviderConstants.KV_JOINER.join(
+                  PolicyFileConstants.PRIVILEGE_DATABASE_NAME, dbName));
+          if (!StringUtils.isEmpty(tableName)) {
+            privileges.add(ProviderConstants.KV_JOINER.join(
+                    PolicyFileConstants.PRIVILEGE_TABLE_NAME, tableName));
+            if (!StringUtils.isEmpty(columnName)) {
+              privileges.add(ProviderConstants.KV_JOINER.join(
+                      PolicyFileConstants.PRIVILEGE_COLUMN_NAME, columnName));
+            }
+          }
+        }
+        if (!StringUtils.isEmpty(action)) {
+          privileges.add(ProviderConstants.KV_JOINER.join(
+                  PolicyFileConstants.PRIVILEGE_ACTION_NAME, action));
+        }
+      }
+      // only append the grant option to privilege string if it's true
+      if ("true".equals(grantOption)) {
+        privileges.add(ProviderConstants.KV_JOINER.join(
+                PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption));
+      }
+    }
+    return ProviderConstants.AUTHORIZABLE_JOINER.join(privileges);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListRolesCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListRolesCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListRolesCmd.java
new file mode 100644
index 0000000..283f2c0
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/ListRolesCmd.java
@@ -0,0 +1,51 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+
+import java.util.Set;
+
+/**
+ * The class for admin command to list roles.
+ */
+public class ListRolesCmd implements Command {
+
+  private String groupName;
+
+  public ListRolesCmd(String groupName) {
+    this.groupName = groupName;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    Set<TSentryRole> roles;
+    if (StringUtils.isEmpty(groupName)) {
+      roles = client.listRoles(requestorName);
+    } else {
+      roles = client.listRolesByGroupName(requestorName, groupName);
+    }
+    if (roles != null) {
+      for (TSentryRole role : roles) {
+        System.out.println(role.getRoleName());
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokePrivilegeFromRoleCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokePrivilegeFromRoleCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokePrivilegeFromRoleCmd.java
new file mode 100644
index 0000000..9405037
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokePrivilegeFromRoleCmd.java
@@ -0,0 +1,62 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.service.thrift.ServiceConstants;
+
+/**
+ * The class for admin command to revoke privileges from role.
+ */
+public class RevokePrivilegeFromRoleCmd implements Command {
+
+  private String roleName;
+  String privilegeStr;
+
+  public RevokePrivilegeFromRoleCmd(String roleName, String privilegeStr) {
+    this.roleName = roleName;
+    this.privilegeStr = privilegeStr;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    TSentryPrivilege tSentryPrivilege = CommandUtil.convertToTSentryPrivilege(privilegeStr);
+    boolean grantOption = tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE) ? true : false;
+    if (ServiceConstants.PrivilegeScope.SERVER.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.revokeServerPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              grantOption);
+    } else if (ServiceConstants.PrivilegeScope.DATABASE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.revokeDatabasePrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.TABLE.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.revokeTablePrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getTableName(),
+              tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.COLUMN.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.revokeColumnPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getDbName(), tSentryPrivilege.getTableName(),
+              tSentryPrivilege.getColumnName(), tSentryPrivilege.getAction(), grantOption);
+    } else if (ServiceConstants.PrivilegeScope.URI.toString().equals(tSentryPrivilege.getPrivilegeScope())) {
+      client.revokeURIPrivilege(requestorName, roleName, tSentryPrivilege.getServerName(),
+              tSentryPrivilege.getURI(), grantOption);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokeRoleFromGroupsCmd.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokeRoleFromGroupsCmd.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokeRoleFromGroupsCmd.java
new file mode 100644
index 0000000..86773ca
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/tools/command/hive/RevokeRoleFromGroupsCmd.java
@@ -0,0 +1,43 @@
+/**
+ * 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.provider.db.tools.command.hive;
+
+import com.google.common.collect.Sets;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
+
+import java.util.Set;
+
+/**
+ * The class for admin command to revoke role from group.
+ */
+public class RevokeRoleFromGroupsCmd implements Command {
+
+  private String roleName;
+  private String groupNamesStr;
+
+  public RevokeRoleFromGroupsCmd(String roleName, String groupNamesStr) {
+    this.roleName = roleName;
+    this.groupNamesStr = groupNamesStr;
+  }
+
+  @Override
+  public void execute(SentryPolicyServiceClient client, String requestorName) throws Exception {
+    Set<String> groups = Sets.newHashSet(groupNamesStr.split(CommandUtil.SPLIT_CHAR));
+    client.revokeRoleFromGroups(requestorName, roleName, groups);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/tools/TestSentryShellHive.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/tools/TestSentryShellHive.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/tools/TestSentryShellHive.java
new file mode 100644
index 0000000..3907200
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/tools/TestSentryShellHive.java
@@ -0,0 +1,583 @@
+/**
+ * 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.provider.db.tools;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.Set;
+
+import junit.framework.Assert;
+import org.apache.commons.io.FileUtils;
+import org.apache.sentry.SentryUserException;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.apache.sentry.service.thrift.SentryServiceIntegrationBase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+
+public class TestSentryShellHive extends SentryServiceIntegrationBase {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(TestSentryShellHive.class);
+  private File confDir;
+  private File confPath;
+  private static String TEST_ROLE_NAME_1 = "testRole1";
+  private static String TEST_ROLE_NAME_2 = "testRole2";
+  private String requestorName = "";
+
+  @Before
+  public void prepareForTest() throws Exception {
+    confDir = Files.createTempDir();
+    confPath = new File(confDir, "sentry-site.xml");
+    if (confPath.createNewFile()) {
+      FileOutputStream to = new FileOutputStream(confPath);
+      conf.writeXml(to);
+      to.close();
+    }
+    requestorName = System.getProperty("user.name", "");
+    Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP);
+    setLocalGroupMapping(requestorName, requestorUserGroupNames);
+    // add ADMIN_USER for the after() in SentryServiceIntegrationBase
+    setLocalGroupMapping(ADMIN_USER, requestorUserGroupNames);
+    writePolicyFile();
+  }
+
+  @After
+  public void clearTestData() throws Exception {
+    FileUtils.deleteQuietly(confDir);
+  }
+
+  @Test
+  public void testCreateDropRole() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // test: create role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: create role with --create_role
+        args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // validate the result, list roles with -lr
+        args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive sentryShell = new SentryShellHive();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of roles", 2, roleNames.size());
+        for (String roleName : roleNames) {
+          assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName)
+              || TEST_ROLE_NAME_2.equalsIgnoreCase(roleName));
+        }
+
+        // validate the result, list roles with --list_role
+        args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of roles", 2, roleNames.size());
+        for (String roleName : roleNames) {
+          assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName)
+              || TEST_ROLE_NAME_2.equalsIgnoreCase(roleName));
+        }
+
+        // test: drop role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: drop role with --drop_role
+        args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listRoles(requestorName);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+      }
+    });
+  }
+
+  @Test
+  public void testAddDeleteRoleForGroup() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1);
+        client.createRole(requestorName, TEST_ROLE_NAME_2);
+        // test: add group to role with -arg
+        String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: add role to multiple groups
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup2,testGroup3",
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: add role to group with --add_role_group
+        args = new String[] { "--add_role_group", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1",
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // validate the result list roles with -lr and -g
+        args = new String[] { "-lr", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive sentryShell = new SentryShellHive();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of roles", 2, roleNames.size());
+        for (String roleName : roleNames) {
+          assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName)
+              || TEST_ROLE_NAME_2.equalsIgnoreCase(roleName));
+        }
+
+        // list roles with --list_role and -g
+        args = new String[] { "--list_role", "-g", "testGroup2", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of roles", 1, roleNames.size());
+        for (String roleName : roleNames) {
+          assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName));
+        }
+
+        args = new String[] { "--list_role", "-g", "testGroup3", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of roles", 1, roleNames.size());
+        for (String roleName : roleNames) {
+          assertTrue(TEST_ROLE_NAME_1.equalsIgnoreCase(roleName));
+        }
+
+        // test: delete group from role with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: delete role to multiple groups
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", "testGroup2,testGroup3",
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // test: delete group from role with --delete_role_group
+        args = new String[] { "--delete_role_group", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listRolesByGroupName(requestorName, "testGroup1");
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, "testGroup2");
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, "testGroup3");
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2);
+      }
+    });
+  }
+
+  @Test
+  public void testGrantRevokePrivilegeWithShortOption() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1);
+        client.createRole(requestorName, TEST_ROLE_NAME_2);
+
+        // test: grant privilege to role with -gpr
+        String[] args = { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->action=*",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->action=select", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // for the uri privilege, the action will be awalys *
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->uri=hdfs://path/testuri", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // test the list privilege with -lp
+        args = new String[] { "-lp", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellHive sentryShell = new SentryShellHive();
+        Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true);
+        // validate the result for -lp
+        assertEquals("Incorrect number of privileges", 6, privilegeStrs.size());
+        assertTrue(privilegeStrs.contains("server=server1->action=*"));
+        assertTrue(privilegeStrs.contains("server=server1->db=db1->action=select"));
+        assertTrue(privilegeStrs.contains("server=server1->db=db1->table=tbl1->action=insert"));
+        assertTrue(privilegeStrs
+            .contains("server=server1->db=db1->table=tbl1->column=col1->action=insert"));
+        assertTrue(privilegeStrs
+            .contains("server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true"));
+        // for the uri privilege, the action will be awalys *
+        assertTrue(privilegeStrs.contains("server=server1->uri=hdfs://path/testuri->action=*"));
+
+        // test: revoke privilege from role with -rpr
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName(requestorName,
+            TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 5, privileges.size());
+
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 4, privileges.size());
+
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->uri=hdfs://path/testuri", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 3, privileges.size());
+
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 2, privileges.size());
+
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->action=select", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 1, privileges.size());
+
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-p", "server=server1->action=*",
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 0, privileges.size());
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2);
+      }
+    });
+  }
+
+  @Test
+  public void testGrantRevokePrivilegeWithLongOption() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1);
+        client.createRole(requestorName, TEST_ROLE_NAME_2);
+
+        // test: grant privilege to role with -gpr
+        String[] args = { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->action=*", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->action=select", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        args = new String[] { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        // for the uri privilege, the action will be awalys *
+        args = new String[] { "--grant_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->uri=hdfs://path/testuri", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+
+        // test the list privilege with -lp
+        args = new String[] { "--list_privilege", "-r", TEST_ROLE_NAME_1, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive sentryShell = new SentryShellHive();
+        Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true);
+        // validate the result for -lp
+        assertEquals("Incorrect number of privileges", 6, privilegeStrs.size());
+        assertTrue(privilegeStrs.contains("server=server1->action=*"));
+        assertTrue(privilegeStrs.contains("server=server1->db=db1->action=select"));
+        assertTrue(privilegeStrs.contains("server=server1->db=db1->table=tbl1->action=insert"));
+        assertTrue(privilegeStrs
+            .contains("server=server1->db=db1->table=tbl1->column=col1->action=insert"));
+        assertTrue(privilegeStrs
+            .contains("server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true"));
+        // for the uri privilege, the action will be awalys *
+        assertTrue(privilegeStrs.contains("server=server1->uri=hdfs://path/testuri->action=*"));
+
+        // test: revoke privilege from role with -rpr
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        Set<TSentryPrivilege> privileges = client.listAllPrivilegesByRoleName(requestorName,
+            TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 5, privileges.size());
+
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->column=col2->action=insert->grantoption=true",
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 4, privileges.size());
+
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->uri=hdfs://path/testuri", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 3, privileges.size());
+
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->table=tbl1->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 2, privileges.size());
+
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->db=db1->action=select", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 1, privileges.size());
+
+        args = new String[] { "--revoke_privilege_role", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->action=*", "-conf", confPath.getAbsolutePath() };
+        SentryShellHive.main(args);
+        privileges = client.listAllPrivilegesByRoleName(requestorName, TEST_ROLE_NAME_1);
+        assertEquals("Incorrect number of privileges", 0, privileges.size());
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2);
+      }
+    });
+  }
+
+  @Test
+  public void testNegativeCaseWithInvalidArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        client.createRole(requestorName, TEST_ROLE_NAME_1);
+        // test: create duplicate role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellHive sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for creating duplicate role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: drop non-exist role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for dropping non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: add group to non-exist role with -arg
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for granting non-exist role to group");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: drop group from non-exist role with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for drop group from non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: grant privilege to role with the error privilege format
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", "serverserver1->action=*",
+            "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (IllegalArgumentException e) {
+          // excepted exception
+        }
+
+        // test: grant privilege to role with the error privilege hierarchy
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->table=tbl1->column=col2->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (IllegalArgumentException e) {
+          // excepted exception
+        }
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1);
+      }
+    });
+  }
+
+  @Test
+  public void testNegativeCaseWithoutRequiredArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        String strOptionConf = "conf";
+        client.createRole(requestorName, TEST_ROLE_NAME_1);
+        // test: the conf is required argument
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 };
+        SentryShellHive sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + strOptionConf);
+
+        // test: -r is required when create role
+        args = new String[] { "-cr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when drop role
+        args = new String[] { "-dr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when add group to role
+        args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when add group to role
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when delete group from role
+        args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when delete group from role
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when grant privilege to role
+        args = new String[] { "-gpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when grant privilege to role
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: -r is required when revoke privilege from role
+        args = new String[] { "-rpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when revoke privilege from role
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: command option is required for shell
+        args = new String[] {"-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellHive();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[-arg Add group to role," +
+                        " -cr Create role, -rpr Revoke privilege from role, -drg Delete group from role," +
+                        " -lr List role, -lp List privilege, -gpr Grant privilege to role, -dr Drop role]");
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1);
+      }
+    });
+  }
+
+  // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result.
+  private Set<String> getShellResultWithOSRedirect(SentryShellHive sentryShell,
+      String[] args, boolean exceptedExecuteResult) throws Exception {
+    PrintStream oldOut = System.out;
+    ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+    System.setOut(new PrintStream(outContent));
+    assertEquals(exceptedExecuteResult, sentryShell.executeShell(args));
+    Set<String> resultSet = Sets.newHashSet(outContent.toString().split("\n"));
+    System.setOut(oldOut);
+    return resultSet;
+  }
+
+  private void validateMissingParameterMsg(SentryShellHive sentryShell, String[] args,
+      String exceptedErrorMsg) throws Exception {
+    Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false);
+    Assert.assertTrue(errorMsgs.contains(exceptedErrorMsg));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/0adfc738/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
index 6bc9f75..124293a 100644
--- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/SentryServiceIntegrationBase.java
@@ -56,12 +56,6 @@ import com.google.common.io.Files;
 public abstract class SentryServiceIntegrationBase extends SentryMiniKdcTestcase {
   private static final Logger LOGGER = LoggerFactory.getLogger(SentryServiceIntegrationBase.class);
 
-  static {
-    if (System.getProperty("sun.security.krb5.debug", "").trim().isEmpty()) {
-      System.setProperty("sun.security.krb5.debug", String.valueOf("true"));
-    }
-  }
-
   protected static final String SERVER_HOST = NetUtils.createSocketAddr("localhost:80").getAddress().getCanonicalHostName();
   protected static final String REALM = "EXAMPLE.COM";
   protected static final String SERVER_PRINCIPAL = "sentry/" + SERVER_HOST;