You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2014/12/09 13:12:42 UTC

[1/4] hbase git commit: HBASE-12564 consolidate the getTableDescriptors() semantic

Repository: hbase
Updated Branches:
  refs/heads/branch-1 a731ea630 -> 09617cc2a
  refs/heads/master b4371252f -> 8a2c84156


http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
index ae4af26..4ed81dc 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
@@ -223,7 +223,7 @@ public class TableAuthManager {
    * Updates the internal permissions cache for a single table, splitting
    * the permissions listed into separate caches for users and groups to optimize
    * group lookups.
-   * 
+   *
    * @param table
    * @param tablePerms
    */
@@ -349,6 +349,20 @@ public class TableAuthManager {
     return false;
   }
 
+  private boolean hasAccess(List<TablePermission> perms,
+                            TableName table, Permission.Action action) {
+    if (perms != null) {
+      for (TablePermission p : perms) {
+        if (p.implies(action)) {
+          return true;
+        }
+      }
+    } else if (LOG.isDebugEnabled()) {
+      LOG.debug("No permissions found for table="+table);
+    }
+    return false;
+  }
+
   /**
    * Authorize a user for a given KV. This is called from AccessControlFilter.
    */
@@ -442,7 +456,7 @@ public class TableAuthManager {
       byte[] qualifier, Permission.Action action) {
     if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
     // Global and namespace authorizations supercede table level
-    if (authorize(user, table.getNamespaceAsString(), action)) {    
+    if (authorize(user, table.getNamespaceAsString(), action)) {
       return true;
     }
     // Check table permissions
@@ -451,6 +465,25 @@ public class TableAuthManager {
   }
 
   /**
+   * Checks if the user has access to the full table or at least a family/qualifier
+   * for the specified action.
+   *
+   * @param user
+   * @param table
+   * @param action
+   * @return true if the user has access to the table, false otherwise
+   */
+  public boolean userHasAccess(User user, TableName table, Permission.Action action) {
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Global and namespace authorizations supercede table level
+    if (authorize(user, table.getNamespaceAsString(), action)) {
+      return true;
+    }
+    // Check table permissions
+    return hasAccess(getTablePermissions(table).getUser(user.getShortName()), table, action);
+  }
+
+  /**
    * Checks global authorization for a given action for a group, based on the stored
    * permissions.
    */
@@ -460,7 +493,7 @@ public class TableAuthManager {
 
   /**
    * Checks authorization to a given table and column family for a group, based
-   * on the stored permissions. 
+   * on the stored permissions.
    * @param groupName
    * @param table
    * @param family
@@ -483,6 +516,29 @@ public class TableAuthManager {
     return authorize(getTablePermissions(table).getGroup(groupName), table, family, action);
   }
 
+  /**
+   * Checks if the user has access to the full table or at least a family/qualifier
+   * for the specified action.
+   * @param groupName
+   * @param table
+   * @param action
+   * @return true if the group has access to the table, false otherwise
+   */
+  public boolean groupHasAccess(String groupName, TableName table, Permission.Action action) {
+    // Global authorization supercedes table level
+    if (authorizeGroup(groupName, action)) {
+      return true;
+    }
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Namespace authorization supercedes table level
+    if (hasAccess(getNamespacePermissions(table.getNamespaceAsString()).getGroup(groupName),
+        table, action)) {
+      return true;
+    }
+    // Check table level
+    return hasAccess(getTablePermissions(table).getGroup(groupName), table, action);
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       byte[] qualifier, Permission.Action action) {
     if (authorizeUser(user, table, family, qualifier, action)) {
@@ -500,6 +556,22 @@ public class TableAuthManager {
     return false;
   }
 
+  public boolean hasAccess(User user, TableName table, Permission.Action action) {
+    if (userHasAccess(user, table, action)) {
+      return true;
+    }
+
+    String[] groups = user.getGroupNames();
+    if (groups != null) {
+      for (String group : groups) {
+        if (groupHasAccess(group, table, action)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       Permission.Action action) {
     return authorize(user, table, family, null, action);

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
index 8fc4471..d3593cd 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
@@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.RequestConverter;
 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
+import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
@@ -150,6 +151,8 @@ public class TestMasterObserver {
     private boolean postModifyTableHandlerCalled;
     private boolean preGetTableDescriptorsCalled;
     private boolean postGetTableDescriptorsCalled;
+    private boolean postGetTableNamesCalled;
+    private boolean preGetTableNamesCalled;
 
     public void enableBypass(boolean bypass) {
       this.bypass = bypass;
@@ -224,6 +227,8 @@ public class TestMasterObserver {
       postModifyTableHandlerCalled = false;
       preGetTableDescriptorsCalled = false;
       postGetTableDescriptorsCalled = false;
+      postGetTableNamesCalled = false;
+      preGetTableNamesCalled = false;
     }
 
     @Override
@@ -773,11 +778,6 @@ public class TestMasterObserver {
       postDeleteSnapshotCalled = true;
     }
 
-    @Override
-    public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-        List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException {
-    }
-
     public boolean wasDeleteSnapshotCalled() {
       return preDeleteSnapshotCalled && postDeleteSnapshotCalled;
     }
@@ -1018,17 +1018,29 @@ public class TestMasterObserver {
 
     @Override
     public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-        List<HTableDescriptor> descriptors) throws IOException {
+        List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+        String regex) throws IOException {
+      postGetTableDescriptorsCalled = true;
+    }
+
+    public boolean wasGetTableDescriptorsCalled() {
+      return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
     }
 
     @Override
-    public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+    public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
         List<HTableDescriptor> descriptors, String regex) throws IOException {
-      postGetTableDescriptorsCalled = true;
+      preGetTableNamesCalled = true;
     }
 
-    public boolean wasGetTableDescriptorsCalled() {
-      return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
+    @Override
+    public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<HTableDescriptor> descriptors, String regex) throws IOException {
+      postGetTableNamesCalled = true;
+    }
+
+    public boolean wasGetTableNamesCalled() {
+      return preGetTableNamesCalled && postGetTableNamesCalled;
     }
 
     @Override
@@ -1552,4 +1564,19 @@ public class TestMasterObserver {
       cp.wasGetTableDescriptorsCalled());
   }
 
+  @Test
+  public void testTableNamesEnumeration() throws Exception {
+    MiniHBaseCluster cluster = UTIL.getHBaseCluster();
+
+    HMaster master = cluster.getMaster();
+    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
+    CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
+        CPMasterObserver.class.getName());
+    cp.resetStates();
+
+    master.getMasterRpcServices().getTableNames(null,
+        GetTableNamesRequest.newBuilder().build());
+    assertTrue("Coprocessor should be called on table names request",
+      cp.wasGetTableNamesCalled());
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
index 9f268c9..fb7af84 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.security.PrivilegedAction;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.logging.Log;
@@ -264,7 +265,7 @@ public class TestAccessController extends SecureTestUtil {
     try {
       assertEquals(4, AccessControlClient.getUserPermissions(conf, TEST_TABLE.toString()).size());
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.getUserPermissions. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
     }
   }
 
@@ -2059,11 +2060,14 @@ public class TestAccessController extends SecureTestUtil {
     AccessTestAction listTablesAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.listTables();
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
@@ -2072,24 +2076,48 @@ public class TestAccessController extends SecureTestUtil {
     AccessTestAction getTableDescAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.getTableDescriptor(TEST_TABLE.getTableName());
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
     };
 
-    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN);
-    verifyDenied(listTablesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, TABLE_ADMIN);
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
+    verifyDenied(listTablesAction, USER_RW, USER_RO, USER_NONE);
 
     verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
     verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE);
   }
 
   @Test
+  public void testTableNameEnumeration() throws Exception {
+    AccessTestAction listTablesAction = new AccessTestAction() {
+      @Override
+      public Object run() throws Exception {
+        Connection unmanagedConnection =
+            ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
+        try {
+          return Arrays.asList(admin.listTableNames());
+        } finally {
+          admin.close();
+          unmanagedConnection.close();
+        }
+      }
+    };
+
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_RW, USER_RO);
+    verifyDenied(listTablesAction, USER_NONE);
+  }
+
+  @Test
   public void testTableDeletion() throws Exception {
     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
 
@@ -2166,7 +2194,7 @@ public class TestAccessController extends SecureTestUtil {
       grantOnTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testGrantRevoke should be able to read also
@@ -2177,7 +2205,7 @@ public class TestAccessController extends SecureTestUtil {
       revokeFromTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testGrantRevoke shouldn't be able read
@@ -2207,7 +2235,7 @@ public class TestAccessController extends SecureTestUtil {
       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testNS should be able to read also
@@ -2218,7 +2246,7 @@ public class TestAccessController extends SecureTestUtil {
       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testNS shouldn't be able read
@@ -2451,8 +2479,7 @@ public class TestAccessController extends SecureTestUtil {
         try {
           return AccessControlClient.getUserPermissions(conf, regex);
         } catch (Throwable e) {
-          LOG.error("error during call of AccessControlClient.getUserPermissions. "
-              + e.getStackTrace());
+          LOG.error("error during call of AccessControlClient.getUserPermissions.", e);
           return null;
         }
       }
@@ -2462,10 +2489,12 @@ public class TestAccessController extends SecureTestUtil {
   @Test
   public void testAccessControlClientUserPerms() throws Exception {
     // adding default prefix explicitly as it is not included in the table name.
-    final String regex = TEST_TABLE.getTableName().getNamespaceAsString() + ":"
-        + TEST_TABLE.getTableName().getNameAsString();
+    assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR,
+                 TEST_TABLE.getTableName().getNamespaceAsString());
+    final String regex = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR +
+      TableName.NAMESPACE_DELIM + TEST_TABLE.getTableName().getNameAsString();
     User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new String[0]);
-    assertNull(testUserPerms.runAs(getPrivilegedAction(regex)));
+    assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
     // Grant TABLE ADMIN privs to testUserPerms
     grantOnTable(TEST_UTIL, testUserPerms.getShortName(), TEST_TABLE.getTableName(), null,
       null, Action.ADMIN);
@@ -2475,12 +2504,12 @@ public class TestAccessController extends SecureTestUtil {
     assertEquals(5, perms.size());
   }
 
-
-
   @Test
-  public void testAccessControllerRegexHandling() throws Exception {
+  public void testAccessControllerUserPermsRegexHandling() throws Exception {
     User testRegexHandler = User.createUserForTesting(conf, "testRegexHandling", new String[0]);
-    String tableName = "testRegex";
+
+    final String REGEX_ALL_TABLES = ".*";
+    final String tableName = "testRegex";
     final TableName table1 = TableName.valueOf(tableName);
     final byte[] family = Bytes.toBytes("f1");
 
@@ -2494,20 +2523,32 @@ public class TestAccessController extends SecureTestUtil {
     // creating the ns and table in it
     String ns = "testNamespace";
     NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
-    final TableName table2 = TableName.valueOf(ns + ":" + tableName);
+    final TableName table2 = TableName.valueOf(ns, tableName);
     TEST_UTIL.getMiniHBaseCluster().getMaster().createNamespace(desc);
     htd = new HTableDescriptor(table2);
     htd.addFamily(new HColumnDescriptor(family));
     admin.createTable(htd);
+    TEST_UTIL.waitUntilAllRegionsAssigned(table2);
+
+    // Verify that we can read sys-tables
+    String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString();
+    assertEquals(1, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
+    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
 
     // Grant TABLE ADMIN privs to testUserPerms
+    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, null, Action.ADMIN);
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, null, Action.ADMIN);
+    assertEquals(4, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
 
     // USER_ADMIN, testUserPerms must have a row each.
     assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
-    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction("default:" + tableName)).size());
-    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(ns + ":" + tableName)).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+          NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + TableName.NAMESPACE_DELIM + tableName)
+        ).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+        ns + TableName.NAMESPACE_DELIM + tableName)).size());
     assertEquals(0, testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
 
     TEST_UTIL.deleteTable(table1);

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-shell/src/main/ruby/hbase/admin.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 2c8828e..748a41c 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -43,7 +43,7 @@ module Hbase
     #----------------------------------------------------------------------------------------------
     # Returns a list of tables in hbase
     def list(regex = ".*")
-      @admin.getTableNames(regex).to_a
+      @admin.listTableNames(regex).map { |t| t.getNameAsString }
     end
 
     #----------------------------------------------------------------------------------------------


[4/4] hbase git commit: HBASE-12564 consolidate the getTableDescriptors() semantic

Posted by mb...@apache.org.
HBASE-12564 consolidate the getTableDescriptors() semantic


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/09617cc2
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/09617cc2
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/09617cc2

Branch: refs/heads/branch-1
Commit: 09617cc2aa1ef77954dab4966d9d7d0c6dd7f2d7
Parents: a731ea6
Author: Matteo Bertozzi <ma...@cloudera.com>
Authored: Tue Dec 9 12:06:39 2014 +0000
Committer: Matteo Bertozzi <ma...@cloudera.com>
Committed: Tue Dec 9 12:06:39 2014 +0000

----------------------------------------------------------------------
 .../org/apache/hadoop/hbase/client/Admin.java   |  60 ++
 .../hadoop/hbase/client/ConnectionAdapter.java  |   2 +-
 .../apache/hadoop/hbase/client/HBaseAdmin.java  | 114 ++-
 .../hadoop/hbase/protobuf/RequestConverter.java |  36 +-
 .../security/access/AccessControlClient.java    |   2 +-
 .../hbase/protobuf/generated/MasterProtos.java  | 721 ++++++++++++++++---
 hbase-protocol/src/main/protobuf/Master.proto   |   8 +-
 .../BaseMasterAndRegionObserver.java            |  22 +
 .../hbase/coprocessor/BaseMasterObserver.java   |  25 +-
 .../hbase/coprocessor/MasterObserver.java       |  51 +-
 .../org/apache/hadoop/hbase/master/HMaster.java | 120 +++
 .../hbase/master/MasterCoprocessorHost.java     |  48 +-
 .../hadoop/hbase/master/MasterRpcServices.java  |  85 +--
 .../hbase/security/access/AccessController.java |  89 ++-
 .../hbase/security/access/TableAuthManager.java |  78 +-
 .../hbase/coprocessor/TestMasterObserver.java   |  57 +-
 .../security/access/TestAccessController.java   | 134 +++-
 hbase-shell/src/main/ruby/hbase/admin.rb        |   2 +-
 18 files changed, 1394 insertions(+), 260 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
index 509ee92..eedbdcb 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
@@ -111,6 +111,30 @@ public interface Admin extends Abortable, Closeable {
   HTableDescriptor[] listTables(String regex) throws IOException;
 
   /**
+   * List all the tables matching the given pattern.
+   *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return - returns an array of HTableDescriptors
+   * @throws IOException if a remote or network exception occurs
+   * @see #listTables()
+   */
+  HTableDescriptor[] listTables(Pattern pattern, boolean includeSysTables)
+      throws IOException;
+
+  /**
+   * List all the tables matching the given pattern.
+   *
+   * @param regex The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return - returns an array of HTableDescriptors
+   * @throws IOException if a remote or network exception occurs
+   * @see #listTables(java.util.regex.Pattern, boolean)
+   */
+  HTableDescriptor[] listTables(String regex, boolean includeSysTables)
+      throws IOException;
+
+  /**
    * List all of the names of userspace tables.
    *
    * @return TableName[] table names
@@ -119,6 +143,42 @@ public interface Admin extends Abortable, Closeable {
   TableName[] listTableNames() throws IOException;
 
   /**
+   * List all of the names of userspace tables.
+   * @param pattern The regular expression to match against
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(Pattern pattern) throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param regex The regular expression to match against
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(String regex) throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param pattern The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(final Pattern pattern, final boolean includeSysTables)
+      throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param regex The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException;
+
+  /**
    * Method for getting the tableDescriptor
    *
    * @param tableName as a {@link TableName}

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
index de13219..394618a 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
@@ -38,7 +38,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
 /**
  * An internal class that delegates to an {@link HConnection} instance.
  * A convenience to override when customizing method implementations.
- * 
+ *
  *
  * @see ConnectionUtils#createShortCircuitHConnection(HConnection, ServerName,
  * AdminService.BlockingInterface, ClientService.BlockingInterface) for case where we make

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
index a9b98c0..40ff168 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
@@ -291,59 +291,38 @@ public class HBaseAdmin implements Admin {
     return tableExists(TableName.valueOf(tableName));
   }
 
-  /**
-   * List all the userspace tables.  In other words, scan the hbase:meta table.
-   *
-   * If we wanted this to be really fast, we could implement a special
-   * catalog table that just contains table names and their descriptors.
-   * Right now, it only exists as part of the hbase:meta table's region info.
-   *
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   */
   @Override
   public HTableDescriptor[] listTables() throws IOException {
-   return executeCallable(new MasterCallable<HTableDescriptor[]>(getConnection()) {
+    return listTables((Pattern)null, false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(Pattern pattern) throws IOException {
+    return listTables(pattern, false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(String regex) throws IOException {
+    return listTables(Pattern.compile(regex), false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(final Pattern pattern, final boolean includeSysTables)
+      throws IOException {
+    return executeCallable(new MasterCallable<HTableDescriptor[]>(getConnection()) {
       @Override
       public HTableDescriptor[] call(int callTimeout) throws ServiceException {
         GetTableDescriptorsRequest req =
-            RequestConverter.buildGetTableDescriptorsRequest((List<TableName>)null);
+            RequestConverter.buildGetTableDescriptorsRequest(pattern, includeSysTables);
         return ProtobufUtil.getHTableDescriptorArray(master.getTableDescriptors(null, req));
       }
     });
   }
 
-  /**
-   * List all the userspace tables matching the given pattern.
-   *
-   * @param pattern The compiled regular expression to match against
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   * @see #listTables()
-   */
   @Override
-  public HTableDescriptor[] listTables(Pattern pattern) throws IOException {
-    List<HTableDescriptor> matched = new LinkedList<HTableDescriptor>();
-    HTableDescriptor[] tables = listTables();
-    for (HTableDescriptor table : tables) {
-      if (pattern.matcher(table.getTableName().getNameAsString()).matches()) {
-        matched.add(table);
-      }
-    }
-    return matched.toArray(new HTableDescriptor[matched.size()]);
-  }
-
-  /**
-   * List all the userspace tables matching the given regular expression.
-   *
-   * @param regex The regular expression to match against
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   * @see #listTables(java.util.regex.Pattern)
-   */
-  @Override
-  public HTableDescriptor[] listTables(String regex) throws IOException {
-    return listTables(Pattern.compile(regex));
+  public HTableDescriptor[] listTables(String regex, boolean includeSysTables)
+      throws IOException {
+    return listTables(Pattern.compile(regex), includeSysTables);
   }
 
   /**
@@ -367,17 +346,16 @@ public class HBaseAdmin implements Admin {
    * @param pattern The regular expression to match against
    * @return String[] table names
    * @throws IOException if a remote or network exception occurs
-   * @deprecated Use {@link Admin#listTables(Pattern)} instead.
+   * @deprecated Use {@link Admin#listTableNames(Pattern)} instead.
    */
   @Deprecated
   public String[] getTableNames(Pattern pattern) throws IOException {
-    List<String> matched = new ArrayList<String>();
-    for (String name: getTableNames()) {
-      if (pattern.matcher(name).matches()) {
-        matched.add(name);
-      }
+    TableName[] tableNames = listTableNames(pattern);
+    String result[] = new String[tableNames.length];
+    for (int i = 0; i < tableNames.length; i++) {
+      result[i] = tableNames[i].getNameAsString();
     }
-    return matched.toArray(new String[matched.size()]);
+    return result;
   }
 
   /**
@@ -385,30 +363,48 @@ public class HBaseAdmin implements Admin {
    * @param regex The regular expression to match against
    * @return String[] table names
    * @throws IOException if a remote or network exception occurs
-   * @deprecated Use {@link Admin#listTables(Pattern)} instead.
+   * @deprecated Use {@link Admin#listTableNames(Pattern)} instead.
    */
   @Deprecated
   public String[] getTableNames(String regex) throws IOException {
     return getTableNames(Pattern.compile(regex));
   }
 
-  /**
-   * List all of the names of userspace tables.
-   * @return TableName[] table names
-   * @throws IOException if a remote or network exception occurs
-   */
   @Override
   public TableName[] listTableNames() throws IOException {
+    return listTableNames((Pattern)null, false);
+  }
+
+  @Override
+  public TableName[] listTableNames(Pattern pattern) throws IOException {
+    return listTableNames(pattern, false);
+  }
+
+  @Override
+  public TableName[] listTableNames(String regex) throws IOException {
+    return listTableNames(Pattern.compile(regex), false);
+  }
+
+  @Override
+  public TableName[] listTableNames(final Pattern pattern, final boolean includeSysTables)
+      throws IOException {
     return executeCallable(new MasterCallable<TableName[]>(getConnection()) {
       @Override
       public TableName[] call(int callTimeout) throws ServiceException {
-        return ProtobufUtil.getTableNameArray(master.getTableNames(null,
-          GetTableNamesRequest.newBuilder().build())
-        .getTableNamesList());
+        GetTableNamesRequest req =
+            RequestConverter.buildGetTableNamesRequest(pattern, includeSysTables);
+        return ProtobufUtil.getTableNameArray(master.getTableNames(null, req)
+            .getTableNamesList());
       }
     });
   }
 
+  @Override
+  public TableName[] listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException {
+    return listTableNames(Pattern.compile(regex), includeSysTables);
+  }
+
   /**
    * Method for getting the tableDescriptor
    * @param tableName as a byte []
@@ -2638,7 +2634,7 @@ public class HBaseAdmin implements Admin {
   }
 
   /**
-   * Roll the log writer. I.e. when using a file system based write ahead log, 
+   * Roll the log writer. I.e. when using a file system based write ahead log,
    * start writing log messages to a new file.
    *
    * Note that when talking to a version 1.0+ HBase deployment, the rolling is asynchronous.

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
index c7c9038..7095fbd 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.protobuf;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import org.apache.hadoop.hbase.util.ByteStringer;
 
@@ -90,6 +91,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableReques
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterStatusRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetSchemaAlterStatusRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
+import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsMasterRunningRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyColumnRequest;
@@ -761,7 +763,7 @@ public final class RequestConverter {
    for (Triple<HRegionInfo, Integer, List<ServerName>> regionOpenInfo: regionOpenInfos) {
      Integer second = regionOpenInfo.getSecond();
      int versionOfOfflineNode = second == null ? -1 : second.intValue();
-     builder.addOpenInfo(buildRegionOpenInfo(regionOpenInfo.getFirst(), versionOfOfflineNode, 
+     builder.addOpenInfo(buildRegionOpenInfo(regionOpenInfo.getFirst(), versionOfOfflineNode,
        regionOpenInfo.getThird(), openForReplay));
    }
    if (server != null) {
@@ -784,7 +786,7 @@ public final class RequestConverter {
      final HRegionInfo region, final int versionOfOfflineNode, List<ServerName> favoredNodes,
      Boolean openForReplay) {
    OpenRegionRequest.Builder builder = OpenRegionRequest.newBuilder();
-   builder.addOpenInfo(buildRegionOpenInfo(region, versionOfOfflineNode, favoredNodes, 
+   builder.addOpenInfo(buildRegionOpenInfo(region, versionOfOfflineNode, favoredNodes,
      openForReplay));
    if (server != null) {
      builder.setServerStartCode(server.getStartcode());
@@ -1247,6 +1249,36 @@ public final class RequestConverter {
   }
 
   /**
+   * Creates a protocol buffer GetTableDescriptorsRequest
+   *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return a GetTableDescriptorsRequest
+   */
+  public static GetTableDescriptorsRequest buildGetTableDescriptorsRequest(final Pattern pattern,
+      boolean includeSysTables) {
+    GetTableDescriptorsRequest.Builder builder = GetTableDescriptorsRequest.newBuilder();
+    if (pattern != null) builder.setRegex(pattern.toString());
+    builder.setIncludeSysTables(includeSysTables);
+    return builder.build();
+  }
+
+  /**
+   * Creates a protocol buffer GetTableNamesRequest
+   *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return a GetTableNamesRequest
+   */
+  public static GetTableNamesRequest buildGetTableNamesRequest(final Pattern pattern,
+      boolean includeSysTables) {
+    GetTableNamesRequest.Builder builder = GetTableNamesRequest.newBuilder();
+    if (pattern != null) builder.setRegex(pattern.toString());
+    builder.setIncludeSysTables(includeSysTables);
+    return builder.build();
+  }
+
+  /**
    * Creates a protocol buffer GetTableDescriptorsRequest for a single table
    *
    * @param tableName the table name

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
index b5d9e1f..72861a4 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
@@ -191,7 +191,7 @@ public class AccessControlClient {
           String namespace = tableRegex.substring(1);
           permList = ProtobufUtil.getUserPermissions(protocol, Bytes.toBytes(namespace));
         } else {
-          htds = admin.listTables(Pattern.compile(tableRegex));
+          htds = admin.listTables(Pattern.compile(tableRegex), true);
           for (HTableDescriptor hd : htds) {
             permList.addAll(ProtobufUtil.getUserPermissions(protocol, hd.getTableName()));
           }

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
index ee1ab67..08bdb47 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
@@ -34181,6 +34181,31 @@ public final class MasterProtos {
      */
     org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.TableNameOrBuilder getTableNamesOrBuilder(
         int index);
+
+    // optional string regex = 2;
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    boolean hasRegex();
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    java.lang.String getRegex();
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getRegexBytes();
+
+    // optional bool include_sys_tables = 3 [default = false];
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    boolean hasIncludeSysTables();
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    boolean getIncludeSysTables();
   }
   /**
    * Protobuf type {@code GetTableDescriptorsRequest}
@@ -34241,6 +34266,16 @@ public final class MasterProtos {
               tableNames_.add(input.readMessage(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.TableName.PARSER, extensionRegistry));
               break;
             }
+            case 18: {
+              bitField0_ |= 0x00000001;
+              regex_ = input.readBytes();
+              break;
+            }
+            case 24: {
+              bitField0_ |= 0x00000002;
+              includeSysTables_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -34283,6 +34318,7 @@ public final class MasterProtos {
       return PARSER;
     }
 
+    private int bitField0_;
     // repeated .TableName table_names = 1;
     public static final int TABLE_NAMES_FIELD_NUMBER = 1;
     private java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.TableName> tableNames_;
@@ -34319,8 +34355,69 @@ public final class MasterProtos {
       return tableNames_.get(index);
     }
 
+    // optional string regex = 2;
+    public static final int REGEX_FIELD_NUMBER = 2;
+    private java.lang.Object regex_;
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    public boolean hasRegex() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    public java.lang.String getRegex() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          regex_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string regex = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getRegexBytes() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        regex_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional bool include_sys_tables = 3 [default = false];
+    public static final int INCLUDE_SYS_TABLES_FIELD_NUMBER = 3;
+    private boolean includeSysTables_;
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    public boolean hasIncludeSysTables() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    public boolean getIncludeSysTables() {
+      return includeSysTables_;
+    }
+
     private void initFields() {
       tableNames_ = java.util.Collections.emptyList();
+      regex_ = "";
+      includeSysTables_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -34343,6 +34440,12 @@ public final class MasterProtos {
       for (int i = 0; i < tableNames_.size(); i++) {
         output.writeMessage(1, tableNames_.get(i));
       }
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(2, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBool(3, includeSysTables_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -34356,6 +34459,14 @@ public final class MasterProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(1, tableNames_.get(i));
       }
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(3, includeSysTables_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -34381,6 +34492,16 @@ public final class MasterProtos {
       boolean result = true;
       result = result && getTableNamesList()
           .equals(other.getTableNamesList());
+      result = result && (hasRegex() == other.hasRegex());
+      if (hasRegex()) {
+        result = result && getRegex()
+            .equals(other.getRegex());
+      }
+      result = result && (hasIncludeSysTables() == other.hasIncludeSysTables());
+      if (hasIncludeSysTables()) {
+        result = result && (getIncludeSysTables()
+            == other.getIncludeSysTables());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -34398,6 +34519,14 @@ public final class MasterProtos {
         hash = (37 * hash) + TABLE_NAMES_FIELD_NUMBER;
         hash = (53 * hash) + getTableNamesList().hashCode();
       }
+      if (hasRegex()) {
+        hash = (37 * hash) + REGEX_FIELD_NUMBER;
+        hash = (53 * hash) + getRegex().hashCode();
+      }
+      if (hasIncludeSysTables()) {
+        hash = (37 * hash) + INCLUDE_SYS_TABLES_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getIncludeSysTables());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -34514,6 +34643,10 @@ public final class MasterProtos {
         } else {
           tableNamesBuilder_.clear();
         }
+        regex_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        includeSysTables_ = false;
+        bitField0_ = (bitField0_ & ~0x00000004);
         return this;
       }
 
@@ -34541,6 +34674,7 @@ public final class MasterProtos {
       public org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest buildPartial() {
         org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest result = new org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest(this);
         int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
         if (tableNamesBuilder_ == null) {
           if (((bitField0_ & 0x00000001) == 0x00000001)) {
             tableNames_ = java.util.Collections.unmodifiableList(tableNames_);
@@ -34550,6 +34684,15 @@ public final class MasterProtos {
         } else {
           result.tableNames_ = tableNamesBuilder_.build();
         }
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.regex_ = regex_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.includeSysTables_ = includeSysTables_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -34591,6 +34734,14 @@ public final class MasterProtos {
             }
           }
         }
+        if (other.hasRegex()) {
+          bitField0_ |= 0x00000002;
+          regex_ = other.regex_;
+          onChanged();
+        }
+        if (other.hasIncludeSysTables()) {
+          setIncludeSysTables(other.getIncludeSysTables());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -34864,6 +35015,113 @@ public final class MasterProtos {
         return tableNamesBuilder_;
       }
 
+      // optional string regex = 2;
+      private java.lang.Object regex_ = "";
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public boolean hasRegex() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public java.lang.String getRegex() {
+        java.lang.Object ref = regex_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          regex_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getRegexBytes() {
+        java.lang.Object ref = regex_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          regex_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public Builder setRegex(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public Builder clearRegex() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        regex_ = getDefaultInstance().getRegex();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 2;</code>
+       */
+      public Builder setRegexBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional bool include_sys_tables = 3 [default = false];
+      private boolean includeSysTables_ ;
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public boolean hasIncludeSysTables() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public boolean getIncludeSysTables() {
+        return includeSysTables_;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public Builder setIncludeSysTables(boolean value) {
+        bitField0_ |= 0x00000004;
+        includeSysTables_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public Builder clearIncludeSysTables() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        includeSysTables_ = false;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:GetTableDescriptorsRequest)
     }
 
@@ -35598,6 +35856,31 @@ public final class MasterProtos {
 
   public interface GetTableNamesRequestOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
+
+    // optional string regex = 1;
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    boolean hasRegex();
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    java.lang.String getRegex();
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getRegexBytes();
+
+    // optional bool include_sys_tables = 2 [default = false];
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    boolean hasIncludeSysTables();
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    boolean getIncludeSysTables();
   }
   /**
    * Protobuf type {@code GetTableNamesRequest}
@@ -35632,6 +35915,7 @@ public final class MasterProtos {
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       initFields();
+      int mutable_bitField0_ = 0;
       com.google.protobuf.UnknownFieldSet.Builder unknownFields =
           com.google.protobuf.UnknownFieldSet.newBuilder();
       try {
@@ -35649,6 +35933,16 @@ public final class MasterProtos {
               }
               break;
             }
+            case 10: {
+              bitField0_ |= 0x00000001;
+              regex_ = input.readBytes();
+              break;
+            }
+            case 16: {
+              bitField0_ |= 0x00000002;
+              includeSysTables_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -35688,7 +35982,69 @@ public final class MasterProtos {
       return PARSER;
     }
 
+    private int bitField0_;
+    // optional string regex = 1;
+    public static final int REGEX_FIELD_NUMBER = 1;
+    private java.lang.Object regex_;
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public boolean hasRegex() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public java.lang.String getRegex() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          regex_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getRegexBytes() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        regex_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional bool include_sys_tables = 2 [default = false];
+    public static final int INCLUDE_SYS_TABLES_FIELD_NUMBER = 2;
+    private boolean includeSysTables_;
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    public boolean hasIncludeSysTables() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    public boolean getIncludeSysTables() {
+      return includeSysTables_;
+    }
+
     private void initFields() {
+      regex_ = "";
+      includeSysTables_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -35702,6 +36058,12 @@ public final class MasterProtos {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBool(2, includeSysTables_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -35711,6 +36073,14 @@ public final class MasterProtos {
       if (size != -1) return size;
 
       size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(2, includeSysTables_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -35734,6 +36104,16 @@ public final class MasterProtos {
       org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest other = (org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest) obj;
 
       boolean result = true;
+      result = result && (hasRegex() == other.hasRegex());
+      if (hasRegex()) {
+        result = result && getRegex()
+            .equals(other.getRegex());
+      }
+      result = result && (hasIncludeSysTables() == other.hasIncludeSysTables());
+      if (hasIncludeSysTables()) {
+        result = result && (getIncludeSysTables()
+            == other.getIncludeSysTables());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -35747,6 +36127,14 @@ public final class MasterProtos {
       }
       int hash = 41;
       hash = (19 * hash) + getDescriptorForType().hashCode();
+      if (hasRegex()) {
+        hash = (37 * hash) + REGEX_FIELD_NUMBER;
+        hash = (53 * hash) + getRegex().hashCode();
+      }
+      if (hasIncludeSysTables()) {
+        hash = (37 * hash) + INCLUDE_SYS_TABLES_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getIncludeSysTables());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -35856,6 +36244,10 @@ public final class MasterProtos {
 
       public Builder clear() {
         super.clear();
+        regex_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        includeSysTables_ = false;
+        bitField0_ = (bitField0_ & ~0x00000002);
         return this;
       }
 
@@ -35882,6 +36274,17 @@ public final class MasterProtos {
 
       public org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest buildPartial() {
         org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest result = new org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.regex_ = regex_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.includeSysTables_ = includeSysTables_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -35897,6 +36300,14 @@ public final class MasterProtos {
 
       public Builder mergeFrom(org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest other) {
         if (other == org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest.getDefaultInstance()) return this;
+        if (other.hasRegex()) {
+          bitField0_ |= 0x00000001;
+          regex_ = other.regex_;
+          onChanged();
+        }
+        if (other.hasIncludeSysTables()) {
+          setIncludeSysTables(other.getIncludeSysTables());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -35922,6 +36333,114 @@ public final class MasterProtos {
         }
         return this;
       }
+      private int bitField0_;
+
+      // optional string regex = 1;
+      private java.lang.Object regex_ = "";
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public boolean hasRegex() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public java.lang.String getRegex() {
+        java.lang.Object ref = regex_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          regex_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getRegexBytes() {
+        java.lang.Object ref = regex_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          regex_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder setRegex(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder clearRegex() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        regex_ = getDefaultInstance().getRegex();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder setRegexBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional bool include_sys_tables = 2 [default = false];
+      private boolean includeSysTables_ ;
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public boolean hasIncludeSysTables() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public boolean getIncludeSysTables() {
+        return includeSysTables_;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public Builder setIncludeSysTables(boolean value) {
+        bitField0_ |= 0x00000002;
+        includeSysTables_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public Builder clearIncludeSysTables() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        includeSysTables_ = false;
+        onChanged();
+        return this;
+      }
 
       // @@protoc_insertion_point(builder_scope:GetTableNamesRequest)
     }
@@ -40978,7 +41497,7 @@ public final class MasterProtos {
        * <code>rpc Snapshot(.SnapshotRequest) returns (.SnapshotResponse);</code>
        *
        * <pre>
-       ** 
+       **
        * Create a snapshot for the given table.
        * </pre>
        */
@@ -42185,7 +42704,7 @@ public final class MasterProtos {
      * <code>rpc Snapshot(.SnapshotRequest) returns (.SnapshotResponse);</code>
      *
      * <pre>
-     ** 
+     **
      * Create a snapshot for the given table.
      * </pre>
      */
@@ -44746,103 +45265,105 @@ public final class MasterProtos {
       "se\"=\n\033GetSchemaAlterStatusRequest\022\036\n\ntab" +
       "le_name\030\001 \002(\0132\n.TableName\"T\n\034GetSchemaAl",
       "terStatusResponse\022\035\n\025yet_to_update_regio" +
-      "ns\030\001 \001(\r\022\025\n\rtotal_regions\030\002 \001(\r\"=\n\032GetTa" +
+      "ns\030\001 \001(\r\022\025\n\rtotal_regions\030\002 \001(\r\"o\n\032GetTa" +
       "bleDescriptorsRequest\022\037\n\013table_names\030\001 \003" +
-      "(\0132\n.TableName\"A\n\033GetTableDescriptorsRes" +
-      "ponse\022\"\n\014table_schema\030\001 \003(\0132\014.TableSchem" +
-      "a\"\026\n\024GetTableNamesRequest\"8\n\025GetTableNam" +
-      "esResponse\022\037\n\013table_names\030\001 \003(\0132\n.TableN" +
-      "ame\"\031\n\027GetClusterStatusRequest\"B\n\030GetClu" +
-      "sterStatusResponse\022&\n\016cluster_status\030\001 \002" +
-      "(\0132\016.ClusterStatus\"\030\n\026IsMasterRunningReq",
-      "uest\"4\n\027IsMasterRunningResponse\022\031\n\021is_ma" +
-      "ster_running\030\001 \002(\010\"@\n\024ExecProcedureReque" +
-      "st\022(\n\tprocedure\030\001 \002(\0132\025.ProcedureDescrip" +
-      "tion\"F\n\025ExecProcedureResponse\022\030\n\020expecte" +
-      "d_timeout\030\001 \001(\003\022\023\n\013return_data\030\002 \001(\014\"B\n\026" +
-      "IsProcedureDoneRequest\022(\n\tprocedure\030\001 \001(" +
-      "\0132\025.ProcedureDescription\"W\n\027IsProcedureD" +
-      "oneResponse\022\023\n\004done\030\001 \001(\010:\005false\022\'\n\010snap" +
-      "shot\030\002 \001(\0132\025.ProcedureDescription2\365\027\n\rMa" +
-      "sterService\022S\n\024GetSchemaAlterStatus\022\034.Ge",
-      "tSchemaAlterStatusRequest\032\035.GetSchemaAlt" +
-      "erStatusResponse\022P\n\023GetTableDescriptors\022" +
-      "\033.GetTableDescriptorsRequest\032\034.GetTableD" +
-      "escriptorsResponse\022>\n\rGetTableNames\022\025.Ge" +
-      "tTableNamesRequest\032\026.GetTableNamesRespon" +
-      "se\022G\n\020GetClusterStatus\022\030.GetClusterStatu" +
-      "sRequest\032\031.GetClusterStatusResponse\022D\n\017I" +
-      "sMasterRunning\022\027.IsMasterRunningRequest\032" +
-      "\030.IsMasterRunningResponse\0222\n\tAddColumn\022\021" +
-      ".AddColumnRequest\032\022.AddColumnResponse\022;\n",
-      "\014DeleteColumn\022\024.DeleteColumnRequest\032\025.De" +
-      "leteColumnResponse\022;\n\014ModifyColumn\022\024.Mod" +
-      "ifyColumnRequest\032\025.ModifyColumnResponse\022" +
-      "5\n\nMoveRegion\022\022.MoveRegionRequest\032\023.Move" +
-      "RegionResponse\022Y\n\026DispatchMergingRegions" +
-      "\022\036.DispatchMergingRegionsRequest\032\037.Dispa" +
-      "tchMergingRegionsResponse\022;\n\014AssignRegio" +
-      "n\022\024.AssignRegionRequest\032\025.AssignRegionRe" +
-      "sponse\022A\n\016UnassignRegion\022\026.UnassignRegio" +
-      "nRequest\032\027.UnassignRegionResponse\022>\n\rOff",
-      "lineRegion\022\025.OfflineRegionRequest\032\026.Offl" +
-      "ineRegionResponse\0228\n\013DeleteTable\022\023.Delet" +
-      "eTableRequest\032\024.DeleteTableResponse\022>\n\rt" +
-      "runcateTable\022\025.TruncateTableRequest\032\026.Tr" +
-      "uncateTableResponse\0228\n\013EnableTable\022\023.Ena" +
-      "bleTableRequest\032\024.EnableTableResponse\022;\n" +
-      "\014DisableTable\022\024.DisableTableRequest\032\025.Di" +
-      "sableTableResponse\0228\n\013ModifyTable\022\023.Modi" +
-      "fyTableRequest\032\024.ModifyTableResponse\0228\n\013" +
-      "CreateTable\022\023.CreateTableRequest\032\024.Creat",
-      "eTableResponse\022/\n\010Shutdown\022\020.ShutdownReq" +
-      "uest\032\021.ShutdownResponse\0225\n\nStopMaster\022\022." +
-      "StopMasterRequest\032\023.StopMasterResponse\022," +
-      "\n\007Balance\022\017.BalanceRequest\032\020.BalanceResp" +
-      "onse\022M\n\022SetBalancerRunning\022\032.SetBalancer" +
-      "RunningRequest\032\033.SetBalancerRunningRespo" +
-      "nse\022A\n\016RunCatalogScan\022\026.RunCatalogScanRe" +
-      "quest\032\027.RunCatalogScanResponse\022S\n\024Enable" +
-      "CatalogJanitor\022\034.EnableCatalogJanitorReq" +
-      "uest\032\035.EnableCatalogJanitorResponse\022\\\n\027I",
-      "sCatalogJanitorEnabled\022\037.IsCatalogJanito" +
-      "rEnabledRequest\032 .IsCatalogJanitorEnable" +
-      "dResponse\022L\n\021ExecMasterService\022\032.Coproce" +
-      "ssorServiceRequest\032\033.CoprocessorServiceR" +
-      "esponse\022/\n\010Snapshot\022\020.SnapshotRequest\032\021." +
-      "SnapshotResponse\022V\n\025GetCompletedSnapshot" +
-      "s\022\035.GetCompletedSnapshotsRequest\032\036.GetCo" +
-      "mpletedSnapshotsResponse\022A\n\016DeleteSnapsh" +
-      "ot\022\026.DeleteSnapshotRequest\032\027.DeleteSnaps" +
-      "hotResponse\022A\n\016IsSnapshotDone\022\026.IsSnapsh",
-      "otDoneRequest\032\027.IsSnapshotDoneResponse\022D" +
-      "\n\017RestoreSnapshot\022\027.RestoreSnapshotReque" +
-      "st\032\030.RestoreSnapshotResponse\022V\n\025IsRestor" +
-      "eSnapshotDone\022\035.IsRestoreSnapshotDoneReq" +
-      "uest\032\036.IsRestoreSnapshotDoneResponse\022>\n\r" +
-      "ExecProcedure\022\025.ExecProcedureRequest\032\026.E" +
-      "xecProcedureResponse\022E\n\024ExecProcedureWit" +
-      "hRet\022\025.ExecProcedureRequest\032\026.ExecProced" +
-      "ureResponse\022D\n\017IsProcedureDone\022\027.IsProce" +
-      "dureDoneRequest\032\030.IsProcedureDoneRespons",
-      "e\022D\n\017ModifyNamespace\022\027.ModifyNamespaceRe" +
-      "quest\032\030.ModifyNamespaceResponse\022D\n\017Creat" +
-      "eNamespace\022\027.CreateNamespaceRequest\032\030.Cr" +
-      "eateNamespaceResponse\022D\n\017DeleteNamespace" +
-      "\022\027.DeleteNamespaceRequest\032\030.DeleteNamesp" +
-      "aceResponse\022Y\n\026GetNamespaceDescriptor\022\036." +
-      "GetNamespaceDescriptorRequest\032\037.GetNames" +
-      "paceDescriptorResponse\022_\n\030ListNamespaceD" +
-      "escriptors\022 .ListNamespaceDescriptorsReq" +
-      "uest\032!.ListNamespaceDescriptorsResponse\022",
-      "t\n\037ListTableDescriptorsByNamespace\022\'.Lis" +
-      "tTableDescriptorsByNamespaceRequest\032(.Li" +
-      "stTableDescriptorsByNamespaceResponse\022b\n" +
-      "\031ListTableNamesByNamespace\022!.ListTableNa" +
-      "mesByNamespaceRequest\032\".ListTableNamesBy" +
-      "NamespaceResponseBB\n*org.apache.hadoop.h" +
-      "base.protobuf.generatedB\014MasterProtosH\001\210" +
-      "\001\001\240\001\001"
+      "(\0132\n.TableName\022\r\n\005regex\030\002 \001(\t\022!\n\022include" +
+      "_sys_tables\030\003 \001(\010:\005false\"A\n\033GetTableDesc" +
+      "riptorsResponse\022\"\n\014table_schema\030\001 \003(\0132\014." +
+      "TableSchema\"H\n\024GetTableNamesRequest\022\r\n\005r" +
+      "egex\030\001 \001(\t\022!\n\022include_sys_tables\030\002 \001(\010:\005" +
+      "false\"8\n\025GetTableNamesResponse\022\037\n\013table_" +
+      "names\030\001 \003(\0132\n.TableName\"\031\n\027GetClusterSta",
+      "tusRequest\"B\n\030GetClusterStatusResponse\022&" +
+      "\n\016cluster_status\030\001 \002(\0132\016.ClusterStatus\"\030" +
+      "\n\026IsMasterRunningRequest\"4\n\027IsMasterRunn" +
+      "ingResponse\022\031\n\021is_master_running\030\001 \002(\010\"@" +
+      "\n\024ExecProcedureRequest\022(\n\tprocedure\030\001 \002(" +
+      "\0132\025.ProcedureDescription\"F\n\025ExecProcedur" +
+      "eResponse\022\030\n\020expected_timeout\030\001 \001(\003\022\023\n\013r" +
+      "eturn_data\030\002 \001(\014\"B\n\026IsProcedureDoneReque" +
+      "st\022(\n\tprocedure\030\001 \001(\0132\025.ProcedureDescrip" +
+      "tion\"W\n\027IsProcedureDoneResponse\022\023\n\004done\030",
+      "\001 \001(\010:\005false\022\'\n\010snapshot\030\002 \001(\0132\025.Procedu" +
+      "reDescription2\365\027\n\rMasterService\022S\n\024GetSc" +
+      "hemaAlterStatus\022\034.GetSchemaAlterStatusRe" +
+      "quest\032\035.GetSchemaAlterStatusResponse\022P\n\023" +
+      "GetTableDescriptors\022\033.GetTableDescriptor" +
+      "sRequest\032\034.GetTableDescriptorsResponse\022>" +
+      "\n\rGetTableNames\022\025.GetTableNamesRequest\032\026" +
+      ".GetTableNamesResponse\022G\n\020GetClusterStat" +
+      "us\022\030.GetClusterStatusRequest\032\031.GetCluste" +
+      "rStatusResponse\022D\n\017IsMasterRunning\022\027.IsM",
+      "asterRunningRequest\032\030.IsMasterRunningRes" +
+      "ponse\0222\n\tAddColumn\022\021.AddColumnRequest\032\022." +
+      "AddColumnResponse\022;\n\014DeleteColumn\022\024.Dele" +
+      "teColumnRequest\032\025.DeleteColumnResponse\022;" +
+      "\n\014ModifyColumn\022\024.ModifyColumnRequest\032\025.M" +
+      "odifyColumnResponse\0225\n\nMoveRegion\022\022.Move" +
+      "RegionRequest\032\023.MoveRegionResponse\022Y\n\026Di" +
+      "spatchMergingRegions\022\036.DispatchMergingRe" +
+      "gionsRequest\032\037.DispatchMergingRegionsRes" +
+      "ponse\022;\n\014AssignRegion\022\024.AssignRegionRequ",
+      "est\032\025.AssignRegionResponse\022A\n\016UnassignRe" +
+      "gion\022\026.UnassignRegionRequest\032\027.UnassignR" +
+      "egionResponse\022>\n\rOfflineRegion\022\025.Offline" +
+      "RegionRequest\032\026.OfflineRegionResponse\0228\n" +
+      "\013DeleteTable\022\023.DeleteTableRequest\032\024.Dele" +
+      "teTableResponse\022>\n\rtruncateTable\022\025.Trunc" +
+      "ateTableRequest\032\026.TruncateTableResponse\022" +
+      "8\n\013EnableTable\022\023.EnableTableRequest\032\024.En" +
+      "ableTableResponse\022;\n\014DisableTable\022\024.Disa" +
+      "bleTableRequest\032\025.DisableTableResponse\0228",
+      "\n\013ModifyTable\022\023.ModifyTableRequest\032\024.Mod" +
+      "ifyTableResponse\0228\n\013CreateTable\022\023.Create" +
+      "TableRequest\032\024.CreateTableResponse\022/\n\010Sh" +
+      "utdown\022\020.ShutdownRequest\032\021.ShutdownRespo" +
+      "nse\0225\n\nStopMaster\022\022.StopMasterRequest\032\023." +
+      "StopMasterResponse\022,\n\007Balance\022\017.BalanceR" +
+      "equest\032\020.BalanceResponse\022M\n\022SetBalancerR" +
+      "unning\022\032.SetBalancerRunningRequest\032\033.Set" +
+      "BalancerRunningResponse\022A\n\016RunCatalogSca" +
+      "n\022\026.RunCatalogScanRequest\032\027.RunCatalogSc",
+      "anResponse\022S\n\024EnableCatalogJanitor\022\034.Ena" +
+      "bleCatalogJanitorRequest\032\035.EnableCatalog" +
+      "JanitorResponse\022\\\n\027IsCatalogJanitorEnabl" +
+      "ed\022\037.IsCatalogJanitorEnabledRequest\032 .Is" +
+      "CatalogJanitorEnabledResponse\022L\n\021ExecMas" +
+      "terService\022\032.CoprocessorServiceRequest\032\033" +
+      ".CoprocessorServiceResponse\022/\n\010Snapshot\022" +
+      "\020.SnapshotRequest\032\021.SnapshotResponse\022V\n\025" +
+      "GetCompletedSnapshots\022\035.GetCompletedSnap" +
+      "shotsRequest\032\036.GetCompletedSnapshotsResp",
+      "onse\022A\n\016DeleteSnapshot\022\026.DeleteSnapshotR" +
+      "equest\032\027.DeleteSnapshotResponse\022A\n\016IsSna" +
+      "pshotDone\022\026.IsSnapshotDoneRequest\032\027.IsSn" +
+      "apshotDoneResponse\022D\n\017RestoreSnapshot\022\027." +
+      "RestoreSnapshotRequest\032\030.RestoreSnapshot" +
+      "Response\022V\n\025IsRestoreSnapshotDone\022\035.IsRe" +
+      "storeSnapshotDoneRequest\032\036.IsRestoreSnap" +
+      "shotDoneResponse\022>\n\rExecProcedure\022\025.Exec" +
+      "ProcedureRequest\032\026.ExecProcedureResponse" +
+      "\022E\n\024ExecProcedureWithRet\022\025.ExecProcedure",
+      "Request\032\026.ExecProcedureResponse\022D\n\017IsPro" +
+      "cedureDone\022\027.IsProcedureDoneRequest\032\030.Is" +
+      "ProcedureDoneResponse\022D\n\017ModifyNamespace" +
+      "\022\027.ModifyNamespaceRequest\032\030.ModifyNamesp" +
+      "aceResponse\022D\n\017CreateNamespace\022\027.CreateN" +
+      "amespaceRequest\032\030.CreateNamespaceRespons" +
+      "e\022D\n\017DeleteNamespace\022\027.DeleteNamespaceRe" +
+      "quest\032\030.DeleteNamespaceResponse\022Y\n\026GetNa" +
+      "mespaceDescriptor\022\036.GetNamespaceDescript" +
+      "orRequest\032\037.GetNamespaceDescriptorRespon",
+      "se\022_\n\030ListNamespaceDescriptors\022 .ListNam" +
+      "espaceDescriptorsRequest\032!.ListNamespace" +
+      "DescriptorsResponse\022t\n\037ListTableDescript" +
+      "orsByNamespace\022\'.ListTableDescriptorsByN" +
+      "amespaceRequest\032(.ListTableDescriptorsBy" +
+      "NamespaceResponse\022b\n\031ListTableNamesByNam" +
+      "espace\022!.ListTableNamesByNamespaceReques" +
+      "t\032\".ListTableNamesByNamespaceResponseBB\n" +
+      "*org.apache.hadoop.hbase.protobuf.genera" +
+      "tedB\014MasterProtosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -45274,7 +45795,7 @@ public final class MasterProtos {
           internal_static_GetTableDescriptorsRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_GetTableDescriptorsRequest_descriptor,
-              new java.lang.String[] { "TableNames", });
+              new java.lang.String[] { "TableNames", "Regex", "IncludeSysTables", });
           internal_static_GetTableDescriptorsResponse_descriptor =
             getDescriptor().getMessageTypes().get(71);
           internal_static_GetTableDescriptorsResponse_fieldAccessorTable = new
@@ -45286,7 +45807,7 @@ public final class MasterProtos {
           internal_static_GetTableNamesRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_GetTableNamesRequest_descriptor,
-              new java.lang.String[] { });
+              new java.lang.String[] { "Regex", "IncludeSysTables", });
           internal_static_GetTableNamesResponse_descriptor =
             getDescriptor().getMessageTypes().get(73);
           internal_static_GetTableNamesResponse_fieldAccessorTable = new

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-protocol/src/main/protobuf/Master.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/Master.proto b/hbase-protocol/src/main/protobuf/Master.proto
index 94ea860..c2ed031 100644
--- a/hbase-protocol/src/main/protobuf/Master.proto
+++ b/hbase-protocol/src/main/protobuf/Master.proto
@@ -313,6 +313,8 @@ message GetSchemaAlterStatusResponse {
 
 message GetTableDescriptorsRequest {
   repeated TableName table_names = 1;
+  optional string regex = 2;
+  optional bool include_sys_tables = 3 [default=false];
 }
 
 message GetTableDescriptorsResponse {
@@ -320,6 +322,8 @@ message GetTableDescriptorsResponse {
 }
 
 message GetTableNamesRequest {
+  optional string regex = 1;
+  optional bool include_sys_tables = 2 [default=false];
 }
 
 message GetTableNamesResponse {
@@ -396,7 +400,7 @@ service MasterService {
 
  /** Master dispatch merging the regions */
   rpc DispatchMergingRegions(DispatchMergingRegionsRequest)
-    returns(DispatchMergingRegionsResponse);    
+    returns(DispatchMergingRegionsResponse);
 
   /** Assign a region to a server chosen at random. */
   rpc AssignRegion(AssignRegionRequest)
@@ -489,7 +493,7 @@ service MasterService {
   rpc ExecMasterService(CoprocessorServiceRequest)
     returns(CoprocessorServiceResponse);
 
-  /** 
+  /**
    * Create a snapshot for the given table.
    */
   rpc Snapshot(SnapshotRequest) returns(SnapshotResponse);

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
index 00db26c..93dd168 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
@@ -417,6 +417,28 @@ public abstract class BaseMasterAndRegionObserver extends BaseRegionObserver
   }
 
   @Override
+  public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
+  }
+
+  @Override
+  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
+  }
+
+  @Override
+  public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+  }
+
+  @Override
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+  }
+
+  @Override
   public void preTableFlush(ObserverContext<MasterCoprocessorEnvironment> ctx,
       TableName tableName) throws IOException {
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
index d364b90..49cd245 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
@@ -331,7 +331,7 @@ public class BaseMasterObserver implements MasterObserver {
   public void preMasterInitialization(
       ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
   }
-  
+
   @Override
   public void start(CoprocessorEnvironment ctx) throws IOException {
   }
@@ -409,6 +409,29 @@ public class BaseMasterObserver implements MasterObserver {
       List<HTableDescriptor> descriptors) throws IOException {
   }
 
+
+  @Override
+  public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors, String regex)
+      throws IOException {
+  }
+
+  @Override
+  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
+  }
+
+  @Override
+  public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+  }
+
+  @Override
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+  }
+
   @Override
   public void preTableFlush(ObserverContext<MasterCoprocessorEnvironment> ctx,
       TableName tableName) throws IOException {

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
index bb41847..ba01857 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
@@ -673,21 +673,68 @@ public interface MasterObserver extends Coprocessor {
    * @param tableNamesList the list of table names, or null if querying for all
    * @param descriptors an empty list, can be filled with what to return if bypassing
    * @throws IOException
+   * @deprecated Use preGetTableDescriptors with regex instead.
    */
+  @Deprecated
   void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList,
-      List<HTableDescriptor> descriptors) throws IOException;
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException;
 
   /**
    * Called after a getTableDescriptors request has been processed.
    * @param ctx the environment to interact with the framework and master
    * @param descriptors the list of descriptors about to be returned
    * @throws IOException
+   * @deprecated Use postGetTableDescriptors with regex instead.
    */
+  @Deprecated
   void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<HTableDescriptor> descriptors) throws IOException;
 
   /**
+   * Called before a getTableDescriptors request has been processed.
+   * @param ctx the environment to interact with the framework and master
+   * @param tableNamesList the list of table names, or null if querying for all
+   * @param descriptors an empty list, can be filled with what to return if bypassing
+   * @param regex regular expression used for filtering the table names
+   * @throws IOException
+   */
+  void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException;
+
+  /**
+   * Called after a getTableDescriptors request has been processed.
+   * @param ctx the environment to interact with the framework and master
+   * @param tableNamesList the list of table names, or null if querying for all
+   * @param descriptors the list of descriptors about to be returned
+   * @param regex regular expression used for filtering the table names
+   * @throws IOException
+   */
+  void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException;
+
+  /**
+   * Called before a getTableNames request has been processed.
+   * @param ctx the environment to interact with the framework and master
+   * @param descriptors an empty list, can be filled with what to return if bypassing
+   * @param regex regular expression used for filtering the table names
+   * @throws IOException
+   */
+  void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException;
+
+  /**
+   * Called after a getTableNames request has been processed.
+   * @param ctx the environment to interact with the framework and master
+   * @param descriptors the list of descriptors about to be returned
+   * @param regex regular expression used for filtering the table names
+   * @throws IOException
+   */
+  void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException;
+
+  /**
    * Called before a new namespace is created by
    * {@link org.apache.hadoop.hbase.master.HMaster}.
    * It can't bypass the default action, e.g., ctx.bypass() won't have effect.

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index 75d26ec..8b102b2 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -26,13 +26,17 @@ import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -2012,4 +2016,120 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
     }
     return tableNames;
   }
+
+  /**
+   * Returns the list of table descriptors that match the specified request
+   *
+   * @param regex The regular expression to match against, or null if querying for all
+   * @param tableNameList the list of table names, or null if querying for all
+   * @param includeSysTables False to match only against userspace tables
+   * @return the list of table descriptors
+   */
+  public List<HTableDescriptor> listTableDescriptors(final String regex,
+      final List<TableName> tableNameList, final boolean includeSysTables)
+      throws IOException {
+    final List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
+
+    boolean bypass = false;
+    if (cpHost != null) {
+      bypass = cpHost.preGetTableDescriptors(tableNameList, descriptors);
+      // method required for AccessController.
+      bypass |= cpHost.preGetTableDescriptors(tableNameList, descriptors, regex);
+    }
+
+    if (!bypass) {
+      if (tableNameList == null || tableNameList.size() == 0) {
+        // request for all TableDescriptors
+        Collection<HTableDescriptor> htds = tableDescriptors.getAll().values();
+        for (HTableDescriptor desc: htds) {
+          if (includeSysTables || !desc.getTableName().isSystemTable()) {
+            descriptors.add(desc);
+          }
+        }
+      } else {
+        for (TableName s: tableNameList) {
+          HTableDescriptor desc = tableDescriptors.get(s);
+          if (desc != null) {
+            descriptors.add(desc);
+          }
+        }
+      }
+
+      // Retains only those matched by regular expression.
+      if (regex != null) {
+        filterTablesByRegex(descriptors, Pattern.compile(regex));
+      }
+
+      if (cpHost != null) {
+        cpHost.postGetTableDescriptors(descriptors);
+        // method required for AccessController.
+        cpHost.postGetTableDescriptors(tableNameList, descriptors, regex);
+      }
+    }
+    return descriptors;
+  }
+
+  /**
+   * Returns the list of table names that match the specified request
+   * @param regex The regular expression to match against, or null if querying for all
+   * @param includeSysTables False to match only against userspace tables
+   * @return the list of table names
+   */
+  public List<TableName> listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException {
+    final List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
+
+    boolean bypass = false;
+    if (cpHost != null) {
+      bypass = cpHost.preGetTableNames(descriptors, regex);
+    }
+
+    if (!bypass) {
+      // get all descriptors
+      Collection<HTableDescriptor> htds = tableDescriptors.getAll().values();
+      for (HTableDescriptor htd: htds) {
+        if (includeSysTables || !htd.getTableName().isSystemTable()) {
+          descriptors.add(htd);
+        }
+      }
+
+      // Retains only those matched by regular expression.
+      if (regex != null) {
+        filterTablesByRegex(descriptors, Pattern.compile(regex));
+      }
+
+      if (cpHost != null) {
+        cpHost.postGetTableNames(descriptors, regex);
+      }
+    }
+
+    List<TableName> result = new ArrayList(descriptors.size());
+    for (HTableDescriptor htd: descriptors) {
+      result.add(htd.getTableName());
+    }
+    return result;
+  }
+
+
+  /**
+   * Removes the table descriptors that don't match the pattern.
+   * @param descriptors list of table descriptors to filter
+   * @param pattern the regex to use
+   */
+  private static void filterTablesByRegex(final Collection<HTableDescriptor> descriptors,
+      final Pattern pattern) {
+    final String defaultNS = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
+      HTableDescriptor htd = itr.next();
+      String tableName = htd.getTableName().getNameAsString();
+      boolean matched = pattern.matcher(tableName).matches();
+      if (!matched && htd.getTableName().getNamespaceAsString().equals(defaultNS)) {
+        matched = pattern.matcher(defaultNS + TableName.NAMESPACE_DELIM + tableName).matches();
+      }
+      if (!matched) {
+        itr.remove();
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
index 2339090..a8e29b9 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
@@ -780,8 +780,9 @@ public class MasterCoprocessorHost
     });
   }
 
+  @Deprecated
   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
-      final List<HTableDescriptor> descriptors) throws IOException {
+    final List<HTableDescriptor> descriptors) throws IOException {
     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override
       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
@@ -791,6 +792,7 @@ public class MasterCoprocessorHost
     });
   }
 
+  @Deprecated
   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
       throws IOException {
     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
@@ -802,6 +804,50 @@ public class MasterCoprocessorHost
     });
   }
 
+  public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
+      final List<HTableDescriptor> descriptors, final String regex) throws IOException {
+    return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+      @Override
+      public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
+          throws IOException {
+        oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
+      }
+    });
+  }
+
+  public void postGetTableDescriptors(final List<TableName> tableNamesList,
+      final List<HTableDescriptor> descriptors, final String regex) throws IOException {
+    execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+      @Override
+      public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
+          throws IOException {
+        oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
+      }
+    });
+  }
+
+  public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
+      final String regex) throws IOException {
+    return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+      @Override
+      public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
+          throws IOException {
+        oserver.preGetTableNames(ctx, descriptors, regex);
+      }
+    });
+  }
+
+  public void postGetTableNames(final List<HTableDescriptor> descriptors,
+      final String regex) throws IOException {
+    execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+      @Override
+      public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
+          throws IOException {
+        oserver.postGetTableNames(ctx, descriptors, regex);
+      }
+    });
+  }
+
   public void preTableFlush(final TableName tableName) throws IOException {
     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index f03af9c..731f6f2 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -21,7 +21,6 @@ package org.apache.hadoop.hbase.master;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -775,67 +774,30 @@ public class MasterRpcServices extends RSRpcServices
       GetTableDescriptorsRequest req) throws ServiceException {
     try {
       master.checkInitialized();
-    } catch (IOException e) {
-      throw new ServiceException(e);
-    }
 
-    List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
-    List<TableName> tableNameList = new ArrayList<TableName>();
-    for(HBaseProtos.TableName tableNamePB: req.getTableNamesList()) {
-      tableNameList.add(ProtobufUtil.toTableName(tableNamePB));
-    }
-    boolean bypass = false;
-    if (master.cpHost != null) {
-      try {
-        bypass = master.cpHost.preGetTableDescriptors(tableNameList, descriptors);
-      } catch (IOException ioe) {
-        throw new ServiceException(ioe);
-      }
-    }
-
-    if (!bypass) {
-      if (req.getTableNamesCount() == 0) {
-        // request for all TableDescriptors
-        Map<String, HTableDescriptor> descriptorMap = null;
-        try {
-          descriptorMap = master.getTableDescriptors().getAll();
-        } catch (IOException e) {
-          LOG.warn("Failed getting all descriptors", e);
-        }
-        if (descriptorMap != null) {
-          for(HTableDescriptor desc: descriptorMap.values()) {
-            if(!desc.getTableName().isSystemTable()) {
-              descriptors.add(desc);
-            }
-          }
-        }
-      } else {
-        for (TableName s: tableNameList) {
-          try {
-            HTableDescriptor desc = master.getTableDescriptors().get(s);
-            if (desc != null) {
-              descriptors.add(desc);
-            }
-          } catch (IOException e) {
-            LOG.warn("Failed getting descriptor for " + s, e);
-          }
+      final String regex = req.hasRegex() ? req.getRegex() : null;
+      List<TableName> tableNameList = null;
+      if (req.getTableNamesCount() > 0) {
+        tableNameList = new ArrayList<TableName>(req.getTableNamesCount());
+        for (HBaseProtos.TableName tableNamePB: req.getTableNamesList()) {
+          tableNameList.add(ProtobufUtil.toTableName(tableNamePB));
         }
       }
 
-      if (master.cpHost != null) {
-        try {
-          master.cpHost.postGetTableDescriptors(descriptors);
-        } catch (IOException ioe) {
-          throw new ServiceException(ioe);
+      List<HTableDescriptor> descriptors = master.listTableDescriptors(regex, tableNameList,
+          req.getIncludeSysTables());
+
+      GetTableDescriptorsResponse.Builder builder = GetTableDescriptorsResponse.newBuilder();
+      if (descriptors != null && descriptors.size() > 0) {
+        // Add the table descriptors to the response
+        for (HTableDescriptor htd: descriptors) {
+          builder.addTableSchema(htd.convert());
         }
       }
+      return builder.build();
+    } catch (IOException ioe) {
+      throw new ServiceException(ioe);
     }
-
-    GetTableDescriptorsResponse.Builder builder = GetTableDescriptorsResponse.newBuilder();
-    for (HTableDescriptor htd: descriptors) {
-      builder.addTableSchema(htd.convert());
-    }
-    return builder.build();
   }
 
   /**
@@ -850,13 +812,16 @@ public class MasterRpcServices extends RSRpcServices
       GetTableNamesRequest req) throws ServiceException {
     try {
       master.checkInitialized();
-      Collection<HTableDescriptor> descriptors = master.getTableDescriptors().getAll().values();
+
+      final String regex = req.hasRegex() ? req.getRegex() : null;
+      List<TableName> tableNames = master.listTableNames(regex, req.getIncludeSysTables());
+
       GetTableNamesResponse.Builder builder = GetTableNamesResponse.newBuilder();
-      for (HTableDescriptor descriptor: descriptors) {
-        if (descriptor.getTableName().isSystemTable()) {
-          continue;
+      if (tableNames != null && tableNames.size() > 0) {
+        // Add the table names to the response
+        for (TableName table: tableNames) {
+          builder.addTableNames(ProtobufUtil.toProtoTableName(table));
         }
-        builder.addTableNames(ProtobufUtil.toProtoTableName(descriptor.getTableName()));
       }
       return builder.build();
     } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
index c174a01..444183c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
@@ -429,6 +429,36 @@ public class AccessController extends BaseMasterAndRegionObserver
   }
 
   /**
+   * Authorizes that the current user has any of the given permissions to access the table.
+   *
+   * @param tableName Table requested
+   * @param permissions Actions being requested
+   * @throws IOException if obtaining the current user fails
+   * @throws AccessDeniedException if user has no authorization
+   */
+  private void requireAccess(String request, TableName tableName,
+      Action... permissions) throws IOException {
+    User user = getActiveUser();
+    AuthResult result = null;
+
+    for (Action permission : permissions) {
+      if (authManager.hasAccess(user, tableName, permission)) {
+        result = AuthResult.allow(request, "Table permission granted", user,
+                                  permission, tableName, null, null);
+        break;
+      } else {
+        // rest of the world
+        result = AuthResult.deny(request, "Insufficient permissions", user,
+                                 permission, tableName, null, null);
+      }
+    }
+    logResult(result);
+    if (!result.isAllowed()) {
+      throw new AccessDeniedException("Insufficient permissions " + result.toContextString());
+    }
+  }
+
+  /**
    * Authorizes that the current user has global privileges for the given action.
    * @param perm The action being requested
    * @throws IOException if obtaining the current user fails
@@ -974,7 +1004,7 @@ public class AccessController extends BaseMasterAndRegionObserver
       TableName tableName, final HTableDescriptor htd) throws IOException {
     final Configuration conf = c.getEnvironment().getConfiguration();
     // default the table owner to current user, if not specified.
-    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() : 
+    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() :
       getActiveUser().getShortName();
     User.runAsLoginUser(new PrivilegedExceptionAction<Void>() {
       @Override
@@ -2230,16 +2260,13 @@ public class AccessController extends BaseMasterAndRegionObserver
 
   @Override
   public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList,
-      List<HTableDescriptor> descriptors) throws IOException {
-    // If the list is empty, this is a request for all table descriptors and requires GLOBAL
-    // ADMIN privs.
-    if (tableNamesList == null || tableNamesList.isEmpty()) {
-      requireGlobalPermission("getTableDescriptors", Action.ADMIN, null, null);
-    }
-    // Otherwise, if the requestor has ADMIN or CREATE privs for all listed tables, the
-    // request can be granted.
-    else {
+       List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+       String regex) throws IOException {
+    // We are delegating the authorization check to postGetTableDescriptors as we don't have
+    // any concrete set of table names when a regex is present or the full list is requested.
+    if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) {
+      // Otherwise, if the requestor has ADMIN or CREATE privs for all listed tables, the
+      // request can be granted.
       MasterServices masterServices = ctx.getEnvironment().getMasterServices();
       for (TableName tableName: tableNamesList) {
         // Skip checks for a table that does not exist
@@ -2247,7 +2274,45 @@ public class AccessController extends BaseMasterAndRegionObserver
           continue;
         }
         requirePermission("getTableDescriptors", tableName, null, null,
-          Action.ADMIN, Action.CREATE);
+            Action.ADMIN, Action.CREATE);
+      }
+    }
+  }
+
+  @Override
+  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
+    // Skipping as checks in this case are already done by preGetTableDescriptors.
+    if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) {
+      return;
+    }
+
+    // Retains only those which passes authorization checks, as the checks weren't done as part
+    // of preGetTableDescriptors.
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
+      HTableDescriptor htd = itr.next();
+      try {
+        requirePermission("getTableDescriptors", htd.getTableName(), null, null,
+            Action.ADMIN, Action.CREATE);
+      } catch (AccessDeniedException e) {
+        itr.remove();
+      }
+    }
+  }
+
+  @Override
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+    // Retains only those which passes authorization checks.
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
+      HTableDescriptor htd = itr.next();
+      try {
+        requireAccess("getTableNames", htd.getTableName(), Action.values());
+      } catch (AccessDeniedException e) {
+        itr.remove();
       }
     }
   }


[3/4] hbase git commit: HBASE-12564 consolidate the getTableDescriptors() semantic

Posted by mb...@apache.org.
http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
index ae4af26..4ed81dc 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
@@ -223,7 +223,7 @@ public class TableAuthManager {
    * Updates the internal permissions cache for a single table, splitting
    * the permissions listed into separate caches for users and groups to optimize
    * group lookups.
-   * 
+   *
    * @param table
    * @param tablePerms
    */
@@ -349,6 +349,20 @@ public class TableAuthManager {
     return false;
   }
 
+  private boolean hasAccess(List<TablePermission> perms,
+                            TableName table, Permission.Action action) {
+    if (perms != null) {
+      for (TablePermission p : perms) {
+        if (p.implies(action)) {
+          return true;
+        }
+      }
+    } else if (LOG.isDebugEnabled()) {
+      LOG.debug("No permissions found for table="+table);
+    }
+    return false;
+  }
+
   /**
    * Authorize a user for a given KV. This is called from AccessControlFilter.
    */
@@ -442,7 +456,7 @@ public class TableAuthManager {
       byte[] qualifier, Permission.Action action) {
     if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
     // Global and namespace authorizations supercede table level
-    if (authorize(user, table.getNamespaceAsString(), action)) {    
+    if (authorize(user, table.getNamespaceAsString(), action)) {
       return true;
     }
     // Check table permissions
@@ -451,6 +465,25 @@ public class TableAuthManager {
   }
 
   /**
+   * Checks if the user has access to the full table or at least a family/qualifier
+   * for the specified action.
+   *
+   * @param user
+   * @param table
+   * @param action
+   * @return true if the user has access to the table, false otherwise
+   */
+  public boolean userHasAccess(User user, TableName table, Permission.Action action) {
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Global and namespace authorizations supercede table level
+    if (authorize(user, table.getNamespaceAsString(), action)) {
+      return true;
+    }
+    // Check table permissions
+    return hasAccess(getTablePermissions(table).getUser(user.getShortName()), table, action);
+  }
+
+  /**
    * Checks global authorization for a given action for a group, based on the stored
    * permissions.
    */
@@ -460,7 +493,7 @@ public class TableAuthManager {
 
   /**
    * Checks authorization to a given table and column family for a group, based
-   * on the stored permissions. 
+   * on the stored permissions.
    * @param groupName
    * @param table
    * @param family
@@ -483,6 +516,29 @@ public class TableAuthManager {
     return authorize(getTablePermissions(table).getGroup(groupName), table, family, action);
   }
 
+  /**
+   * Checks if the user has access to the full table or at least a family/qualifier
+   * for the specified action.
+   * @param groupName
+   * @param table
+   * @param action
+   * @return true if the group has access to the table, false otherwise
+   */
+  public boolean groupHasAccess(String groupName, TableName table, Permission.Action action) {
+    // Global authorization supercedes table level
+    if (authorizeGroup(groupName, action)) {
+      return true;
+    }
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Namespace authorization supercedes table level
+    if (hasAccess(getNamespacePermissions(table.getNamespaceAsString()).getGroup(groupName),
+        table, action)) {
+      return true;
+    }
+    // Check table level
+    return hasAccess(getTablePermissions(table).getGroup(groupName), table, action);
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       byte[] qualifier, Permission.Action action) {
     if (authorizeUser(user, table, family, qualifier, action)) {
@@ -500,6 +556,22 @@ public class TableAuthManager {
     return false;
   }
 
+  public boolean hasAccess(User user, TableName table, Permission.Action action) {
+    if (userHasAccess(user, table, action)) {
+      return true;
+    }
+
+    String[] groups = user.getGroupNames();
+    if (groups != null) {
+      for (String group : groups) {
+        if (groupHasAccess(group, table, action)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       Permission.Action action) {
     return authorize(user, table, family, null, action);

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
index 22e9e67..dc4253e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
@@ -55,6 +55,7 @@ import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.RequestConverter;
 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
+import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Threads;
@@ -146,6 +147,8 @@ public class TestMasterObserver {
     private boolean postModifyTableHandlerCalled;
     private boolean preGetTableDescriptorsCalled;
     private boolean postGetTableDescriptorsCalled;
+    private boolean postGetTableNamesCalled;
+    private boolean preGetTableNamesCalled;
 
     public void enableBypass(boolean bypass) {
       this.bypass = bypass;
@@ -218,6 +221,8 @@ public class TestMasterObserver {
       postModifyTableHandlerCalled = false;
       preGetTableDescriptorsCalled = false;
       postGetTableDescriptorsCalled = false;
+      postGetTableNamesCalled = false;
+      preGetTableNamesCalled = false;
     }
 
     @Override
@@ -656,11 +661,11 @@ public class TestMasterObserver {
         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
       preMasterInitializationCalled = true;
     }
-    
+
     public boolean wasMasterInitializationCalled(){
       return preMasterInitializationCalled;
     }
-    
+
     @Override
     public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
         throws IOException {
@@ -984,14 +989,25 @@ public class TestMasterObserver {
 
     @Override
     public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-        List<TableName> tableNamesList, List<HTableDescriptor> descriptors)
-        throws IOException {
-      preGetTableDescriptorsCalled = true;
+        List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException {
     }
 
     @Override
     public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
         List<HTableDescriptor> descriptors) throws IOException {
+    }
+
+    @Override
+    public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+        String regex) throws IOException {
+      preGetTableDescriptorsCalled = true;
+    }
+
+    @Override
+    public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+        String regex) throws IOException {
       postGetTableDescriptorsCalled = true;
     }
 
@@ -1000,6 +1016,22 @@ public class TestMasterObserver {
     }
 
     @Override
+    public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<HTableDescriptor> descriptors, String regex) throws IOException {
+      preGetTableNamesCalled = true;
+    }
+
+    @Override
+    public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<HTableDescriptor> descriptors, String regex) throws IOException {
+      postGetTableNamesCalled = true;
+    }
+
+    public boolean wasGetTableNamesCalled() {
+      return preGetTableNamesCalled && postGetTableNamesCalled;
+    }
+
+    @Override
     public void preTableFlush(ObserverContext<MasterCoprocessorEnvironment> ctx,
         TableName tableName) throws IOException {
     }
@@ -1465,4 +1497,19 @@ public class TestMasterObserver {
       cp.wasGetTableDescriptorsCalled());
   }
 
+  @Test
+  public void testTableNamesEnumeration() throws Exception {
+    MiniHBaseCluster cluster = UTIL.getHBaseCluster();
+
+    HMaster master = cluster.getMaster();
+    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
+    CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
+        CPMasterObserver.class.getName());
+    cp.resetStates();
+
+    master.getMasterRpcServices().getTableNames(null,
+        GetTableNamesRequest.newBuilder().build());
+    assertTrue("Coprocessor should be called on table names request",
+      cp.wasGetTableNamesCalled());
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
index af734df..b5d7e3d 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
@@ -20,10 +20,13 @@ package org.apache.hadoop.hbase.security.access;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.logging.Log;
@@ -259,7 +262,7 @@ public class TestAccessController extends SecureTestUtil {
     try {
       assertEquals(4, AccessControlClient.getUserPermissions(conf, TEST_TABLE.toString()).size());
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.getUserPermissions. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
     }
   }
 
@@ -1992,11 +1995,14 @@ public class TestAccessController extends SecureTestUtil {
     AccessTestAction listTablesAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.listTables();
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
@@ -2005,24 +2011,48 @@ public class TestAccessController extends SecureTestUtil {
     AccessTestAction getTableDescAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.getTableDescriptor(TEST_TABLE.getTableName());
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
     };
 
-    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN);
-    verifyDenied(listTablesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, TABLE_ADMIN);
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
+    verifyDenied(listTablesAction, USER_RW, USER_RO, USER_NONE);
 
     verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, TABLE_ADMIN);
     verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE);
   }
 
   @Test
+  public void testTableNameEnumeration() throws Exception {
+    AccessTestAction listTablesAction = new AccessTestAction() {
+      @Override
+      public Object run() throws Exception {
+        Connection unmanagedConnection =
+            ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
+        try {
+          return Arrays.asList(admin.listTableNames());
+        } finally {
+          admin.close();
+          unmanagedConnection.close();
+        }
+      }
+    };
+
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, USER_RW, USER_RO);
+    verifyDenied(listTablesAction, USER_NONE);
+  }
+
+  @Test
   public void testTableDeletion() throws Exception {
     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new String[0]);
 
@@ -2099,7 +2129,7 @@ public class TestAccessController extends SecureTestUtil {
       grantOnTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testGrantRevoke should be able to read also
@@ -2110,7 +2140,7 @@ public class TestAccessController extends SecureTestUtil {
       revokeFromTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
           TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testGrantRevoke shouldn't be able read
@@ -2140,7 +2170,7 @@ public class TestAccessController extends SecureTestUtil {
       grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testNS should be able to read also
@@ -2151,7 +2181,7 @@ public class TestAccessController extends SecureTestUtil {
       revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
           TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testNS shouldn't be able read
@@ -2262,7 +2292,7 @@ public class TestAccessController extends SecureTestUtil {
         try {
           KeyValue kv = new KeyValue(TEST_ROW, TEST_FAMILY, TEST_QUALIFIER,
             HConstants.LATEST_TIMESTAMP, HConstants.EMPTY_BYTE_ARRAY,
-            new Tag[] { new Tag(AccessControlLists.ACL_TAG_TYPE, 
+            new Tag[] { new Tag(AccessControlLists.ACL_TAG_TYPE,
               ProtobufUtil.toUsersAndPermissions(USER_OWNER.getShortName(),
                 new Permission(Permission.Action.READ)).toByteArray()) });
           t.put(new Put(TEST_ROW).add(kv));
@@ -2314,4 +2344,88 @@ public class TestAccessController extends SecureTestUtil {
       assertEquals(existingPerms.size(), perms.size());
     }
   }
+
+  private PrivilegedAction<List<UserPermission>> getPrivilegedAction(final String regex) {
+    return new PrivilegedAction<List<UserPermission>>() {
+      @Override
+      public List<UserPermission> run() {
+        try {
+          return AccessControlClient.getUserPermissions(conf, regex);
+        } catch (Throwable e) {
+          LOG.error("error during call of AccessControlClient.getUserPermissions.", e);
+          return null;
+        }
+      }
+    };
+  }
+
+  @Test
+  public void testAccessControlClientUserPerms() throws Exception {
+    // adding default prefix explicitly as it is not included in the table name.
+    assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR,
+                 TEST_TABLE.getTableName().getNamespaceAsString());
+    final String regex = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR +
+      TableName.NAMESPACE_DELIM + TEST_TABLE.getTableName().getNameAsString();
+    User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new String[0]);
+    assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
+    // Grant TABLE ADMIN privs to testUserPerms
+    grantOnTable(TEST_UTIL, testUserPerms.getShortName(), TEST_TABLE.getTableName(), null,
+      null, Action.ADMIN);
+    List<UserPermission> perms = testUserPerms.runAs(getPrivilegedAction(regex));
+    assertNotNull(perms);
+    // USER_ADMIN, USER_CREATE, USER_RW, USER_RO, testUserPerms has row each.
+    assertEquals(5, perms.size());
+  }
+
+  @Test
+  public void testAccessControllerUserPermsRegexHandling() throws Exception {
+    User testRegexHandler = User.createUserForTesting(conf, "testRegexHandling", new String[0]);
+
+    final String REGEX_ALL_TABLES = ".*";
+    final String tableName = "testRegex";
+    final TableName table1 = TableName.valueOf(tableName);
+    final byte[] family = Bytes.toBytes("f1");
+
+    // create table in default ns
+    Admin admin = TEST_UTIL.getHBaseAdmin();
+    HTableDescriptor htd = new HTableDescriptor(table1);
+    htd.addFamily(new HColumnDescriptor(family));
+    admin.createTable(htd);
+    TEST_UTIL.waitUntilAllRegionsAssigned(table1);
+
+    // creating the ns and table in it
+    String ns = "testNamespace";
+    NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
+    final TableName table2 = TableName.valueOf(ns, tableName);
+    TEST_UTIL.getMiniHBaseCluster().getMaster().createNamespace(desc);
+    htd = new HTableDescriptor(table2);
+    htd.addFamily(new HColumnDescriptor(family));
+    admin.createTable(htd);
+    TEST_UTIL.waitUntilAllRegionsAssigned(table2);
+
+    // Verify that we can read sys-tables
+    String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString();
+    assertEquals(1, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
+    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
+
+    // Grant TABLE ADMIN privs to testUserPerms
+    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
+    grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, null, Action.ADMIN);
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
+    grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, null, Action.ADMIN);
+    assertEquals(4, testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
+
+    // USER_ADMIN, testUserPerms must have a row each.
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+          NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + TableName.NAMESPACE_DELIM + tableName)
+        ).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+        ns + TableName.NAMESPACE_DELIM + tableName)).size());
+    assertEquals(0, testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
+
+    TEST_UTIL.deleteTable(table1);
+    TEST_UTIL.deleteTable(table2);
+    TEST_UTIL.getMiniHBaseCluster().getMaster().deleteNamespace(ns);
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/09617cc2/hbase-shell/src/main/ruby/hbase/admin.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 2c8828e..748a41c 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -43,7 +43,7 @@ module Hbase
     #----------------------------------------------------------------------------------------------
     # Returns a list of tables in hbase
     def list(regex = ".*")
-      @admin.getTableNames(regex).to_a
+      @admin.listTableNames(regex).map { |t| t.getNameAsString }
     end
 
     #----------------------------------------------------------------------------------------------


[2/4] hbase git commit: HBASE-12564 consolidate the getTableDescriptors() semantic

Posted by mb...@apache.org.
HBASE-12564 consolidate the getTableDescriptors() semantic


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/8a2c8415
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/8a2c8415
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/8a2c8415

Branch: refs/heads/master
Commit: 8a2c84156a2829f44307e5aff07323902580af86
Parents: b437125
Author: Matteo Bertozzi <ma...@cloudera.com>
Authored: Tue Dec 9 12:06:00 2014 +0000
Committer: Matteo Bertozzi <ma...@cloudera.com>
Committed: Tue Dec 9 12:06:00 2014 +0000

----------------------------------------------------------------------
 .../org/apache/hadoop/hbase/client/Admin.java   |  60 ++
 .../hadoop/hbase/client/ConnectionAdapter.java  |   7 +-
 .../hadoop/hbase/client/ConnectionManager.java  |  14 -
 .../apache/hadoop/hbase/client/HBaseAdmin.java  | 107 ++--
 .../apache/hadoop/hbase/client/HConnection.java |   7 -
 .../hadoop/hbase/protobuf/RequestConverter.java |  25 +-
 .../security/access/AccessControlClient.java    |   2 +-
 .../hbase/protobuf/generated/MasterProtos.java  | 569 +++++++++++++++----
 hbase-protocol/src/main/protobuf/Master.proto   |   3 +
 .../BaseMasterAndRegionObserver.java            |  16 +-
 .../hbase/coprocessor/BaseMasterObserver.java   |  15 +-
 .../hbase/coprocessor/MasterObserver.java       |  29 +-
 .../org/apache/hadoop/hbase/master/HMaster.java | 117 +++-
 .../hbase/master/MasterCoprocessorHost.java     |  24 +-
 .../hadoop/hbase/master/MasterRpcServices.java  | 108 +---
 .../hbase/security/access/AccessController.java |  87 ++-
 .../hbase/security/access/TableAuthManager.java |  78 ++-
 .../hbase/coprocessor/TestMasterObserver.java   |  47 +-
 .../security/access/TestAccessController.java   |  83 ++-
 hbase-shell/src/main/ruby/hbase/admin.rb        |   2 +-
 20 files changed, 1023 insertions(+), 377 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
index b9c6432..c5d9556 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java
@@ -115,6 +115,30 @@ public interface Admin extends Abortable, Closeable {
   HTableDescriptor[] listTables(String regex) throws IOException;
 
   /**
+   * List all the tables matching the given pattern.
+   *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return - returns an array of HTableDescriptors
+   * @throws IOException if a remote or network exception occurs
+   * @see #listTables()
+   */
+  HTableDescriptor[] listTables(Pattern pattern, boolean includeSysTables)
+      throws IOException;
+
+  /**
+   * List all the tables matching the given pattern.
+   *
+   * @param regex The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return - returns an array of HTableDescriptors
+   * @throws IOException if a remote or network exception occurs
+   * @see #listTables(java.util.regex.Pattern, boolean)
+   */
+  HTableDescriptor[] listTables(String regex, boolean includeSysTables)
+      throws IOException;
+
+  /**
    * List all of the names of userspace tables.
    *
    * @return TableName[] table names
@@ -123,6 +147,42 @@ public interface Admin extends Abortable, Closeable {
   TableName[] listTableNames() throws IOException;
 
   /**
+   * List all of the names of userspace tables.
+   * @param pattern The regular expression to match against
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(Pattern pattern) throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param regex The regular expression to match against
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(String regex) throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param pattern The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(final Pattern pattern, final boolean includeSysTables)
+      throws IOException;
+
+  /**
+   * List all of the names of userspace tables.
+   * @param regex The regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return TableName[] table names
+   * @throws IOException if a remote or network exception occurs
+   */
+  TableName[] listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException;
+
+  /**
    * Method for getting the tableDescriptor
    *
    * @param tableName as a {@link TableName}

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
index d8856ad..a30ce9d 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionAdapter.java
@@ -38,7 +38,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
 /**
  * An internal class that delegates to an {@link HConnection} instance.
  * A convenience to override when customizing method implementations.
- * 
+ *
  *
  * @see ConnectionUtils#createShortCircuitHConnection(HConnection, ServerName,
  * AdminService.BlockingInterface, ClientService.BlockingInterface) for case where we make
@@ -177,11 +177,6 @@ abstract class ConnectionAdapter implements ClusterConnection {
   }
 
   @Override
-  public HTableDescriptor[] listTables(String regex) throws IOException {
-    return wrappedConnection.listTables(regex);
-  }
-
-  @Override
   public String[] getTableNames() throws IOException {
     return wrappedConnection.getTableNames();
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
index 7f599da..ce8651c 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java
@@ -2384,20 +2384,6 @@ class ConnectionManager {
      */
     @Deprecated
     @Override
-    public HTableDescriptor[] listTables(String regex) throws IOException {
-      MasterKeepAliveConnection master = getKeepAliveMasterService();
-      try {
-        GetTableDescriptorsRequest req =
-            RequestConverter.buildGetTableDescriptorsRequest(regex);
-        return ProtobufUtil.getHTableDescriptorArray(master.getTableDescriptors(null, req));
-      } catch (ServiceException se) {
-        throw ProtobufUtil.getRemoteException(se);
-      } finally {
-        master.close();
-      }
-    }
-
-    @Override
     public String[] getTableNames() throws IOException {
       TableName[] tableNames = listTableNames();
       String result[] = new String[tableNames.length];

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
index 2289ad8..0677606 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
@@ -296,52 +296,38 @@ public class HBaseAdmin implements Admin {
     return tableExists(TableName.valueOf(tableName));
   }
 
-  /**
-   * List all the userspace tables.  In other words, scan the hbase:meta table.
-   *
-   * If we wanted this to be really fast, we could implement a special
-   * catalog table that just contains table names and their descriptors.
-   * Right now, it only exists as part of the hbase:meta table's region info.
-   *
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   */
   @Override
   public HTableDescriptor[] listTables() throws IOException {
-   return executeCallable(new MasterCallable<HTableDescriptor[]>(getConnection()) {
+    return listTables((Pattern)null, false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(Pattern pattern) throws IOException {
+    return listTables(pattern, false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(String regex) throws IOException {
+    return listTables(Pattern.compile(regex), false);
+  }
+
+  @Override
+  public HTableDescriptor[] listTables(final Pattern pattern, final boolean includeSysTables)
+      throws IOException {
+    return executeCallable(new MasterCallable<HTableDescriptor[]>(getConnection()) {
       @Override
       public HTableDescriptor[] call(int callTimeout) throws ServiceException {
         GetTableDescriptorsRequest req =
-            RequestConverter.buildGetTableDescriptorsRequest((List<TableName>)null);
+            RequestConverter.buildGetTableDescriptorsRequest(pattern, includeSysTables);
         return ProtobufUtil.getHTableDescriptorArray(master.getTableDescriptors(null, req));
       }
     });
   }
 
-  /**
-   * List all the userspace tables matching the given pattern.
-   *
-   * @param pattern The compiled regular expression to match against
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   * @see #listTables()
-   */
   @Override
-  public HTableDescriptor[] listTables(Pattern pattern) throws IOException {
-    return this.connection.listTables(pattern.toString());
-  }
-
-  /**
-   * List all the userspace tables matching the given regular expression.
-   *
-   * @param regex The regular expression to match against
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   * @see #listTables(java.util.regex.Pattern)
-   */
-  @Override
-  public HTableDescriptor[] listTables(String regex) throws IOException {
-    return listTables(Pattern.compile(regex));
+  public HTableDescriptor[] listTables(String regex, boolean includeSysTables)
+      throws IOException {
+    return listTables(Pattern.compile(regex), includeSysTables);
   }
 
   /**
@@ -365,17 +351,16 @@ public class HBaseAdmin implements Admin {
    * @param pattern The regular expression to match against
    * @return String[] table names
    * @throws IOException if a remote or network exception occurs
-   * @deprecated Use {@link Admin#listTables(Pattern)} instead.
+   * @deprecated Use {@link Admin#listTableNames(Pattern)} instead.
    */
   @Deprecated
   public String[] getTableNames(Pattern pattern) throws IOException {
-    List<String> matched = new ArrayList<String>();
-    for (String name: getTableNames()) {
-      if (pattern.matcher(name).matches()) {
-        matched.add(name);
-      }
+    TableName[] tableNames = listTableNames(pattern);
+    String result[] = new String[tableNames.length];
+    for (int i = 0; i < tableNames.length; i++) {
+      result[i] = tableNames[i].getNameAsString();
     }
-    return matched.toArray(new String[matched.size()]);
+    return result;
   }
 
   /**
@@ -383,30 +368,48 @@ public class HBaseAdmin implements Admin {
    * @param regex The regular expression to match against
    * @return String[] table names
    * @throws IOException if a remote or network exception occurs
-   * @deprecated Use {@link Admin#listTables(Pattern)} instead.
+   * @deprecated Use {@link Admin#listTableNames(Pattern)} instead.
    */
   @Deprecated
   public String[] getTableNames(String regex) throws IOException {
     return getTableNames(Pattern.compile(regex));
   }
 
-  /**
-   * List all of the names of userspace tables.
-   * @return TableName[] table names
-   * @throws IOException if a remote or network exception occurs
-   */
   @Override
   public TableName[] listTableNames() throws IOException {
+    return listTableNames((Pattern)null, false);
+  }
+
+  @Override
+  public TableName[] listTableNames(Pattern pattern) throws IOException {
+    return listTableNames(pattern, false);
+  }
+
+  @Override
+  public TableName[] listTableNames(String regex) throws IOException {
+    return listTableNames(Pattern.compile(regex), false);
+  }
+
+  @Override
+  public TableName[] listTableNames(final Pattern pattern, final boolean includeSysTables)
+      throws IOException {
     return executeCallable(new MasterCallable<TableName[]>(getConnection()) {
       @Override
       public TableName[] call(int callTimeout) throws ServiceException {
-        return ProtobufUtil.getTableNameArray(master.getTableNames(null,
-          GetTableNamesRequest.newBuilder().build())
-        .getTableNamesList());
+        GetTableNamesRequest req =
+            RequestConverter.buildGetTableNamesRequest(pattern, includeSysTables);
+        return ProtobufUtil.getTableNameArray(master.getTableNames(null, req)
+            .getTableNamesList());
       }
     });
   }
 
+  @Override
+  public TableName[] listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException {
+    return listTableNames(Pattern.compile(regex), includeSysTables);
+  }
+
   /**
    * Method for getting the tableDescriptor
    * @param tableName as a byte []
@@ -2669,7 +2672,7 @@ public class HBaseAdmin implements Admin {
   }
 
   /**
-   * Roll the log writer. I.e. when using a file system based write ahead log, 
+   * Roll the log writer. I.e. when using a file system based write ahead log,
    * start writing log messages to a new file.
    *
    * Note that when talking to a version 1.0+ HBase deployment, the rolling is asynchronous.

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
index 7add87b..9a4ef69 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HConnection.java
@@ -258,13 +258,6 @@ public interface HConnection extends Connection {
   @Deprecated
   HTableDescriptor[] listTables() throws IOException;
 
-  /**
-   * List all the userspace tables matching the pattern.
-   * @return - returns an array of HTableDescriptors
-   * @throws IOException if a remote or network exception occurs
-   */
-  HTableDescriptor[] listTables(String pattern) throws IOException;
-
   // This is a bit ugly - We call this getTableNames in 0.94 and the
   // successor function, returning TableName, listTableNames in later versions
   // because Java polymorphism doesn't consider return value types

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
index 2d8c53e..d23aa02 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.protobuf;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import org.apache.hadoop.hbase.CellScannable;
 import org.apache.hadoop.hbase.DoNotRetryIOException;
@@ -88,6 +89,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableReques
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterStatusRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetSchemaAlterStatusRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
+import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableStateRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledRequest;
 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsMasterRunningRequest;
@@ -1229,11 +1231,30 @@ public final class RequestConverter {
   /**
    * Creates a protocol buffer GetTableDescriptorsRequest
    *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
    * @return a GetTableDescriptorsRequest
    */
-  public static GetTableDescriptorsRequest buildGetTableDescriptorsRequest(final String pattern) {
+  public static GetTableDescriptorsRequest buildGetTableDescriptorsRequest(final Pattern pattern,
+      boolean includeSysTables) {
     GetTableDescriptorsRequest.Builder builder = GetTableDescriptorsRequest.newBuilder();
-    builder.setRegex(pattern);
+    if (pattern != null) builder.setRegex(pattern.toString());
+    builder.setIncludeSysTables(includeSysTables);
+    return builder.build();
+  }
+
+  /**
+   * Creates a protocol buffer GetTableNamesRequest
+   *
+   * @param pattern The compiled regular expression to match against
+   * @param includeSysTables False to match only against userspace tables
+   * @return a GetTableNamesRequest
+   */
+  public static GetTableNamesRequest buildGetTableNamesRequest(final Pattern pattern,
+      boolean includeSysTables) {
+    GetTableNamesRequest.Builder builder = GetTableNamesRequest.newBuilder();
+    if (pattern != null) builder.setRegex(pattern.toString());
+    builder.setIncludeSysTables(includeSysTables);
     return builder.build();
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
index ae43c17..521c58b 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
@@ -178,7 +178,7 @@ public class AccessControlClient {
             String namespace = tableRegex.substring(1);
             permList = ProtobufUtil.getUserPermissions(protocol, Bytes.toBytes(namespace));
           } else {
-            htds = admin.listTables(Pattern.compile(tableRegex));
+            htds = admin.listTables(Pattern.compile(tableRegex), true);
             for (HTableDescriptor hd : htds) {
               permList.addAll(ProtobufUtil.getUserPermissions(protocol, hd.getTableName()));
             }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
index caeea87..90d5764 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/MasterProtos.java
@@ -34196,6 +34196,16 @@ public final class MasterProtos {
      */
     com.google.protobuf.ByteString
         getRegexBytes();
+
+    // optional bool include_sys_tables = 3 [default = false];
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    boolean hasIncludeSysTables();
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    boolean getIncludeSysTables();
   }
   /**
    * Protobuf type {@code GetTableDescriptorsRequest}
@@ -34261,6 +34271,11 @@ public final class MasterProtos {
               regex_ = input.readBytes();
               break;
             }
+            case 24: {
+              bitField0_ |= 0x00000002;
+              includeSysTables_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -34383,9 +34398,26 @@ public final class MasterProtos {
       }
     }
 
+    // optional bool include_sys_tables = 3 [default = false];
+    public static final int INCLUDE_SYS_TABLES_FIELD_NUMBER = 3;
+    private boolean includeSysTables_;
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    public boolean hasIncludeSysTables() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional bool include_sys_tables = 3 [default = false];</code>
+     */
+    public boolean getIncludeSysTables() {
+      return includeSysTables_;
+    }
+
     private void initFields() {
       tableNames_ = java.util.Collections.emptyList();
       regex_ = "";
+      includeSysTables_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -34411,6 +34443,9 @@ public final class MasterProtos {
       if (((bitField0_ & 0x00000001) == 0x00000001)) {
         output.writeBytes(2, getRegexBytes());
       }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBool(3, includeSysTables_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -34428,6 +34463,10 @@ public final class MasterProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(2, getRegexBytes());
       }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(3, includeSysTables_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -34458,6 +34497,11 @@ public final class MasterProtos {
         result = result && getRegex()
             .equals(other.getRegex());
       }
+      result = result && (hasIncludeSysTables() == other.hasIncludeSysTables());
+      if (hasIncludeSysTables()) {
+        result = result && (getIncludeSysTables()
+            == other.getIncludeSysTables());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -34479,6 +34523,10 @@ public final class MasterProtos {
         hash = (37 * hash) + REGEX_FIELD_NUMBER;
         hash = (53 * hash) + getRegex().hashCode();
       }
+      if (hasIncludeSysTables()) {
+        hash = (37 * hash) + INCLUDE_SYS_TABLES_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getIncludeSysTables());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -34597,6 +34645,8 @@ public final class MasterProtos {
         }
         regex_ = "";
         bitField0_ = (bitField0_ & ~0x00000002);
+        includeSysTables_ = false;
+        bitField0_ = (bitField0_ & ~0x00000004);
         return this;
       }
 
@@ -34638,6 +34688,10 @@ public final class MasterProtos {
           to_bitField0_ |= 0x00000001;
         }
         result.regex_ = regex_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.includeSysTables_ = includeSysTables_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -34685,6 +34739,9 @@ public final class MasterProtos {
           regex_ = other.regex_;
           onChanged();
         }
+        if (other.hasIncludeSysTables()) {
+          setIncludeSysTables(other.getIncludeSysTables());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -35032,6 +35089,39 @@ public final class MasterProtos {
         return this;
       }
 
+      // optional bool include_sys_tables = 3 [default = false];
+      private boolean includeSysTables_ ;
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public boolean hasIncludeSysTables() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public boolean getIncludeSysTables() {
+        return includeSysTables_;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public Builder setIncludeSysTables(boolean value) {
+        bitField0_ |= 0x00000004;
+        includeSysTables_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 3 [default = false];</code>
+       */
+      public Builder clearIncludeSysTables() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        includeSysTables_ = false;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:GetTableDescriptorsRequest)
     }
 
@@ -35766,6 +35856,31 @@ public final class MasterProtos {
 
   public interface GetTableNamesRequestOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
+
+    // optional string regex = 1;
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    boolean hasRegex();
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    java.lang.String getRegex();
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getRegexBytes();
+
+    // optional bool include_sys_tables = 2 [default = false];
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    boolean hasIncludeSysTables();
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    boolean getIncludeSysTables();
   }
   /**
    * Protobuf type {@code GetTableNamesRequest}
@@ -35800,6 +35915,7 @@ public final class MasterProtos {
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       initFields();
+      int mutable_bitField0_ = 0;
       com.google.protobuf.UnknownFieldSet.Builder unknownFields =
           com.google.protobuf.UnknownFieldSet.newBuilder();
       try {
@@ -35817,6 +35933,16 @@ public final class MasterProtos {
               }
               break;
             }
+            case 10: {
+              bitField0_ |= 0x00000001;
+              regex_ = input.readBytes();
+              break;
+            }
+            case 16: {
+              bitField0_ |= 0x00000002;
+              includeSysTables_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -35856,7 +35982,69 @@ public final class MasterProtos {
       return PARSER;
     }
 
+    private int bitField0_;
+    // optional string regex = 1;
+    public static final int REGEX_FIELD_NUMBER = 1;
+    private java.lang.Object regex_;
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public boolean hasRegex() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public java.lang.String getRegex() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          regex_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string regex = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getRegexBytes() {
+      java.lang.Object ref = regex_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        regex_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional bool include_sys_tables = 2 [default = false];
+    public static final int INCLUDE_SYS_TABLES_FIELD_NUMBER = 2;
+    private boolean includeSysTables_;
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    public boolean hasIncludeSysTables() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional bool include_sys_tables = 2 [default = false];</code>
+     */
+    public boolean getIncludeSysTables() {
+      return includeSysTables_;
+    }
+
     private void initFields() {
+      regex_ = "";
+      includeSysTables_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -35870,6 +36058,12 @@ public final class MasterProtos {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBool(2, includeSysTables_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -35879,6 +36073,14 @@ public final class MasterProtos {
       if (size != -1) return size;
 
       size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getRegexBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(2, includeSysTables_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -35902,6 +36104,16 @@ public final class MasterProtos {
       org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest other = (org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest) obj;
 
       boolean result = true;
+      result = result && (hasRegex() == other.hasRegex());
+      if (hasRegex()) {
+        result = result && getRegex()
+            .equals(other.getRegex());
+      }
+      result = result && (hasIncludeSysTables() == other.hasIncludeSysTables());
+      if (hasIncludeSysTables()) {
+        result = result && (getIncludeSysTables()
+            == other.getIncludeSysTables());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -35915,6 +36127,14 @@ public final class MasterProtos {
       }
       int hash = 41;
       hash = (19 * hash) + getDescriptorForType().hashCode();
+      if (hasRegex()) {
+        hash = (37 * hash) + REGEX_FIELD_NUMBER;
+        hash = (53 * hash) + getRegex().hashCode();
+      }
+      if (hasIncludeSysTables()) {
+        hash = (37 * hash) + INCLUDE_SYS_TABLES_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getIncludeSysTables());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -36024,6 +36244,10 @@ public final class MasterProtos {
 
       public Builder clear() {
         super.clear();
+        regex_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        includeSysTables_ = false;
+        bitField0_ = (bitField0_ & ~0x00000002);
         return this;
       }
 
@@ -36050,6 +36274,17 @@ public final class MasterProtos {
 
       public org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest buildPartial() {
         org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest result = new org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.regex_ = regex_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.includeSysTables_ = includeSysTables_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -36065,6 +36300,14 @@ public final class MasterProtos {
 
       public Builder mergeFrom(org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest other) {
         if (other == org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest.getDefaultInstance()) return this;
+        if (other.hasRegex()) {
+          bitField0_ |= 0x00000001;
+          regex_ = other.regex_;
+          onChanged();
+        }
+        if (other.hasIncludeSysTables()) {
+          setIncludeSysTables(other.getIncludeSysTables());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -36090,6 +36333,114 @@ public final class MasterProtos {
         }
         return this;
       }
+      private int bitField0_;
+
+      // optional string regex = 1;
+      private java.lang.Object regex_ = "";
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public boolean hasRegex() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public java.lang.String getRegex() {
+        java.lang.Object ref = regex_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          regex_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getRegexBytes() {
+        java.lang.Object ref = regex_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          regex_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder setRegex(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder clearRegex() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        regex_ = getDefaultInstance().getRegex();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string regex = 1;</code>
+       */
+      public Builder setRegexBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        regex_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional bool include_sys_tables = 2 [default = false];
+      private boolean includeSysTables_ ;
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public boolean hasIncludeSysTables() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public boolean getIncludeSysTables() {
+        return includeSysTables_;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public Builder setIncludeSysTables(boolean value) {
+        bitField0_ |= 0x00000002;
+        includeSysTables_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool include_sys_tables = 2 [default = false];</code>
+       */
+      public Builder clearIncludeSysTables() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        includeSysTables_ = false;
+        onChanged();
+        return this;
+      }
 
       // @@protoc_insertion_point(builder_scope:GetTableNamesRequest)
     }
@@ -47998,113 +48349,115 @@ public final class MasterProtos {
       "equest\022\036\n\ntable_name\030\001 \002(\0132\n.TableName\"T",
       "\n\034GetSchemaAlterStatusResponse\022\035\n\025yet_to" +
       "_update_regions\030\001 \001(\r\022\025\n\rtotal_regions\030\002" +
-      " \001(\r\"L\n\032GetTableDescriptorsRequest\022\037\n\013ta" +
+      " \001(\r\"o\n\032GetTableDescriptorsRequest\022\037\n\013ta" +
       "ble_names\030\001 \003(\0132\n.TableName\022\r\n\005regex\030\002 \001" +
-      "(\t\"A\n\033GetTableDescriptorsResponse\022\"\n\014tab" +
-      "le_schema\030\001 \003(\0132\014.TableSchema\"\026\n\024GetTabl" +
-      "eNamesRequest\"8\n\025GetTableNamesResponse\022\037" +
-      "\n\013table_names\030\001 \003(\0132\n.TableName\"6\n\024GetTa" +
-      "bleStateRequest\022\036\n\ntable_name\030\001 \002(\0132\n.Ta" +
-      "bleName\"9\n\025GetTableStateResponse\022 \n\013tabl",
-      "e_state\030\001 \002(\0132\013.TableState\"\031\n\027GetCluster" +
-      "StatusRequest\"B\n\030GetClusterStatusRespons" +
-      "e\022&\n\016cluster_status\030\001 \002(\0132\016.ClusterStatu" +
-      "s\"\030\n\026IsMasterRunningRequest\"4\n\027IsMasterR" +
-      "unningResponse\022\031\n\021is_master_running\030\001 \002(" +
-      "\010\"@\n\024ExecProcedureRequest\022(\n\tprocedure\030\001" +
-      " \002(\0132\025.ProcedureDescription\"F\n\025ExecProce" +
-      "dureResponse\022\030\n\020expected_timeout\030\001 \001(\003\022\023" +
-      "\n\013return_data\030\002 \001(\014\"B\n\026IsProcedureDoneRe" +
-      "quest\022(\n\tprocedure\030\001 \001(\0132\025.ProcedureDesc",
-      "ription\"W\n\027IsProcedureDoneResponse\022\023\n\004do" +
-      "ne\030\001 \001(\010:\005false\022\'\n\010snapshot\030\002 \001(\0132\025.Proc" +
-      "edureDescription\"\273\001\n\017SetQuotaRequest\022\021\n\t" +
-      "user_name\030\001 \001(\t\022\022\n\nuser_group\030\002 \001(\t\022\021\n\tn" +
-      "amespace\030\003 \001(\t\022\036\n\ntable_name\030\004 \001(\0132\n.Tab" +
-      "leName\022\022\n\nremove_all\030\005 \001(\010\022\026\n\016bypass_glo" +
-      "bals\030\006 \001(\010\022\"\n\010throttle\030\007 \001(\0132\020.ThrottleR" +
-      "equest\"\022\n\020SetQuotaResponse2\346\030\n\rMasterSer" +
-      "vice\022S\n\024GetSchemaAlterStatus\022\034.GetSchema" +
-      "AlterStatusRequest\032\035.GetSchemaAlterStatu",
-      "sResponse\022P\n\023GetTableDescriptors\022\033.GetTa" +
-      "bleDescriptorsRequest\032\034.GetTableDescript" +
-      "orsResponse\022>\n\rGetTableNames\022\025.GetTableN" +
-      "amesRequest\032\026.GetTableNamesResponse\022G\n\020G" +
-      "etClusterStatus\022\030.GetClusterStatusReques" +
-      "t\032\031.GetClusterStatusResponse\022D\n\017IsMaster" +
-      "Running\022\027.IsMasterRunningRequest\032\030.IsMas" +
-      "terRunningResponse\0222\n\tAddColumn\022\021.AddCol" +
-      "umnRequest\032\022.AddColumnResponse\022;\n\014Delete" +
-      "Column\022\024.DeleteColumnRequest\032\025.DeleteCol",
-      "umnResponse\022;\n\014ModifyColumn\022\024.ModifyColu" +
-      "mnRequest\032\025.ModifyColumnResponse\0225\n\nMove" +
-      "Region\022\022.MoveRegionRequest\032\023.MoveRegionR" +
-      "esponse\022Y\n\026DispatchMergingRegions\022\036.Disp" +
-      "atchMergingRegionsRequest\032\037.DispatchMerg" +
-      "ingRegionsResponse\022;\n\014AssignRegion\022\024.Ass" +
-      "ignRegionRequest\032\025.AssignRegionResponse\022" +
-      "A\n\016UnassignRegion\022\026.UnassignRegionReques" +
-      "t\032\027.UnassignRegionResponse\022>\n\rOfflineReg" +
-      "ion\022\025.OfflineRegionRequest\032\026.OfflineRegi",
-      "onResponse\0228\n\013DeleteTable\022\023.DeleteTableR" +
-      "equest\032\024.DeleteTableResponse\022>\n\rtruncate" +
-      "Table\022\025.TruncateTableRequest\032\026.TruncateT" +
-      "ableResponse\0228\n\013EnableTable\022\023.EnableTabl" +
-      "eRequest\032\024.EnableTableResponse\022;\n\014Disabl" +
-      "eTable\022\024.DisableTableRequest\032\025.DisableTa" +
-      "bleResponse\0228\n\013ModifyTable\022\023.ModifyTable" +
-      "Request\032\024.ModifyTableResponse\0228\n\013CreateT" +
-      "able\022\023.CreateTableRequest\032\024.CreateTableR" +
-      "esponse\022/\n\010Shutdown\022\020.ShutdownRequest\032\021.",
-      "ShutdownResponse\0225\n\nStopMaster\022\022.StopMas" +
-      "terRequest\032\023.StopMasterResponse\022,\n\007Balan" +
-      "ce\022\017.BalanceRequest\032\020.BalanceResponse\022M\n" +
-      "\022SetBalancerRunning\022\032.SetBalancerRunning" +
-      "Request\032\033.SetBalancerRunningResponse\022A\n\016" +
-      "RunCatalogScan\022\026.RunCatalogScanRequest\032\027" +
-      ".RunCatalogScanResponse\022S\n\024EnableCatalog" +
-      "Janitor\022\034.EnableCatalogJanitorRequest\032\035." +
-      "EnableCatalogJanitorResponse\022\\\n\027IsCatalo" +
-      "gJanitorEnabled\022\037.IsCatalogJanitorEnable",
-      "dRequest\032 .IsCatalogJanitorEnabledRespon" +
-      "se\022L\n\021ExecMasterService\022\032.CoprocessorSer" +
-      "viceRequest\032\033.CoprocessorServiceResponse" +
-      "\022/\n\010Snapshot\022\020.SnapshotRequest\032\021.Snapsho" +
-      "tResponse\022V\n\025GetCompletedSnapshots\022\035.Get" +
-      "CompletedSnapshotsRequest\032\036.GetCompleted" +
-      "SnapshotsResponse\022A\n\016DeleteSnapshot\022\026.De" +
-      "leteSnapshotRequest\032\027.DeleteSnapshotResp" +
-      "onse\022A\n\016IsSnapshotDone\022\026.IsSnapshotDoneR" +
-      "equest\032\027.IsSnapshotDoneResponse\022D\n\017Resto",
-      "reSnapshot\022\027.RestoreSnapshotRequest\032\030.Re" +
-      "storeSnapshotResponse\022V\n\025IsRestoreSnapsh" +
-      "otDone\022\035.IsRestoreSnapshotDoneRequest\032\036." +
-      "IsRestoreSnapshotDoneResponse\022>\n\rExecPro" +
-      "cedure\022\025.ExecProcedureRequest\032\026.ExecProc" +
-      "edureResponse\022E\n\024ExecProcedureWithRet\022\025." +
-      "ExecProcedureRequest\032\026.ExecProcedureResp" +
-      "onse\022D\n\017IsProcedureDone\022\027.IsProcedureDon" +
-      "eRequest\032\030.IsProcedureDoneResponse\022D\n\017Mo" +
-      "difyNamespace\022\027.ModifyNamespaceRequest\032\030",
-      ".ModifyNamespaceResponse\022D\n\017CreateNamesp" +
-      "ace\022\027.CreateNamespaceRequest\032\030.CreateNam" +
-      "espaceResponse\022D\n\017DeleteNamespace\022\027.Dele" +
-      "teNamespaceRequest\032\030.DeleteNamespaceResp" +
-      "onse\022Y\n\026GetNamespaceDescriptor\022\036.GetName" +
-      "spaceDescriptorRequest\032\037.GetNamespaceDes" +
-      "criptorResponse\022_\n\030ListNamespaceDescript" +
-      "ors\022 .ListNamespaceDescriptorsRequest\032!." +
-      "ListNamespaceDescriptorsResponse\022t\n\037List" +
-      "TableDescriptorsByNamespace\022\'.ListTableD",
-      "escriptorsByNamespaceRequest\032(.ListTable" +
-      "DescriptorsByNamespaceResponse\022b\n\031ListTa" +
-      "bleNamesByNamespace\022!.ListTableNamesByNa" +
-      "mespaceRequest\032\".ListTableNamesByNamespa" +
-      "ceResponse\022>\n\rGetTableState\022\025.GetTableSt" +
-      "ateRequest\032\026.GetTableStateResponse\022/\n\010Se" +
-      "tQuota\022\020.SetQuotaRequest\032\021.SetQuotaRespo" +
-      "nseBB\n*org.apache.hadoop.hbase.protobuf." +
-      "generatedB\014MasterProtosH\001\210\001\001\240\001\001"
+      "(\t\022!\n\022include_sys_tables\030\003 \001(\010:\005false\"A\n" +
+      "\033GetTableDescriptorsResponse\022\"\n\014table_sc" +
+      "hema\030\001 \003(\0132\014.TableSchema\"H\n\024GetTableName" +
+      "sRequest\022\r\n\005regex\030\001 \001(\t\022!\n\022include_sys_t" +
+      "ables\030\002 \001(\010:\005false\"8\n\025GetTableNamesRespo" +
+      "nse\022\037\n\013table_names\030\001 \003(\0132\n.TableName\"6\n\024",
+      "GetTableStateRequest\022\036\n\ntable_name\030\001 \002(\013" +
+      "2\n.TableName\"9\n\025GetTableStateResponse\022 \n" +
+      "\013table_state\030\001 \002(\0132\013.TableState\"\031\n\027GetCl" +
+      "usterStatusRequest\"B\n\030GetClusterStatusRe" +
+      "sponse\022&\n\016cluster_status\030\001 \002(\0132\016.Cluster" +
+      "Status\"\030\n\026IsMasterRunningRequest\"4\n\027IsMa" +
+      "sterRunningResponse\022\031\n\021is_master_running" +
+      "\030\001 \002(\010\"@\n\024ExecProcedureRequest\022(\n\tproced" +
+      "ure\030\001 \002(\0132\025.ProcedureDescription\"F\n\025Exec" +
+      "ProcedureResponse\022\030\n\020expected_timeout\030\001 ",
+      "\001(\003\022\023\n\013return_data\030\002 \001(\014\"B\n\026IsProcedureD" +
+      "oneRequest\022(\n\tprocedure\030\001 \001(\0132\025.Procedur" +
+      "eDescription\"W\n\027IsProcedureDoneResponse\022" +
+      "\023\n\004done\030\001 \001(\010:\005false\022\'\n\010snapshot\030\002 \001(\0132\025" +
+      ".ProcedureDescription\"\273\001\n\017SetQuotaReques" +
+      "t\022\021\n\tuser_name\030\001 \001(\t\022\022\n\nuser_group\030\002 \001(\t" +
+      "\022\021\n\tnamespace\030\003 \001(\t\022\036\n\ntable_name\030\004 \001(\0132" +
+      "\n.TableName\022\022\n\nremove_all\030\005 \001(\010\022\026\n\016bypas" +
+      "s_globals\030\006 \001(\010\022\"\n\010throttle\030\007 \001(\0132\020.Thro" +
+      "ttleRequest\"\022\n\020SetQuotaResponse2\346\030\n\rMast",
+      "erService\022S\n\024GetSchemaAlterStatus\022\034.GetS" +
+      "chemaAlterStatusRequest\032\035.GetSchemaAlter" +
+      "StatusResponse\022P\n\023GetTableDescriptors\022\033." +
+      "GetTableDescriptorsRequest\032\034.GetTableDes" +
+      "criptorsResponse\022>\n\rGetTableNames\022\025.GetT" +
+      "ableNamesRequest\032\026.GetTableNamesResponse" +
+      "\022G\n\020GetClusterStatus\022\030.GetClusterStatusR" +
+      "equest\032\031.GetClusterStatusResponse\022D\n\017IsM" +
+      "asterRunning\022\027.IsMasterRunningRequest\032\030." +
+      "IsMasterRunningResponse\0222\n\tAddColumn\022\021.A",
+      "ddColumnRequest\032\022.AddColumnResponse\022;\n\014D" +
+      "eleteColumn\022\024.DeleteColumnRequest\032\025.Dele" +
+      "teColumnResponse\022;\n\014ModifyColumn\022\024.Modif" +
+      "yColumnRequest\032\025.ModifyColumnResponse\0225\n" +
+      "\nMoveRegion\022\022.MoveRegionRequest\032\023.MoveRe" +
+      "gionResponse\022Y\n\026DispatchMergingRegions\022\036" +
+      ".DispatchMergingRegionsRequest\032\037.Dispatc" +
+      "hMergingRegionsResponse\022;\n\014AssignRegion\022" +
+      "\024.AssignRegionRequest\032\025.AssignRegionResp" +
+      "onse\022A\n\016UnassignRegion\022\026.UnassignRegionR",
+      "equest\032\027.UnassignRegionResponse\022>\n\rOffli" +
+      "neRegion\022\025.OfflineRegionRequest\032\026.Offlin" +
+      "eRegionResponse\0228\n\013DeleteTable\022\023.DeleteT" +
+      "ableRequest\032\024.DeleteTableResponse\022>\n\rtru" +
+      "ncateTable\022\025.TruncateTableRequest\032\026.Trun" +
+      "cateTableResponse\0228\n\013EnableTable\022\023.Enabl" +
+      "eTableRequest\032\024.EnableTableResponse\022;\n\014D" +
+      "isableTable\022\024.DisableTableRequest\032\025.Disa" +
+      "bleTableResponse\0228\n\013ModifyTable\022\023.Modify" +
+      "TableRequest\032\024.ModifyTableResponse\0228\n\013Cr",
+      "eateTable\022\023.CreateTableRequest\032\024.CreateT" +
+      "ableResponse\022/\n\010Shutdown\022\020.ShutdownReque" +
+      "st\032\021.ShutdownResponse\0225\n\nStopMaster\022\022.St" +
+      "opMasterRequest\032\023.StopMasterResponse\022,\n\007" +
+      "Balance\022\017.BalanceRequest\032\020.BalanceRespon" +
+      "se\022M\n\022SetBalancerRunning\022\032.SetBalancerRu" +
+      "nningRequest\032\033.SetBalancerRunningRespons" +
+      "e\022A\n\016RunCatalogScan\022\026.RunCatalogScanRequ" +
+      "est\032\027.RunCatalogScanResponse\022S\n\024EnableCa" +
+      "talogJanitor\022\034.EnableCatalogJanitorReque",
+      "st\032\035.EnableCatalogJanitorResponse\022\\\n\027IsC" +
+      "atalogJanitorEnabled\022\037.IsCatalogJanitorE" +
+      "nabledRequest\032 .IsCatalogJanitorEnabledR" +
+      "esponse\022L\n\021ExecMasterService\022\032.Coprocess" +
+      "orServiceRequest\032\033.CoprocessorServiceRes" +
+      "ponse\022/\n\010Snapshot\022\020.SnapshotRequest\032\021.Sn" +
+      "apshotResponse\022V\n\025GetCompletedSnapshots\022" +
+      "\035.GetCompletedSnapshotsRequest\032\036.GetComp" +
+      "letedSnapshotsResponse\022A\n\016DeleteSnapshot" +
+      "\022\026.DeleteSnapshotRequest\032\027.DeleteSnapsho",
+      "tResponse\022A\n\016IsSnapshotDone\022\026.IsSnapshot" +
+      "DoneRequest\032\027.IsSnapshotDoneResponse\022D\n\017" +
+      "RestoreSnapshot\022\027.RestoreSnapshotRequest" +
+      "\032\030.RestoreSnapshotResponse\022V\n\025IsRestoreS" +
+      "napshotDone\022\035.IsRestoreSnapshotDoneReque" +
+      "st\032\036.IsRestoreSnapshotDoneResponse\022>\n\rEx" +
+      "ecProcedure\022\025.ExecProcedureRequest\032\026.Exe" +
+      "cProcedureResponse\022E\n\024ExecProcedureWithR" +
+      "et\022\025.ExecProcedureRequest\032\026.ExecProcedur" +
+      "eResponse\022D\n\017IsProcedureDone\022\027.IsProcedu",
+      "reDoneRequest\032\030.IsProcedureDoneResponse\022" +
+      "D\n\017ModifyNamespace\022\027.ModifyNamespaceRequ" +
+      "est\032\030.ModifyNamespaceResponse\022D\n\017CreateN" +
+      "amespace\022\027.CreateNamespaceRequest\032\030.Crea" +
+      "teNamespaceResponse\022D\n\017DeleteNamespace\022\027" +
+      ".DeleteNamespaceRequest\032\030.DeleteNamespac" +
+      "eResponse\022Y\n\026GetNamespaceDescriptor\022\036.Ge" +
+      "tNamespaceDescriptorRequest\032\037.GetNamespa" +
+      "ceDescriptorResponse\022_\n\030ListNamespaceDes" +
+      "criptors\022 .ListNamespaceDescriptorsReque",
+      "st\032!.ListNamespaceDescriptorsResponse\022t\n" +
+      "\037ListTableDescriptorsByNamespace\022\'.ListT" +
+      "ableDescriptorsByNamespaceRequest\032(.List" +
+      "TableDescriptorsByNamespaceResponse\022b\n\031L" +
+      "istTableNamesByNamespace\022!.ListTableName" +
+      "sByNamespaceRequest\032\".ListTableNamesByNa" +
+      "mespaceResponse\022>\n\rGetTableState\022\025.GetTa" +
+      "bleStateRequest\032\026.GetTableStateResponse\022" +
+      "/\n\010SetQuota\022\020.SetQuotaRequest\032\021.SetQuota" +
+      "ResponseBB\n*org.apache.hadoop.hbase.prot",
+      "obuf.generatedB\014MasterProtosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -48536,7 +48889,7 @@ public final class MasterProtos {
           internal_static_GetTableDescriptorsRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_GetTableDescriptorsRequest_descriptor,
-              new java.lang.String[] { "TableNames", "Regex", });
+              new java.lang.String[] { "TableNames", "Regex", "IncludeSysTables", });
           internal_static_GetTableDescriptorsResponse_descriptor =
             getDescriptor().getMessageTypes().get(71);
           internal_static_GetTableDescriptorsResponse_fieldAccessorTable = new
@@ -48548,7 +48901,7 @@ public final class MasterProtos {
           internal_static_GetTableNamesRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_GetTableNamesRequest_descriptor,
-              new java.lang.String[] { });
+              new java.lang.String[] { "Regex", "IncludeSysTables", });
           internal_static_GetTableNamesResponse_descriptor =
             getDescriptor().getMessageTypes().get(73);
           internal_static_GetTableNamesResponse_fieldAccessorTable = new

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-protocol/src/main/protobuf/Master.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/Master.proto b/hbase-protocol/src/main/protobuf/Master.proto
index 5d60e55..82104f5 100644
--- a/hbase-protocol/src/main/protobuf/Master.proto
+++ b/hbase-protocol/src/main/protobuf/Master.proto
@@ -315,6 +315,7 @@ message GetSchemaAlterStatusResponse {
 message GetTableDescriptorsRequest {
   repeated TableName table_names = 1;
   optional string regex = 2;
+  optional bool include_sys_tables = 3 [default=false];
 }
 
 message GetTableDescriptorsResponse {
@@ -322,6 +323,8 @@ message GetTableDescriptorsResponse {
 }
 
 message GetTableNamesRequest {
+  optional string regex = 1;
+  optional bool include_sys_tables = 2 [default=false];
 }
 
 message GetTableNamesResponse {

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
index afc6ecf..9d702fa 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterAndRegionObserver.java
@@ -418,23 +418,23 @@ public abstract class BaseMasterAndRegionObserver extends BaseRegionObserver
 
   @Override
   public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList, List<HTableDescriptor> descriptors)
-      throws IOException {
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
   }
 
   @Override
-  public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList, List<HTableDescriptor> descriptors, String regex)
-      throws IOException {
+  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
   }
 
   @Override
-  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<HTableDescriptor> descriptors) throws IOException {
+  public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
   }
 
   @Override
-  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<HTableDescriptor> descriptors, String regex) throws IOException {
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
index 3f0ffc2..b26e7d4 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseMasterObserver.java
@@ -411,22 +411,23 @@ public class BaseMasterObserver implements MasterObserver {
 
   @Override
   public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException {
-  }
-
-  @Override
-  public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<TableName> tableNamesList, List<HTableDescriptor> descriptors, String regex)
       throws IOException {
   }
 
   @Override
   public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<HTableDescriptor> descriptors) throws IOException {
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
   }
 
   @Override
-  public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+  public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+  }
+
+  @Override
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<HTableDescriptor> descriptors, String regex) throws IOException {
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
index 1e00210..50912b3 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java
@@ -693,46 +693,47 @@ public interface MasterObserver extends Coprocessor {
    * @param ctx the environment to interact with the framework and master
    * @param tableNamesList the list of table names, or null if querying for all
    * @param descriptors an empty list, can be filled with what to return if bypassing
+   * @param regex regular expression used for filtering the table names
    * @throws IOException
-   * @deprecated Use preGetTableDescriptors with regex instead.
    */
-  @Deprecated
   void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException;
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException;
 
   /**
-   * Called before a getTableDescriptors request has been processed.
+   * Called after a getTableDescriptors request has been processed.
    * @param ctx the environment to interact with the framework and master
    * @param tableNamesList the list of table names, or null if querying for all
-   * @param descriptors an empty list, can be filled with what to return if bypassing
+   * @param descriptors the list of descriptors about to be returned
    * @param regex regular expression used for filtering the table names
    * @throws IOException
    */
-  void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+  void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
       String regex) throws IOException;
 
   /**
-   * Called after a getTableDescriptors request has been processed.
+   * Called before a getTableNames request has been processed.
    * @param ctx the environment to interact with the framework and master
-   * @param descriptors the list of descriptors about to be returned
+   * @param descriptors an empty list, can be filled with what to return if bypassing
+   * @param regex regular expression used for filtering the table names
    * @throws IOException
-   * @deprecated Use postGetTableDescriptors with regex instead.
    */
-  @Deprecated
-  void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<HTableDescriptor> descriptors) throws IOException;
+  void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException;
 
   /**
-   * Called after a getTableDescriptors request has been processed.
+   * Called after a getTableNames request has been processed.
    * @param ctx the environment to interact with the framework and master
    * @param descriptors the list of descriptors about to be returned
    * @param regex regular expression used for filtering the table names
    * @throws IOException
    */
-  void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+  void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
       List<HTableDescriptor> descriptors, String regex) throws IOException;
 
+
+
   /**
    * Called before a new namespace is created by
    * {@link org.apache.hadoop.hbase.master.HMaster}.

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index af4abb0..9e7a679 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -27,13 +27,16 @@ import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -304,7 +307,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
     this.preLoadTableDescriptors = conf.getBoolean("hbase.master.preload.tabledescriptors", true);
 
     // Do we publish the status?
-    
+
     boolean shouldPublish = conf.getBoolean(HConstants.STATUS_PUBLISHED,
         HConstants.STATUS_PUBLISHED_DEFAULT);
     Class<? extends ClusterStatusPublisher.Publisher> publisherClass =
@@ -1997,4 +2000,116 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
     }
     return tableNames;
   }
+
+  /**
+   * Returns the list of table descriptors that match the specified request
+   *
+   * @param regex The regular expression to match against, or null if querying for all
+   * @param tableNameList the list of table names, or null if querying for all
+   * @param includeSysTables False to match only against userspace tables
+   * @return the list of table descriptors
+   */
+  public List<HTableDescriptor> listTableDescriptors(final String regex,
+      final List<TableName> tableNameList, final boolean includeSysTables)
+      throws IOException {
+    final List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
+
+    boolean bypass = false;
+    if (cpHost != null) {
+      bypass = cpHost.preGetTableDescriptors(tableNameList, descriptors, regex);
+    }
+
+    if (!bypass) {
+      if (tableNameList == null || tableNameList.size() == 0) {
+        // request for all TableDescriptors
+        Collection<HTableDescriptor> htds = tableDescriptors.getAll().values();
+        for (HTableDescriptor desc: htds) {
+          if (includeSysTables || !desc.getTableName().isSystemTable()) {
+            descriptors.add(desc);
+          }
+        }
+      } else {
+        for (TableName s: tableNameList) {
+          HTableDescriptor desc = tableDescriptors.get(s);
+          if (desc != null) {
+            descriptors.add(desc);
+          }
+        }
+      }
+
+      // Retains only those matched by regular expression.
+      if (regex != null) {
+        filterTablesByRegex(descriptors, Pattern.compile(regex));
+      }
+
+      if (cpHost != null) {
+        cpHost.postGetTableDescriptors(tableNameList, descriptors, regex);
+      }
+    }
+    return descriptors;
+  }
+
+  /**
+   * Returns the list of table names that match the specified request
+   * @param regex The regular expression to match against, or null if querying for all
+   * @param includeSysTables False to match only against userspace tables
+   * @return the list of table names
+   */
+  public List<TableName> listTableNames(final String regex, final boolean includeSysTables)
+      throws IOException {
+    final List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
+
+    boolean bypass = false;
+    if (cpHost != null) {
+      bypass = cpHost.preGetTableNames(descriptors, regex);
+    }
+
+    if (!bypass) {
+      // get all descriptors
+      Collection<HTableDescriptor> htds = tableDescriptors.getAll().values();
+      for (HTableDescriptor htd: htds) {
+        if (includeSysTables || !htd.getTableName().isSystemTable()) {
+          descriptors.add(htd);
+        }
+      }
+
+      // Retains only those matched by regular expression.
+      if (regex != null) {
+        filterTablesByRegex(descriptors, Pattern.compile(regex));
+      }
+
+      if (cpHost != null) {
+        cpHost.postGetTableNames(descriptors, regex);
+      }
+    }
+
+    List<TableName> result = new ArrayList(descriptors.size());
+    for (HTableDescriptor htd: descriptors) {
+      result.add(htd.getTableName());
+    }
+    return result;
+  }
+
+
+  /**
+   * Removes the table descriptors that don't match the pattern.
+   * @param descriptors list of table descriptors to filter
+   * @param pattern the regex to use
+   */
+  private static void filterTablesByRegex(final Collection<HTableDescriptor> descriptors,
+      final Pattern pattern) {
+    final String defaultNS = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
+      HTableDescriptor htd = itr.next();
+      String tableName = htd.getTableName().getNameAsString();
+      boolean matched = pattern.matcher(tableName).matches();
+      if (!matched && htd.getTableName().getNamespaceAsString().equals(defaultNS)) {
+        matched = pattern.matcher(defaultNS + TableName.NAMESPACE_DELIM + tableName).matches();
+      }
+      if (!matched) {
+        itr.remove();
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
index 31a5dab..cdddbfa 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java
@@ -812,45 +812,45 @@ public class MasterCoprocessorHost
   }
 
   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
-    final List<HTableDescriptor> descriptors) throws IOException {
+      final List<HTableDescriptor> descriptors, final String regex) throws IOException {
     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override
       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
           throws IOException {
-        oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
+        oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
       }
     });
   }
 
-  public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
+  public void postGetTableDescriptors(final List<TableName> tableNamesList,
       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
-    return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+    execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override
       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
           throws IOException {
-        oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
+        oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
       }
     });
   }
 
-  public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
-      throws IOException {
-    execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
+  public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
+      final String regex) throws IOException {
+    return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override
       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
           throws IOException {
-        oserver.postGetTableDescriptors(ctx, descriptors);
+        oserver.preGetTableNames(ctx, descriptors, regex);
       }
     });
   }
 
-  public void postGetTableDescriptors(final List<HTableDescriptor> descriptors, final String regex)
-      throws IOException {
+  public void postGetTableNames(final List<HTableDescriptor> descriptors,
+      final String regex) throws IOException {
     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
       @Override
       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
           throws IOException {
-        oserver.postGetTableDescriptors(ctx, descriptors, regex);
+        oserver.postGetTableNames(ctx, descriptors, regex);
       }
     });
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index 470e8e3..1c41368 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -21,11 +21,8 @@ package org.apache.hadoop.hbase.master;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -788,90 +785,30 @@ public class MasterRpcServices extends RSRpcServices
       GetTableDescriptorsRequest req) throws ServiceException {
     try {
       master.checkInitialized();
-    } catch (IOException e) {
-      throw new ServiceException(e);
-    }
-
-    List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
-    List<TableName> tableNameList = new ArrayList<TableName>();
-    for(HBaseProtos.TableName tableNamePB: req.getTableNamesList()) {
-      tableNameList.add(ProtobufUtil.toTableName(tableNamePB));
-    }
-    boolean bypass = false;
-    String regex = req.hasRegex() ? req.getRegex() : null;
-    if (master.cpHost != null) {
-      try {
-        bypass = master.cpHost.preGetTableDescriptors(tableNameList, descriptors);
-        // method required for AccessController.
-        bypass |= master.cpHost.preGetTableDescriptors(tableNameList, descriptors, regex);
-      } catch (IOException ioe) {
-        throw new ServiceException(ioe);
-      }
-    }
 
-    if (!bypass) {
-      if (req.getTableNamesCount() == 0) {
-        // request for all TableDescriptors
-        Map<String, HTableDescriptor> descriptorMap = null;
-        try {
-          descriptorMap = master.getTableDescriptors().getAll();
-        } catch (IOException e) {
-          LOG.warn("Failed getting all descriptors", e);
-        }
-        if (descriptorMap != null) {
-          for(HTableDescriptor desc: descriptorMap.values()) {
-            if(!desc.getTableName().isSystemTable()) {
-              descriptors.add(desc);
-            }
-          }
-        }
-      } else {
-        for (TableName s: tableNameList) {
-          try {
-            HTableDescriptor desc = master.getTableDescriptors().get(s);
-            if (desc != null) {
-              descriptors.add(desc);
-            }
-          } catch (IOException e) {
-            LOG.warn("Failed getting descriptor for " + s, e);
-          }
+      final String regex = req.hasRegex() ? req.getRegex() : null;
+      List<TableName> tableNameList = null;
+      if (req.getTableNamesCount() > 0) {
+        tableNameList = new ArrayList<TableName>(req.getTableNamesCount());
+        for (HBaseProtos.TableName tableNamePB: req.getTableNamesList()) {
+          tableNameList.add(ProtobufUtil.toTableName(tableNamePB));
         }
       }
 
-      // Retains only those matched by regular expression.
-      if(regex != null) {
-        Pattern pat = Pattern.compile(regex);
-        for (Iterator<HTableDescriptor> itr = descriptors.iterator(); itr.hasNext(); ) {
-          HTableDescriptor htd = itr.next();
-          String tableName = htd.getTableName().getNameAsString();
-          String defaultNameSpace = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
-          boolean matched = pat.matcher(tableName).matches();
-          if(!matched && htd.getTableName().getNamespaceAsString().equals(defaultNameSpace)) {
-            matched = pat.matcher(defaultNameSpace + TableName.NAMESPACE_DELIM + tableName)
-                .matches();
-          }
-          if (!matched)
-            itr.remove();
-          }
-      }
+      List<HTableDescriptor> descriptors = master.listTableDescriptors(regex, tableNameList,
+          req.getIncludeSysTables());
 
-      if (master.cpHost != null) {
-        try {
-          master.cpHost.postGetTableDescriptors(descriptors);
-          // method required for AccessController.
-          master.cpHost.postGetTableDescriptors(descriptors, regex);
-        } catch (IOException ioe) {
-          throw new ServiceException(ioe);
+      GetTableDescriptorsResponse.Builder builder = GetTableDescriptorsResponse.newBuilder();
+      if (descriptors != null && descriptors.size() > 0) {
+        // Add the table descriptors to the response
+        for (HTableDescriptor htd: descriptors) {
+          builder.addTableSchema(htd.convert());
         }
       }
+      return builder.build();
+    } catch (IOException ioe) {
+      throw new ServiceException(ioe);
     }
-
-
-    GetTableDescriptorsResponse.Builder builder = GetTableDescriptorsResponse.newBuilder();
-    for (HTableDescriptor htd: descriptors) {
-      builder.addTableSchema(htd.convert());
-    }
-    return builder.build();
   }
 
   /**
@@ -886,13 +823,16 @@ public class MasterRpcServices extends RSRpcServices
       GetTableNamesRequest req) throws ServiceException {
     try {
       master.checkServiceStarted();
-      Collection<HTableDescriptor> descriptors = master.getTableDescriptors().getAll().values();
+
+      final String regex = req.hasRegex() ? req.getRegex() : null;
+      List<TableName> tableNames = master.listTableNames(regex, req.getIncludeSysTables());
+
       GetTableNamesResponse.Builder builder = GetTableNamesResponse.newBuilder();
-      for (HTableDescriptor descriptor: descriptors) {
-        if (descriptor.getTableName().isSystemTable()) {
-          continue;
+      if (tableNames != null && tableNames.size() > 0) {
+        // Add the table names to the response
+        for (TableName table: tableNames) {
+          builder.addTableNames(ProtobufUtil.toProtoTableName(table));
         }
-        builder.addTableNames(ProtobufUtil.toProtoTableName(descriptor.getTableName()));
       }
       return builder.build();
     } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
index a9e5302..728669c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
@@ -431,6 +431,36 @@ public class AccessController extends BaseMasterAndRegionObserver
   }
 
   /**
+   * Authorizes that the current user has any of the given permissions to access the table.
+   *
+   * @param tableName Table requested
+   * @param permissions Actions being requested
+   * @throws IOException if obtaining the current user fails
+   * @throws AccessDeniedException if user has no authorization
+   */
+  private void requireAccess(String request, TableName tableName,
+      Action... permissions) throws IOException {
+    User user = getActiveUser();
+    AuthResult result = null;
+
+    for (Action permission : permissions) {
+      if (authManager.hasAccess(user, tableName, permission)) {
+        result = AuthResult.allow(request, "Table permission granted", user,
+                                  permission, tableName, null, null);
+        break;
+      } else {
+        // rest of the world
+        result = AuthResult.deny(request, "Insufficient permissions", user,
+                                 permission, tableName, null, null);
+      }
+    }
+    logResult(result);
+    if (!result.isAllowed()) {
+      throw new AccessDeniedException("Insufficient permissions " + result.toContextString());
+    }
+  }
+
+  /**
    * Authorizes that the current user has global privileges for the given action.
    * @param perm The action being requested
    * @throws IOException if obtaining the current user fails
@@ -976,7 +1006,7 @@ public class AccessController extends BaseMasterAndRegionObserver
       TableName tableName, final HTableDescriptor htd) throws IOException {
     final Configuration conf = c.getEnvironment().getConfiguration();
     // default the table owner to current user, if not specified.
-    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() : 
+    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() :
       getActiveUser().getShortName();
     User.runAsLoginUser(new PrivilegedExceptionAction<Void>() {
       @Override
@@ -2255,51 +2285,56 @@ public class AccessController extends BaseMasterAndRegionObserver
        List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
        String regex) throws IOException {
     // We are delegating the authorization check to postGetTableDescriptors as we don't have
-    // any concrete set of table names when regex is present.
-    if(regex == null) {
-      // If the list is empty, this is a request for all table descriptors and requires GLOBAL
-      // ADMIN privs.
-      if (tableNamesList == null || tableNamesList.isEmpty()) {
-        requireGlobalPermission("getTableDescriptors", Action.ADMIN, null, null);
-      }
+    // any concrete set of table names when a regex is present or the full list is requested.
+    if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) {
       // Otherwise, if the requestor has ADMIN or CREATE privs for all listed tables, the
       // request can be granted.
-      else {
-        MasterServices masterServices = ctx.getEnvironment().getMasterServices();
-        for (TableName tableName: tableNamesList) {
-          // Skip checks for a table that does not exist
-          if (!masterServices.getTableStateManager().isTablePresent(tableName))
-            continue;
-          requirePermission("getTableDescriptors", tableName, null, null,
-              Action.ADMIN, Action.CREATE);
-        }
+      MasterServices masterServices = ctx.getEnvironment().getMasterServices();
+      for (TableName tableName: tableNamesList) {
+        // Skip checks for a table that does not exist
+        if (!masterServices.getTableStateManager().isTablePresent(tableName))
+          continue;
+        requirePermission("getTableDescriptors", tableName, null, null,
+            Action.ADMIN, Action.CREATE);
       }
     }
   }
 
   @Override
   public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-      List<HTableDescriptor> descriptors, String regex) throws IOException {
+      List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+      String regex) throws IOException {
     // Skipping as checks in this case are already done by preGetTableDescriptors.
-    if (regex == null) {
+    if (regex == null && tableNamesList != null && !tableNamesList.isEmpty()) {
       return;
     }
-    int numMatchedTables = descriptors.size();
+
     // Retains only those which passes authorization checks, as the checks weren't done as part
     // of preGetTableDescriptors.
-    for(Iterator<HTableDescriptor> itr = descriptors.iterator(); itr.hasNext();) {
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
       HTableDescriptor htd = itr.next();
       try {
         requirePermission("getTableDescriptors", htd.getTableName(), null, null,
             Action.ADMIN, Action.CREATE);
-      } catch(AccessDeniedException exception) {
+      } catch (AccessDeniedException e) {
         itr.remove();
       }
     }
+  }
 
-    // Throws exception if none of the matched tables are authorized for the user.
-    if(numMatchedTables > 0 && descriptors.size() == 0) {
-      throw new AccessDeniedException("Insufficient permissions for accessing tables");
+  @Override
+  public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+      List<HTableDescriptor> descriptors, String regex) throws IOException {
+    // Retains only those which passes authorization checks.
+    Iterator<HTableDescriptor> itr = descriptors.iterator();
+    while (itr.hasNext()) {
+      HTableDescriptor htd = itr.next();
+      try {
+        requireAccess("getTableNames", htd.getTableName(), Action.values());
+      } catch (AccessDeniedException e) {
+        itr.remove();
+      }
     }
   }
 
@@ -2369,7 +2404,7 @@ public class AccessController extends BaseMasterAndRegionObserver
       final String namespace, final Quotas quotas) throws IOException {
     requirePermission("setNamespaceQuota", Action.ADMIN);
   }
-  
+
   @Override
   public ReplicationEndpoint postCreateReplicationEndPoint(
       ObserverContext<RegionServerCoprocessorEnvironment> ctx, ReplicationEndpoint endpoint) {