commit 7794663b206d65c03f686ca65454471e4a8b3a4f
Author: Todd Lipcon <todd@apache.org>
Date:   Tue Apr 5 01:49:02 2016 -0700

    WIP: start_remote_bootstrap command for Binglin
    
    Change-Id: I00cc5bfb3e69c4a861dfc918fa2d867c8b2d5fb7

diff --git a/src/kudu/tools/ts-cli.cc b/src/kudu/tools/ts-cli.cc
index 80bcda3..d6b2268 100644
--- a/src/kudu/tools/ts-cli.cc
+++ b/src/kudu/tools/ts-cli.cc
@@ -28,6 +28,7 @@
 #include "kudu/common/partition.h"
 #include "kudu/common/schema.h"
 #include "kudu/common/wire_protocol.h"
+#include "kudu/consensus/consensus.proxy.h"
 #include "kudu/gutil/strings/human_readable.h"
 #include "kudu/server/server_base.proxy.h"
 #include "kudu/tserver/tserver.pb.h"
@@ -73,6 +74,7 @@ const char* const kDumpTabletOp = "dump_tablet";
 const char* const kDeleteTabletOp = "delete_tablet";
 const char* const kCurrentTimestamp = "current_timestamp";
 const char* const kStatus = "status";
+const char* const kRemoteBootstrap = "start_remote_bootstrap";
 
 DEFINE_string(server_address, "localhost",
               "Address of server to run against");
@@ -150,14 +152,23 @@ class TsAdminClient {
 
   // Get the server status
   Status GetStatus(ServerStatusPB* pb);
+
+  Status StartRemoteBootstrap(const std::string& tablet_id,
+                              const std::string& src_addr);
+
+  const HostPort& host_port() const {
+    return host_port_;
+  }
  private:
   std::string addr_;
+  HostPort host_port_;
   vector<Sockaddr> addrs_;
   MonoDelta timeout_;
   bool initted_;
   shared_ptr<server::GenericServiceProxy> generic_proxy_;
   gscoped_ptr<tserver::TabletServerServiceProxy> ts_proxy_;
   gscoped_ptr<tserver::TabletServerAdminServiceProxy> ts_admin_proxy_;
+  gscoped_ptr<consensus::ConsensusServiceProxy> consensus_proxy_;
   shared_ptr<rpc::Messenger> messenger_;
 
   DISALLOW_COPY_AND_ASSIGN(TsAdminClient);
@@ -171,16 +182,16 @@ TsAdminClient::TsAdminClient(string addr, int64_t timeout_millis)
 Status TsAdminClient::Init() {
   CHECK(!initted_);
 
-  HostPort host_port;
-  RETURN_NOT_OK(host_port.ParseString(addr_, tserver::TabletServer::kDefaultPort));
+  RETURN_NOT_OK(host_port_.ParseString(addr_, tserver::TabletServer::kDefaultPort));
   MessengerBuilder builder("ts-cli");
   RETURN_NOT_OK(builder.Build(&messenger_));
 
-  RETURN_NOT_OK(host_port.ResolveAddresses(&addrs_))
+  RETURN_NOT_OK(host_port_.ResolveAddresses(&addrs_))
 
   generic_proxy_.reset(new server::GenericServiceProxy(messenger_, addrs_[0]));
   ts_proxy_.reset(new TabletServerServiceProxy(messenger_, addrs_[0]));
   ts_admin_proxy_.reset(new TabletServerAdminServiceProxy(messenger_, addrs_[0]));
+  consensus_proxy_.reset(new consensus::ConsensusServiceProxy(messenger_, addrs_[0]));
 
   initted_ = true;
 
@@ -344,6 +355,30 @@ Status TsAdminClient::GetStatus(ServerStatusPB* pb) {
   return Status::OK();
 }
 
+Status TsAdminClient::StartRemoteBootstrap(const string& tablet_id,
+                                           const string& src_addr) {
+  TsAdminClient src_client(src_addr, 10000);
+  RETURN_NOT_OK_PREPEND(src_client.Init(),
+      "Could not connect to source tablet server");
+  ServerStatusPB src_status;
+  RETURN_NOT_OK_PREPEND(src_client.GetStatus(&src_status),
+      "Could not get status of source tablet server");
+
+  consensus::StartRemoteBootstrapRequestPB req;
+  consensus::StartRemoteBootstrapResponsePB resp;
+  req.set_tablet_id(tablet_id);
+  req.set_bootstrap_peer_uuid(src_status.node_instance().permanent_uuid());
+  CHECK_OK(HostPortToPB(src_client.host_port(), req.mutable_bootstrap_peer_addr()));
+  // TODO: req.set_caller_term?
+  LOG(INFO) << req.DebugString();
+  RpcController rpc;
+  rpc.set_timeout(timeout_);
+  RETURN_NOT_OK(consensus_proxy_->StartRemoteBootstrap(req, &resp, &rpc));
+  LOG(INFO) << resp.DebugString();
+  return Status::OK();
+}
+
+
 namespace {
 
 void SetUsage(const char* argv0) {
@@ -476,6 +511,14 @@ static int TsCliMain(int argc, char** argv) {
     RETURN_NOT_OK_PREPEND_FROM_MAIN(client.GetStatus(&status),
                                     "Unable to get status");
     std::cout << status.DebugString() << std::endl;
+  } else if (op == kRemoteBootstrap) {
+    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
+
+    string tablet_id = argv[2];
+    string src_addr = argv[3];
+
+    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.StartRemoteBootstrap(tablet_id, src_addr),
+        "Unable to start remote bootstrap");
   } else {
     std::cerr << "Invalid operation: " << op << std::endl;
     google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
