KUDU-1230. Add an admin tool to delete a table
This patch adds 'list_tables' and 'delete_table' to the kudu-admin tool.
Nothing fancy is being done, it's simple enough to use command line
utilities if there's a need to delete tables based on some selection
criteria.
Change-Id: I6d633b54e9cfd8f23c7f5fef6ff504cb04a02f35
Reviewed-on: http://gerrit.cloudera.org:8080/1459
Tested-by: Internal Jenkins
Reviewed-by: Mike Percy <mpercy@cloudera.com>
(cherry picked from commit 61e6cd19f3b350448e6ea649d34a43962fb6f345)
Reviewed-on: http://gerrit.cloudera.org:8080/1496
Reviewed-by: Jean-Daniel Cryans
Tested-by: Jean-Daniel Cryans
diff --git a/src/kudu/tools/kudu-admin-test.cc b/src/kudu/tools/kudu-admin-test.cc
index 80c4638..21ce33a 100644
--- a/src/kudu/tools/kudu-admin-test.cc
+++ b/src/kudu/tools/kudu-admin-test.cc
@@ -18,6 +18,7 @@
#include <boost/foreach.hpp>
#include <gtest/gtest.h>
+#include "kudu/client/client.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/integration-tests/test_workload.h"
@@ -28,10 +29,14 @@
namespace kudu {
namespace tools {
+using kudu::client::KuduClient;
+using kudu::client::KuduClientBuilder;
using itest::TabletServerMap;
using itest::TServerDetails;
using strings::Substitute;
+using std::tr1::shared_ptr;
+
static const char* const kAdminToolName = "kudu-admin";
class AdminCliTest : public tserver::TabletServerIntegrationTestBase {
@@ -152,5 +157,34 @@
MonoDelta::FromSeconds(10)));
}
+TEST_F(AdminCliTest, TestDeleteTable) {
+ FLAGS_num_tablet_servers = 1;
+ FLAGS_num_replicas = 1;
+
+ vector<string> ts_flags, master_flags;
+ BuildAndStart(ts_flags, master_flags);
+ string master_address = cluster_->master()->bound_rpc_addr().ToString();
+
+ shared_ptr<KuduClient> client;
+ CHECK_OK(KuduClientBuilder()
+ .add_master_server_addr(master_address)
+ .Build(&client));
+
+ // Default table that gets created;
+ string table_name = "TestTable";
+
+ string exe_path = GetAdminToolPath();
+ string arg_str = Substitute("$0 -master_addresses $1 delete_table $2",
+ exe_path,
+ master_address,
+ table_name);
+
+ ASSERT_OK(Subprocess::Call(arg_str));
+
+ vector<string> tables;
+ ASSERT_OK(client->ListTables(&tables));
+ ASSERT_TRUE(tables.empty());
+}
+
} // namespace tools
} // namespace kudu
diff --git a/src/kudu/tools/kudu-admin.cc b/src/kudu/tools/kudu-admin.cc
index e1ed975..c217489 100644
--- a/src/kudu/tools/kudu-admin.cc
+++ b/src/kudu/tools/kudu-admin.cc
@@ -70,7 +70,7 @@
using client::KuduTabletServer;
using consensus::ConsensusServiceProxy;
using consensus::RaftPeerPB;
-using master::ListTabletServersRequestPB;;
+using master::ListTabletServersRequestPB;
using master::ListTabletServersResponsePB;
using master::MasterServiceProxy;
using master::TabletLocationsPB;
@@ -82,6 +82,8 @@
using strings::Substitute;
const char* const kChangeConfigOp = "change_config";
+const char* const kListTablesOp = "list_tables";
+const char* const kDeleteTableOp = "delete_table";
static const char* g_progname = NULL;
class ClusterAdminClient {
@@ -100,6 +102,12 @@
const string& peer_uuid,
const boost::optional<string>& member_type);
+ // List all the tables.
+ Status ListTables();
+
+ // Delete a single table by name.
+ Status DeleteTable(const string& table_name);
+
private:
// Fetch the locations of the replicas for a given tablet from the Master.
Status GetTabletLocations(const std::string& tablet_id,
@@ -120,6 +128,7 @@
bool initted_;
shared_ptr<rpc::Messenger> messenger_;
gscoped_ptr<MasterServiceProxy> master_proxy_;
+ shared_ptr<KuduClient> kudu_client_;
DISALLOW_COPY_AND_ASSIGN(ClusterAdminClient);
};
@@ -153,6 +162,11 @@
<< master_hostport.ToString();
master_proxy_.reset(new MasterServiceProxy(messenger_, master_addrs[0]));
+ CHECK_OK(KuduClientBuilder()
+ .add_master_server_addr(master_addr_list_)
+ .default_admin_operation_timeout(timeout_)
+ .Build(&kudu_client_));
+
initted_ = true;
return Status::OK();
}
@@ -309,6 +323,22 @@
"registered with the Master", uuid));
}
+Status ClusterAdminClient::ListTables() {
+ vector<string> tables;
+ RETURN_NOT_OK(kudu_client_->ListTables(&tables));
+ BOOST_FOREACH(const string& table, tables) {
+ std::cout << table << std::endl;
+ }
+ return Status::OK();
+}
+
+Status ClusterAdminClient::DeleteTable(const string& table_name) {
+ vector<Sockaddr> tables;
+ RETURN_NOT_OK(kudu_client_->DeleteTable(table_name));
+ std::cout << "Deleted table " << table_name << std::endl;
+ return Status::OK();
+}
+
static void SetUsage(const char* argv0) {
ostringstream str;
@@ -316,7 +346,9 @@
<< "<operation> must be one of:\n"
<< " " << kChangeConfigOp << " <tablet_id> "
<< "<ADD_SERVER|REMOVE_SERVER|CHANGE_ROLE> <peer_uuid> "
- << "[VOTER|NON_VOTER]";
+ << "[VOTER|NON_VOTER]" << std::endl
+ << " " << kListTablesOp << std::endl
+ << " " << kDeleteTableOp << " <table_name>";
google::SetUsageMessage(str.str());
}
@@ -360,6 +392,23 @@
std::cerr << "Unable to change config: " << s.ToString() << std::endl;
return 1;
}
+ } else if (op == kListTablesOp) {
+ Status s = client.ListTables();
+ if (!s.ok()) {
+ std::cerr << "Unable to list tables: " << s.ToString() << std::endl;
+ return 1;
+ }
+ } else if (op == kDeleteTableOp) {
+ if (argc < 3) {
+ google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
+ exit(1);
+ }
+ string table_name = argv[2];
+ Status s = client.DeleteTable(table_name);
+ if (!s.ok()) {
+ std::cerr << "Unable to delete table " << table_name << ": " << s.ToString() << std::endl;
+ return 1;
+ }
} else {
std::cerr << "Invalid operation: " << op << std::endl;
google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);