You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2022/11/23 02:29:47 UTC

[hbase] branch branch-2 updated: HBASE-27444 Add tool commands list_enabled_tables and list_disabled_tables (#4880)

This is an automated email from the ASF dual-hosted git repository.

zhangduo pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 8c2f4b2aaa0 HBASE-27444 Add tool commands list_enabled_tables and list_disabled_tables (#4880)
8c2f4b2aaa0 is described below

commit 8c2f4b2aaa04a609ca3c6f401a711dceca9026d8
Author: LiangJun He <20...@163.com>
AuthorDate: Wed Nov 23 10:29:37 2022 +0800

    HBASE-27444 Add tool commands list_enabled_tables and list_disabled_tables (#4880)
    
    Signed-off-by: Duo Zhang <zh...@apache.org>
---
 .../java/org/apache/hadoop/hbase/client/Admin.java | 15 ++++
 .../org/apache/hadoop/hbase/client/AsyncAdmin.java | 16 +++++
 .../hadoop/hbase/client/AsyncHBaseAdmin.java       | 10 +++
 .../hbase/client/ConnectionImplementation.java     | 14 ++++
 .../org/apache/hadoop/hbase/client/HBaseAdmin.java | 31 ++++++++
 .../hadoop/hbase/client/RawAsyncHBaseAdmin.java    | 26 +++++++
 .../hbase/client/ShortCircuitMasterConnection.java | 16 +++++
 .../hadoop/hbase/shaded/protobuf/ProtobufUtil.java | 15 ++++
 .../src/main/protobuf/Master.proto                 | 24 +++++++
 .../hadoop/hbase/master/MasterRpcServices.java     | 52 ++++++++++++++
 .../hadoop/hbase/master/TestListTablesByState.java | 83 ++++++++++++++++++++++
 hbase-shell/src/main/ruby/hbase/admin.rb           |  6 ++
 hbase-shell/src/main/ruby/shell.rb                 |  2 +
 .../ruby/shell/commands/list_disabled_tables.rb    | 43 +++++++++++
 .../ruby/shell/commands/list_enabled_tables.rb     | 43 +++++++++++
 .../{TestShell.java => TestListTablesShell.java}   | 21 ++++--
 .../org/apache/hadoop/hbase/client/TestShell.java  |  2 +-
 .../src/test/ruby/shell/list_tables_test.rb        | 44 ++++++++++++
 .../hadoop/hbase/thrift2/client/ThriftAdmin.java   | 10 +++
 19 files changed, 466 insertions(+), 7 deletions(-)

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 b3c8a6aee6b..e16c21eb2c3 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
@@ -141,6 +141,13 @@ public interface Admin extends Abortable, Closeable {
    */
   List<TableDescriptor> listTableDescriptors() throws IOException;
 
+  /**
+   * List all enabled or disabled tables
+   * @param isEnabled is true means return enabled tables, false means return disabled tables
+   * @return a list of enabled or disabled tables
+   */
+  List<TableDescriptor> listTableDescriptorsByState(boolean isEnabled) throws IOException;
+
   /**
    * List all the userspace tables that match the given pattern.
    * @param pattern The compiled regular expression to match against
@@ -264,6 +271,14 @@ public interface Admin extends Abortable, Closeable {
   @Deprecated
   TableName[] listTableNames(String regex, boolean includeSysTables) throws IOException;
 
+  /**
+   * List all enabled or disabled table names
+   * @param isEnabled is true means return enabled table names, false means return disabled table
+   *                  names
+   * @return a list of enabled or disabled table names
+   */
+  List<TableName> listTableNamesByState(boolean isEnabled) throws IOException;
+
   /**
    * Get a table descriptor.
    * @param tableName as a {@link TableName}
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
index be8a961ee2e..361e967b8bc 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java
@@ -106,6 +106,14 @@ public interface AsyncAdmin {
    */
   CompletableFuture<List<TableDescriptor>> listTableDescriptorsByNamespace(String name);
 
+  /**
+   * List all enabled or disabled table descriptors
+   * @param isEnabled is true means return enabled table descriptors, false means return disabled
+   *                  table descriptors
+   * @return a list of table names wrapped by a {@link CompletableFuture}.
+   */
+  CompletableFuture<List<TableDescriptor>> listTableDescriptorsByState(boolean isEnabled);
+
   /**
    * List all of the names of userspace tables.
    * @return a list of table names wrapped by a {@link CompletableFuture}.
@@ -137,6 +145,14 @@ public interface AsyncAdmin {
    */
   CompletableFuture<List<TableName>> listTableNamesByNamespace(String name);
 
+  /**
+   * List all enabled or disabled table names
+   * @param isEnabled is true means return enabled table names, false means return disabled table
+   *                  names
+   * @return a list of table names wrapped by a {@link CompletableFuture}.
+   */
+  CompletableFuture<List<TableName>> listTableNamesByState(boolean isEnabled);
+
   /**
    * Method for getting the tableDescriptor
    * @param tableName as a {@link TableName}
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
index 925891ff58c..bf5e2905c3b 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java
@@ -99,6 +99,11 @@ class AsyncHBaseAdmin implements AsyncAdmin {
     return wrap(rawAdmin.listTableDescriptorsByNamespace(name));
   }
 
+  @Override
+  public CompletableFuture<List<TableDescriptor>> listTableDescriptorsByState(boolean isEnabled) {
+    return wrap(rawAdmin.listTableDescriptorsByState(isEnabled));
+  }
+
   @Override
   public CompletableFuture<List<TableName>> listTableNames(boolean includeSysTables) {
     return wrap(rawAdmin.listTableNames(includeSysTables));
@@ -115,6 +120,11 @@ class AsyncHBaseAdmin implements AsyncAdmin {
     return wrap(rawAdmin.listTableNamesByNamespace(name));
   }
 
+  @Override
+  public CompletableFuture<List<TableName>> listTableNamesByState(boolean isEnabled) {
+    return wrap(rawAdmin.listTableNamesByState(isEnabled));
+  }
+
   @Override
   public CompletableFuture<TableDescriptor> getDescriptor(TableName tableName) {
     return wrap(rawAdmin.getDescriptor(tableName));
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
index a834da72d28..a45a4a89dc7 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
@@ -1734,12 +1734,26 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
         return stub.getTableDescriptors(controller, request);
       }
 
+      @Override
+      public MasterProtos.ListTableDescriptorsByStateResponse listTableDescriptorsByState(
+        RpcController controller, MasterProtos.ListTableDescriptorsByStateRequest request)
+        throws ServiceException {
+        return stub.listTableDescriptorsByState(controller, request);
+      }
+
       @Override
       public MasterProtos.GetTableNamesResponse getTableNames(RpcController controller,
         MasterProtos.GetTableNamesRequest request) throws ServiceException {
         return stub.getTableNames(controller, request);
       }
 
+      @Override
+      public MasterProtos.ListTableNamesByStateResponse listTableNamesByState(
+        RpcController controller, MasterProtos.ListTableNamesByStateRequest request)
+        throws ServiceException {
+        return stub.listTableNamesByState(controller, request);
+      }
+
       @Override
       public MasterProtos.GetClusterStatusResponse getClusterStatus(RpcController controller,
         MasterProtos.GetClusterStatusRequest request) throws ServiceException {
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 bc6288197b9..36c8304ecb9 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
@@ -190,7 +190,11 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListDecomm
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespacesRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampForRegionRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MergeTableRegionsRequest;
@@ -343,6 +347,20 @@ public class HBaseAdmin implements Admin {
     return listTableDescriptors((Pattern) null, false);
   }
 
+  @Override
+  public List<TableDescriptor> listTableDescriptorsByState(boolean isEnabled) throws IOException {
+    return executeCallable(
+      new MasterCallable<List<TableDescriptor>>(getConnection(), getRpcControllerFactory()) {
+        @Override
+        protected List<TableDescriptor> rpcCall() throws Exception {
+          ListTableDescriptorsByStateResponse response =
+            master.listTableDescriptorsByState(getRpcController(),
+              ListTableDescriptorsByStateRequest.newBuilder().setIsEnabled(isEnabled).build());
+          return ProtobufUtil.toTableDescriptorList(response);
+        }
+      });
+  }
+
   @Override
   public List<TableDescriptor> listTableDescriptors(Pattern pattern, boolean includeSysTables)
     throws IOException {
@@ -566,6 +584,19 @@ public class HBaseAdmin implements Admin {
     return listTableNames(Pattern.compile(regex), includeSysTables);
   }
 
+  @Override
+  public List<TableName> listTableNamesByState(boolean isEnabled) throws IOException {
+    return executeCallable(
+      new MasterCallable<List<TableName>>(getConnection(), getRpcControllerFactory()) {
+        @Override
+        protected List<TableName> rpcCall() throws Exception {
+          ListTableNamesByStateResponse response = master.listTableNamesByState(getRpcController(),
+            ListTableNamesByStateRequest.newBuilder().setIsEnabled(isEnabled).build());
+          return ProtobufUtil.toTableNameList(response.getTableNamesList());
+        }
+      });
+  }
+
   @Override
   public HTableDescriptor getTableDescriptor(final TableName tableName) throws IOException {
     return getHTableDescriptor(tableName, getConnection(), rpcCallerFactory, rpcControllerFactory,
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
index 7970f8f3e11..e2187f8b4e8 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
@@ -219,8 +219,12 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamesp
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespacesResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampForRegionRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampResponse;
@@ -550,6 +554,17 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
       .call();
   }
 
+  @Override
+  public CompletableFuture<List<TableDescriptor>> listTableDescriptorsByState(boolean isEnabled) {
+    return this.<List<TableDescriptor>> newMasterCaller()
+      .action((controller, stub) -> this.<ListTableDescriptorsByStateRequest,
+        ListTableDescriptorsByStateResponse, List<TableDescriptor>> call(controller, stub,
+          ListTableDescriptorsByStateRequest.newBuilder().setIsEnabled(isEnabled).build(),
+          (s, c, req, done) -> s.listTableDescriptorsByState(c, req, done),
+          (resp) -> ProtobufUtil.toTableDescriptorList(resp)))
+      .call();
+  }
+
   @Override
   public CompletableFuture<List<TableName>> listTableNamesByNamespace(String name) {
     return this.<List<TableName>> newMasterCaller()
@@ -561,6 +576,17 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
       .call();
   }
 
+  @Override
+  public CompletableFuture<List<TableName>> listTableNamesByState(boolean isEnabled) {
+    return this.<List<TableName>> newMasterCaller()
+      .action((controller, stub) -> this.<ListTableNamesByStateRequest,
+        ListTableNamesByStateResponse, List<TableName>> call(controller, stub,
+          ListTableNamesByStateRequest.newBuilder().setIsEnabled(isEnabled).build(),
+          (s, c, req, done) -> s.listTableNamesByState(c, req, done),
+          (resp) -> ProtobufUtil.toTableNameList(resp.getTableNamesList())))
+      .call();
+  }
+
   @Override
   public CompletableFuture<TableDescriptor> getDescriptor(TableName tableName) {
     CompletableFuture<TableDescriptor> future = new CompletableFuture<>();
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java
index 6827700d9f7..62b9cf16e9d 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java
@@ -117,8 +117,12 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamesp
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespacesResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampForRegionRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampResponse;
@@ -443,12 +447,24 @@ public class ShortCircuitMasterConnection implements MasterKeepAliveConnection {
     return stub.getTableNames(controller, request);
   }
 
+  @Override
+  public ListTableNamesByStateResponse listTableNamesByState(RpcController controller,
+    ListTableNamesByStateRequest request) throws ServiceException {
+    return stub.listTableNamesByState(controller, request);
+  }
+
   @Override
   public GetTableDescriptorsResponse getTableDescriptors(RpcController controller,
     GetTableDescriptorsRequest request) throws ServiceException {
     return stub.getTableDescriptors(controller, request);
   }
 
+  @Override
+  public ListTableDescriptorsByStateResponse listTableDescriptorsByState(RpcController controller,
+    ListTableDescriptorsByStateRequest request) throws ServiceException {
+    return stub.listTableDescriptorsByState(controller, request);
+  }
+
   @Override
   public SecurityCapabilitiesResponse getSecurityCapabilities(RpcController controller,
     SecurityCapabilitiesRequest request) throws ServiceException {
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
index 1c1125f6aea..49e3f85cdc0 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
@@ -195,6 +195,7 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetComplet
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableDescriptorsResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespaceDescriptorsResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
@@ -457,6 +458,20 @@ public final class ProtobufUtil {
       .collect(Collectors.toList());
   }
 
+  /**
+   * Get a list of TableDescriptor from ListTableDescriptorsByNamespaceResponse protobuf
+   * @param proto the ListTableDescriptorsByNamespaceResponse
+   * @return a list of TableDescriptor
+   */
+  public static List<TableDescriptor>
+    toTableDescriptorList(ListTableDescriptorsByStateResponse proto) {
+    if (proto == null) {
+      return new ArrayList<>();
+    }
+    return proto.getTableSchemaList().stream().map(ProtobufUtil::toTableDescriptor)
+      .collect(Collectors.toList());
+  }
+
   /**
    * get the split keys in form "byte [][]" from a CreateTableRequest proto
    * @param proto the CreateTableRequest
diff --git a/hbase-protocol-shaded/src/main/protobuf/Master.proto b/hbase-protocol-shaded/src/main/protobuf/Master.proto
index 29fc22d618c..5e5a4462173 100644
--- a/hbase-protocol-shaded/src/main/protobuf/Master.proto
+++ b/hbase-protocol-shaded/src/main/protobuf/Master.proto
@@ -511,6 +511,14 @@ message GetTableDescriptorsResponse {
   repeated TableSchema table_schema = 1;
 }
 
+message ListTableDescriptorsByStateRequest {
+  required bool is_enabled = 1;
+}
+
+message ListTableDescriptorsByStateResponse {
+  repeated TableSchema table_schema = 1;
+}
+
 message GetTableNamesRequest {
   optional string regex = 1;
   optional bool include_sys_tables = 2 [default=false];
@@ -521,6 +529,14 @@ message GetTableNamesResponse {
   repeated TableName table_names = 1;
 }
 
+message ListTableNamesByStateRequest {
+  required bool is_enabled = 1;
+}
+
+message ListTableNamesByStateResponse {
+  repeated TableName table_names = 1;
+}
+
 message GetTableStateRequest {
   required TableName table_name = 1;
 }
@@ -769,10 +785,18 @@ service MasterService {
   rpc GetTableDescriptors(GetTableDescriptorsRequest)
     returns(GetTableDescriptorsResponse);
 
+  /** List all enabled or disabled table descriptors. */
+  rpc ListTableDescriptorsByState(ListTableDescriptorsByStateRequest)
+    returns(ListTableDescriptorsByStateResponse);
+
   /** Get the list of table names. */
   rpc GetTableNames(GetTableNamesRequest)
     returns(GetTableNamesResponse);
 
+  /** List all enabled or disabled table names. */
+  rpc ListTableNamesByState(ListTableNamesByStateRequest)
+    returns(ListTableNamesByStateResponse);
+
   /** Return cluster status. */
   rpc GetClusterStatus(GetClusterStatusRequest)
     returns(GetClusterStatusResponse);
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 437d9d8a07b..e6244aae026 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
@@ -253,8 +253,12 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamesp
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListNamespacesResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableDescriptorsByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByNamespaceResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ListTableNamesByStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampForRegionRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MajorCompactionTimestampResponse;
@@ -1101,6 +1105,31 @@ public class MasterRpcServices extends RSRpcServices
     }
   }
 
+  @Override
+  public ListTableDescriptorsByStateResponse listTableDescriptorsByState(RpcController controller,
+    ListTableDescriptorsByStateRequest request) throws ServiceException {
+    try {
+      master.checkInitialized();
+      List<TableDescriptor> descriptors = master.listTableDescriptors(null, null, null, false);
+
+      ListTableDescriptorsByStateResponse.Builder builder =
+        ListTableDescriptorsByStateResponse.newBuilder();
+      if (descriptors != null && descriptors.size() > 0) {
+        // Add the table descriptors to the response
+        TableState.State state =
+          request.getIsEnabled() ? TableState.State.ENABLED : TableState.State.DISABLED;
+        for (TableDescriptor htd : descriptors) {
+          if (master.getTableStateManager().isTableState(htd.getTableName(), state)) {
+            builder.addTableSchema(ProtobufUtil.toTableSchema(htd));
+          }
+        }
+      }
+      return builder.build();
+    } catch (IOException ioe) {
+      throw new ServiceException(ioe);
+    }
+  }
+
   /**
    * Get list of userspace table names
    * @param controller Unused (set to null).
@@ -1130,6 +1159,29 @@ public class MasterRpcServices extends RSRpcServices
     }
   }
 
+  @Override
+  public ListTableNamesByStateResponse listTableNamesByState(RpcController controller,
+    ListTableNamesByStateRequest request) throws ServiceException {
+    try {
+      master.checkServiceStarted();
+      List<TableName> tableNames = master.listTableNames(null, null, false);
+      ListTableNamesByStateResponse.Builder builder = ListTableNamesByStateResponse.newBuilder();
+      if (tableNames != null && tableNames.size() > 0) {
+        // Add the disabled table names to the response
+        TableState.State state =
+          request.getIsEnabled() ? TableState.State.ENABLED : TableState.State.DISABLED;
+        for (TableName table : tableNames) {
+          if (master.getTableStateManager().isTableState(table, state)) {
+            builder.addTableNames(ProtobufUtil.toProtoTableName(table));
+          }
+        }
+      }
+      return builder.build();
+    } catch (IOException e) {
+      throw new ServiceException(e);
+    }
+  }
+
   @Override
   public GetTableStateResponse getTableState(RpcController controller, GetTableStateRequest request)
     throws ServiceException {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestListTablesByState.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestListTablesByState.java
new file mode 100644
index 00000000000..f545eb9ae94
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestListTablesByState.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category({ MasterTests.class, MediumTests.class })
+public class TestListTablesByState {
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestListTablesByState.class);
+
+  private static HBaseTestingUtility UTIL;
+  private static Admin ADMIN;
+  private final static int SLAVES = 1;
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    UTIL = new HBaseTestingUtility();
+    UTIL.startMiniCluster(SLAVES);
+    ADMIN = UTIL.getAdmin();
+  }
+
+  @Test
+  public void testListTableNamesByState() throws Exception {
+    TableName testTableName = TableName.valueOf("test");
+    TableDescriptor testTableDesc = TableDescriptorBuilder.newBuilder(testTableName).build();
+    ADMIN.createTable(testTableDesc);
+    ADMIN.disableTable(testTableName);
+    Assert.assertEquals(ADMIN.listTableNamesByState(false).get(0), testTableName);
+    ADMIN.enableTable(testTableName);
+    Assert.assertEquals(ADMIN.listTableNamesByState(true).get(0), testTableName);
+  }
+
+  @Test
+  public void testListTableDescriptorByState() throws Exception {
+    TableName testTableName = TableName.valueOf("test");
+    TableDescriptor testTableDesc = TableDescriptorBuilder.newBuilder(testTableName).build();
+    ADMIN.createTable(testTableDesc);
+    ADMIN.disableTable(testTableName);
+    Assert.assertEquals(ADMIN.listTableDescriptorsByState(false).get(0), testTableDesc);
+    ADMIN.enableTable(testTableName);
+    Assert.assertEquals(ADMIN.listTableDescriptorsByState(true).get(0), testTableDesc);
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    if (ADMIN != null) {
+      ADMIN.close();
+    }
+    if (UTIL != null) {
+      UTIL.shutdownMiniCluster();
+    }
+  }
+}
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 42f25111c1a..a6dcb541c71 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -1812,6 +1812,12 @@ module Hbase
     def flush_master_store()
       @admin.flushMasterStore()
     end
+
+    #----------------------------------------------------------------------------------------------
+    # Returns a list of enable or disabled tables in hbase
+    def list_tables_by_state(is_enabled)
+      @admin.listTableNamesByState(is_enabled).map(&:getNameAsString)
+    end
   end
   # rubocop:enable Metrics/ClassLength
 end
diff --git a/hbase-shell/src/main/ruby/shell.rb b/hbase-shell/src/main/ruby/shell.rb
index f6b3efd945f..adb25372540 100644
--- a/hbase-shell/src/main/ruby/shell.rb
+++ b/hbase-shell/src/main/ruby/shell.rb
@@ -390,6 +390,8 @@ Shell.load_command_group(
     locate_region
     list_regions
     clone_table_schema
+    list_enabled_tables
+    list_disabled_tables
   ],
   aliases: {
     'describe' => ['desc']
diff --git a/hbase-shell/src/main/ruby/shell/commands/list_disabled_tables.rb b/hbase-shell/src/main/ruby/shell/commands/list_disabled_tables.rb
new file mode 100644
index 00000000000..2108098b150
--- /dev/null
+++ b/hbase-shell/src/main/ruby/shell/commands/list_disabled_tables.rb
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module Shell
+  module Commands
+    # list all disabled tables
+    class ListDisabledTables < Command
+      def help
+        <<~EOF
+           List all disabled tables
+           Examples:
+           hbase> list_disabled_tables
+        EOF
+      end
+
+      def command
+        formatter.header(['TABLE'])
+
+        list = admin.list_tables_by_state(false)
+        list.each do |table|
+          formatter.row([table])
+        end
+
+        formatter.footer(list.size)
+        list
+      end
+    end
+  end
+end
diff --git a/hbase-shell/src/main/ruby/shell/commands/list_enabled_tables.rb b/hbase-shell/src/main/ruby/shell/commands/list_enabled_tables.rb
new file mode 100644
index 00000000000..d386473a580
--- /dev/null
+++ b/hbase-shell/src/main/ruby/shell/commands/list_enabled_tables.rb
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module Shell
+  module Commands
+    # list all enabled tables
+    class ListEnabledTables < Command
+      def help
+        <<~EOF
+           List all enabled tables
+           Examples:
+           hbase> list_enabled_tables
+        EOF
+      end
+
+      def command
+        formatter.header(['TABLE'])
+
+        list = admin.list_tables_by_state(true)
+        list.each do |table|
+          formatter.row([table])
+        end
+
+        formatter.footer(list.size)
+        list
+      end
+    end
+  end
+end
diff --git a/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestListTablesShell.java
similarity index 73%
copy from hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java
copy to hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestListTablesShell.java
index b97f7b516b5..b823b6fc3aa 100644
--- a/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java
+++ b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestListTablesShell.java
@@ -20,18 +20,27 @@ package org.apache.hadoop.hbase.client;
 import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.ClientTests;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
+import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.experimental.categories.Category;
 
 @Category({ ClientTests.class, LargeTests.class })
-public class TestShell extends AbstractTestShell {
-
+public class TestListTablesShell extends AbstractTestShell {
   @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestShell.class);
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestListTablesShell.class);
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    setUpConfig();
+
+    TEST_UTIL.startMiniCluster(3);
+
+    setUpJRubyRuntime();
+  }
 
   @Override
-  protected String getExcludeList() {
-    return "replication_admin_test.rb,rsgroup_shell_test.rb,admin_test.rb,table_test.rb,"
-      + "quotas_test.rb,admin2_test.rb";
+  protected String getIncludeList() {
+    return "list_tables_test.rb";
   }
 }
diff --git a/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java
index b97f7b516b5..47918f68019 100644
--- a/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java
+++ b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShell.java
@@ -32,6 +32,6 @@ public class TestShell extends AbstractTestShell {
   @Override
   protected String getExcludeList() {
     return "replication_admin_test.rb,rsgroup_shell_test.rb,admin_test.rb,table_test.rb,"
-      + "quotas_test.rb,admin2_test.rb";
+      + "quotas_test.rb,admin2_test.rb,list_tables_test.rb";
   }
 }
diff --git a/hbase-shell/src/test/ruby/shell/list_tables_test.rb b/hbase-shell/src/test/ruby/shell/list_tables_test.rb
new file mode 100644
index 00000000000..961e662fa62
--- /dev/null
+++ b/hbase-shell/src/test/ruby/shell/list_tables_test.rb
@@ -0,0 +1,44 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'hbase_constants'
+require 'hbase_shell'
+
+# test for list_enabled_tables and list_disabled_tables
+class ListTablesTest < Test::Unit::TestCase
+  def setup
+    @shell = Shell::Shell.new(::Hbase::Hbase.new($TEST_CLUSTER.getConfiguration))
+  end
+
+  define_test 'List enabled tables' do
+    table = 'test_table1'
+    family = 'f1'
+    @shell.command('create', table, family)
+    assert_equal [table], @shell.command('list_enabled_tables')
+    @shell.command(:disable, table)
+    @shell.command(:drop, table)
+  end
+
+  define_test 'List disabled tables' do
+    table = 'test_table2'
+    family = 'f2'
+    @shell.command('create', table, family)
+    @shell.command(:disable, table)
+    assert_equal [table], @shell.command('list_disabled_tables')
+    @shell.command(:drop, table)
+  end
+end
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
index 2084467a313..60cee0945dd 100644
--- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java
@@ -155,6 +155,11 @@ public class ThriftAdmin implements Admin {
     return listTableDescriptors((Pattern) null);
   }
 
+  @Override
+  public List<TableDescriptor> listTableDescriptorsByState(boolean isEnabled) throws IOException {
+    throw new NotImplementedException("listTableDescriptorsByState not supported in ThriftAdmin");
+  }
+
   @Override
   public HTableDescriptor[] listTables(Pattern pattern) throws IOException {
     String regex = (pattern == null ? null : pattern.toString());
@@ -236,6 +241,11 @@ public class ThriftAdmin implements Admin {
     }
   }
 
+  @Override
+  public List<TableName> listTableNamesByState(boolean isEnabled) throws IOException {
+    throw new NotImplementedException("listTableNamesByState not supported in ThriftAdmin");
+  }
+
   @Override
   public HTableDescriptor getTableDescriptor(TableName tableName)
     throws TableNotFoundException, IOException {