kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject [1/5] kudu git commit: KUDU-2200: provide better diagnostics when connecting to a subset of masters
Date Fri, 03 Nov 2017 00:27:31 GMT
Repository: kudu
Updated Branches:
  refs/heads/master 9dd64e1b3 -> b418e88b6


KUDU-2200: provide better diagnostics when connecting to a subset of masters

This changes the ConnectToMaster RPC to send back the list of the master
peers, and then changes the clients to use this information to provide
better error messages in the case that the user has specified only a
subset of the live masters.

Note that this patch follows a "first do no harm" philosophy. In the
case that the user "gets lucky" and only specifies one of their three
masters, and that master happens to be the leader, we'll continue to
treat that as "successful".

Change-Id: I52f903e1aa5ae6948ca1ba6d4d856c3c9dc73d56
Reviewed-on: http://gerrit.cloudera.org:8080/8393
Reviewed-by: Alexey Serbin <aserbin@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/3e86797e
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/3e86797e
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/3e86797e

Branch: refs/heads/master
Commit: 3e86797e6e73365c26b8826083c447494c7fa7eb
Parents: 9dd64e1
Author: Todd Lipcon <todd@apache.org>
Authored: Wed Oct 25 16:36:40 2017 -0700
Committer: Todd Lipcon <todd@apache.org>
Committed: Thu Nov 2 05:39:01 2017 +0000

----------------------------------------------------------------------
 .../apache/kudu/client/ConnectToCluster.java    | 47 +++++++++++++++++++-
 .../org/apache/kudu/client/ProtobufHelper.java  | 12 +++++
 .../kudu/client/TestConnectToCluster.java       | 47 ++++++++++++++++++++
 src/kudu/client/master_rpc.cc                   | 40 ++++++++++++++---
 .../master_replication-itest.cc                 | 47 ++++++++++++++++++++
 src/kudu/master/master-test.cc                  |  4 ++
 src/kudu/master/master.cc                       | 31 +++++++++++++
 src/kudu/master/master.h                        | 11 ++++-
 src/kudu/master/master.proto                    | 12 +++++
 src/kudu/master/master_service.cc               | 14 ++++++
 10 files changed, 256 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java b/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java
index 832bbbc..d69bd76 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Functions;
@@ -34,7 +35,7 @@ import com.stumbleupon.async.Deferred;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
+import org.apache.kudu.Common.HostPortPB;
 import org.apache.kudu.consensus.Metadata.RaftPeerPB.Role;
 import org.apache.kudu.master.Master.ConnectToMasterResponsePB;
 import org.apache.kudu.rpc.RpcHeader.ErrorStatusPB.RpcErrorCodePB;
@@ -64,6 +65,12 @@ final class ConnectToCluster {
       Collections.synchronizedList(new ArrayList<Exception>());
 
   /**
+   * If we've received a response from a master which indicates the full
+   * list of masters in the cluster, it is stored here. Otherwise, null.
+   */
+  private AtomicReference<List<HostPortPB>> knownMasters = new AtomicReference<>();
+
+  /**
    * Creates an object that holds the state needed to retrieve master table's location.
    * @param masterAddrs Addresses of all master replicas that we want to retrieve the
    *                    registration from.
@@ -222,6 +229,34 @@ final class ConnectToCluster {
         Status s = Status.ServiceUnavailable(msg);
         responseD.callback(new NonRecoverableException(s));
       } else {
+        // We couldn't find a leader master. A common case here is that the user only
+        // specified a subset of the masters, so check for that. We could try to do
+        // something fancier like compare the actual host/ports to see if they don't
+        // match, but it's possible that the hostnames used by clients are not the
+        // same as the hostnames that the servers use for each other in some network
+        // setups.
+
+        List<HostPortPB> knownMastersLocal = knownMasters.get();
+        if (knownMastersLocal != null &&
+            knownMastersLocal.size() != numMasters) {
+          String msg = String.format(
+              "Could not connect to a leader master. " +
+              "Client configured with %s master(s) (%s) but cluster indicates it expects
" +
+              "%s master(s) (%s)",
+              numMasters, allHosts,
+              knownMastersLocal.size(),
+              ProtobufHelper.hostPortPbListToString(knownMastersLocal));
+          LOG.warn(msg);
+          Exception e = new NonRecoverableException(Status.ConfigurationError(msg));
+          if (!LOG.isDebugEnabled()) {
+            // Stack trace is just internal guts of netty, etc, no need for the detail
+            // level.
+            e.setStackTrace(new StackTraceElement[]{});
+          }
+          responseD.callback(e);
+          return;
+        }
+
         String message = String.format("Master config (%s) has no leader.",
             allHosts);
         Exception ex;
@@ -242,6 +277,15 @@ final class ConnectToCluster {
     }
   }
 
+  private void recordKnownMasters(ConnectToMasterResponsePB r) {
+    // Old versions don't set this field.
+    if (r.getMasterAddrsCount() == 0) {
+      return;
+    }
+
+    knownMasters.compareAndSet(null, r.getMasterAddrsList());
+  }
+
   /**
    * Callback for each ConnectToCluster RPC sent in connectToMaster() above.
    * If a request (paired to a specific master) returns a reply that indicates it's a leader,
@@ -260,6 +304,7 @@ final class ConnectToCluster {
 
     @Override
     public Void call(ConnectToMasterResponsePB r) throws Exception {
+      recordKnownMasters(r);
       if (!r.getRole().equals(Role.LEADER)) {
         incrementCountAndCheckExhausted();
         return null;

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/java/kudu-client/src/main/java/org/apache/kudu/client/ProtobufHelper.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/ProtobufHelper.java b/java/kudu-client/src/main/java/org/apache/kudu/client/ProtobufHelper.java
index af0963f..c816e3d 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/ProtobufHelper.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/ProtobufHelper.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.net.HostAndPort;
 import com.google.protobuf.ByteString;
@@ -301,4 +302,15 @@ public class ProtobufHelper {
   public static HostAndPort hostAndPortFromPB(Common.HostPortPB hostPortPB) {
     return HostAndPort.fromParts(hostPortPB.getHost(), hostPortPB.getPort());
   }
+
+  /**
+   * Convert a list of HostPortPBs into a comma-separated string.
+   */
+  public static String hostPortPbListToString(List<Common.HostPortPB> pbs) {
+    List<String> strs = new ArrayList<>(pbs.size());
+    for (Common.HostPortPB pb : pbs) {
+      strs.add(pb.getHost() + ":" + pb.getPort());
+    }
+    return Joiner.on(',').join(strs);
+  }
 }

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/java/kudu-client/src/test/java/org/apache/kudu/client/TestConnectToCluster.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/TestConnectToCluster.java
b/java/kudu-client/src/test/java/org/apache/kudu/client/TestConnectToCluster.java
index 30727ed..d467c8c 100644
--- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestConnectToCluster.java
+++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestConnectToCluster.java
@@ -27,6 +27,8 @@ import java.util.List;
 import com.google.common.collect.ImmutableList;
 import com.google.common.net.HostAndPort;
 import com.stumbleupon.async.Callback;
+
+import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.kudu.consensus.Metadata;
@@ -67,6 +69,51 @@ public class TestConnectToCluster {
   }
 
   /**
+   * Test for KUDU-2200: if a cluster is running multiple masters, but
+   * the user only specifies one of them in the connection string,
+   * the resulting exception should clarify their error rather than
+   * saying that no leader was found.
+   */
+  @Test(timeout=60000)
+  public void testConnectToOneOfManyMasters() throws Exception {
+    MiniKuduCluster cluster = new MiniKuduCluster.MiniKuduClusterBuilder()
+        .numMasters(3)
+        .numTservers(0)
+        .build();
+    int successes = 0;
+    try {
+      String[] masterAddrs = cluster.getMasterAddresses().split(",");
+      assertEquals(3, masterAddrs.length);
+      for (String masterAddr : masterAddrs) {
+        KuduClient c = null;
+        try {
+          c = new KuduClient.KuduClientBuilder(masterAddr).build();
+          // Call some method which uses the master. This forces us to connect.
+          c.listTabletServers();
+          successes++;
+        } catch (Exception e) {
+          Assert.assertTrue("unexpected exception: " + e.toString(),
+              e.toString().matches(
+                  ".*Client configured with 1 master\\(s\\) " +
+                  "\\(.+?\\) but cluster indicates it expects 3 master\\(s\\) " +
+                  "\\(.+?,.+?,.+?\\).*"));
+        } finally {
+          if (c != null) {
+            c.close();
+          }
+        }
+      }
+    } finally {
+      cluster.shutdown();
+    }
+    // Typically, one of the connections will have succeeded. However, it's possible
+    // that 0 succeeded in the case that the masters were slow at electing
+    // themselves.
+    Assert.assertTrue(successes <= 1);
+  }
+
+
+  /**
    * Unit test which checks that the ConnectToCluster aggregates the
    * responses from the different masters properly and returns the
    * response from the located leader.

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/client/master_rpc.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/master_rpc.cc b/src/kudu/client/master_rpc.cc
index dcdc9a5..a03f5f7 100644
--- a/src/kudu/client/master_rpc.cc
+++ b/src/kudu/client/master_rpc.cc
@@ -27,6 +27,7 @@
 #include <boost/bind.hpp>
 #include <glog/logging.h>
 
+#include "kudu/common/common.pb.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/consensus/metadata.pb.h"
 #include "kudu/gutil/basictypes.h"
@@ -318,13 +319,38 @@ void ConnectToClusterRpc::SingleNodeCallback(int master_idx,
     }
     if (new_status.ok()) {
       if (resp.role() != RaftPeerPB::LEADER) {
-        // Use a Status::NotFound() to indicate that the node is not
-        // the leader: this way, we can handle the case where we've
-        // received a reply from all of the nodes in the cluster (no
-        // network or other errors encountered), but haven't found a
-        // leader (which means that SendRpcCb() above can perform a
-        // delayed retry).
-        new_status = Status::NotFound("no leader found: " + ToString());
+        string msg;
+        if (resp.master_addrs_size() > 0 &&
+            resp.master_addrs_size() != addrs_with_names_.size()) {
+          // If we connected to a non-leader, and it responds that the
+          // number of masters in the cluster don't match the client's
+          // view of the number of masters, then it's likely the client
+          // is mis-configured (i.e with a subset of the masters).
+          // We'll include that info in the error message.
+          string client_config = JoinMapped(
+              addrs_with_names_,
+              [](const pair<Sockaddr, string>& addr_with_name) {
+                return Substitute("$0:$1", addr_with_name.second, addr_with_name.first.port());
+              }, ",");
+          string cluster_config = JoinMapped(
+              resp.master_addrs(),
+              [](const HostPortPB& pb) {
+                return Substitute("$0:$1", pb.host(), pb.port());
+              }, ",");
+          new_status = Status::ConfigurationError(Substitute(
+              "no leader master found. Client configured with $0 master(s) ($1) "
+              "but cluster indicates it expects $2 master(s) ($3)",
+              addrs_with_names_.size(), client_config,
+              resp.master_addrs_size(), cluster_config));
+        } else {
+          // Use a Status::NotFound() to indicate that the node is not
+          // the leader: this way, we can handle the case where we've
+          // received a reply from all of the nodes in the cluster (no
+          // network or other errors encountered), but haven't found a
+          // leader (which means that SendRpcCb() above can perform a
+          // delayed retry).
+          new_status = Status::NotFound("no leader found", ToString());
+        }
       } else {
         // We've found a leader.
         leader_idx_ = master_idx;

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/integration-tests/master_replication-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/master_replication-itest.cc b/src/kudu/integration-tests/master_replication-itest.cc
index 80728ad..f75bca5 100644
--- a/src/kudu/integration-tests/master_replication-itest.cc
+++ b/src/kudu/integration-tests/master_replication-itest.cc
@@ -32,6 +32,7 @@
 #include "kudu/gutil/gscoped_ptr.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/ref_counted.h"
+#include "kudu/gutil/strings/substitute.h"
 #include "kudu/master/catalog_manager.h"
 #include "kudu/master/master.h"
 #include "kudu/master/master.pb.h"
@@ -52,6 +53,8 @@
 using std::string;
 using std::vector;
 
+using strings::Substitute;
+
 namespace kudu {
 namespace master {
 
@@ -288,5 +291,49 @@ TEST_F(MasterReplicationTest, TestMasterPeerSetsDontMatch) {
   ASSERT_STR_CONTAINS(s.ToString(), "55555");
 }
 
+TEST_F(MasterReplicationTest, TestConnectToClusterReturnsAddresses) {
+  for (int i = 0; i < cluster_->num_masters(); i++) {
+    SCOPED_TRACE(Substitute("Connecting to master $0", i));
+    auto proxy = cluster_->master_proxy(i);
+    rpc::RpcController rpc;
+    ConnectToMasterRequestPB req;
+    ConnectToMasterResponsePB resp;
+    ASSERT_OK(proxy->ConnectToMaster(req, &resp, &rpc));
+    ASSERT_EQ(cluster_->num_masters(), resp.master_addrs_size());
+    for (int j = 0; j < cluster_->num_masters(); j++) {
+      const auto& addr = resp.master_addrs(j);
+      ASSERT_EQ(cluster_->mini_master(j)->bound_rpc_addr().ToString(),
+                Substitute("$0:$1", addr.host(), addr.port()));
+    }
+  }
+}
+
+
+// Test for KUDU-2200: if a user specifies just one of the masters, and that master is a
+// follower, we should give a status message that explains their mistake.
+TEST_F(MasterReplicationTest, TestConnectToFollowerMasterOnly) {
+  int successes = 0;
+  for (int i = 0; i < cluster_->num_masters(); i++) {
+    SCOPED_TRACE(Substitute("Connecting to master $0", i));
+
+    shared_ptr<KuduClient> client;
+    KuduClientBuilder builder;
+    builder.add_master_server_addr(cluster_->mini_master(i)->bound_rpc_addr_str());
+    Status s = builder.Build(&client);
+    if (s.ok()) {
+      successes++;
+    } else {
+      ASSERT_STR_MATCHES(s.ToString(),
+                         R"(Configuration error: .*Client configured with 1 master\(s\) \(.+\)
)"
+                         R"(but cluster indicates it expects 3.*)");
+    }
+  }
+  // It's possible that we get either 0 or 1 success in the above loop:
+  // - 0, in the case that no master had elected itself yet
+  // - 1, in the case that one master had become leader by the time we connected.
+  EXPECT_LE(successes, 1);
+}
+
+
 } // namespace master
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/master/master-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/master/master-test.cc b/src/kudu/master/master-test.cc
index 30a914d..de0af5c 100644
--- a/src/kudu/master/master-test.cc
+++ b/src/kudu/master/master-test.cc
@@ -1424,6 +1424,10 @@ TEST_F(MasterTest, TestConnectToMaster) {
   security::TokenPB token;
   ASSERT_TRUE(token.ParseFromString(resp.authn_token().token_data()));
   ASSERT_TRUE(token.authn().has_username());
+
+  ASSERT_EQ(1, resp.master_addrs_size());
+  ASSERT_EQ("127.0.0.1", resp.master_addrs(0).host());
+  ASSERT_NE(0, resp.master_addrs(0).port());
 }
 
 // Test that the master signs its on server certificate when it becomes the leader,

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/master/master.cc
----------------------------------------------------------------------
diff --git a/src/kudu/master/master.cc b/src/kudu/master/master.cc
index 0bb45cf..5aff500 100644
--- a/src/kudu/master/master.cc
+++ b/src/kudu/master/master.cc
@@ -30,14 +30,17 @@
 #include <glog/logging.h>
 
 #include "kudu/cfile/block_cache.h"
+#include "kudu/common/common.pb.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/common/wire_protocol.pb.h"
 #include "kudu/consensus/metadata.pb.h"
+#include "kudu/consensus/raft_consensus.h"
 #include "kudu/fs/fs_manager.h"
 #include "kudu/gutil/bind.h"
 #include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/move.h"
+#include "kudu/gutil/ref_counted.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/master/catalog_manager.h"
 #include "kudu/master/master.pb.h"
@@ -45,6 +48,7 @@
 #include "kudu/master/master_cert_authority.h"
 #include "kudu/master/master_path_handlers.h"
 #include "kudu/master/master_service.h"
+#include "kudu/master/sys_catalog.h"
 #include "kudu/master/ts_manager.h"
 #include "kudu/rpc/messenger.h"
 #include "kudu/rpc/rpc_controller.h"
@@ -52,6 +56,7 @@
 #include "kudu/security/token_signer.h"
 #include "kudu/server/rpc_server.h"
 #include "kudu/server/webserver.h"
+#include "kudu/tablet/tablet_replica.h"
 #include "kudu/tserver/tablet_copy_service.h"
 #include "kudu/tserver/tablet_service.h"
 #include "kudu/util/flag_tags.h"
@@ -330,5 +335,31 @@ Status Master::ListMasters(std::vector<ServerEntryPB>* masters)
const {
   return Status::OK();
 }
 
+Status Master::GetMasterHostPorts(std::vector<HostPortPB>* hostports) const {
+  auto consensus = catalog_manager_->sys_catalog()->tablet_replica()->shared_consensus();
+  if (!consensus) {
+    return Status::IllegalState("consensus not running");
+  }
+
+  hostports->clear();
+  consensus::RaftConfigPB config = consensus->CommittedConfig();
+  for (auto& peer : *config.mutable_peers()) {
+    if (peer.member_type() == consensus::RaftPeerPB::VOTER) {
+      // In non-distributed master configurations, we don't store our own
+      // last known address in the Raft config. So, we'll fill it in from
+      // the server Registration instead.
+      if (!peer.has_last_known_addr()) {
+        DCHECK_EQ(config.peers_size(), 1);
+        DCHECK(registration_initialized_.load());
+        hostports->emplace_back(registration_.rpc_addresses(0));
+      } else {
+        hostports->emplace_back(std::move(*peer.mutable_last_known_addr()));
+      }
+    }
+  }
+  return Status::OK();
+}
+
+
 } // namespace master
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/master/master.h
----------------------------------------------------------------------
diff --git a/src/kudu/master/master.h b/src/kudu/master/master.h
index 63a29a4..fda75a1 100644
--- a/src/kudu/master/master.h
+++ b/src/kudu/master/master.h
@@ -34,6 +34,7 @@
 
 namespace kudu {
 
+class HostPortPB;
 class MaintenanceManager;
 class MonoDelta;
 class ThreadPool;
@@ -88,12 +89,20 @@ class Master : public kserver::KuduServer {
   // Get node instance, Raft role, RPC and HTTP addresses for all
   // masters.
   //
-  // TODO move this to a separate class to be re-used in TS and
+  // NOTE: this performs a round-trip RPC to all of the masters so
+  // should not be used in any performance-critical paths.
+  //
+  // TODO(todd) move this to a separate class to be re-used in TS and
   // client; cache this information with a TTL (possibly in another
   // SysTable), so that we don't have to perform an RPC call on every
   // request.
   Status ListMasters(std::vector<ServerEntryPB>* masters) const;
 
+  // Gets the HostPorts for all of the masters in the cluster.
+  // This is not as complete as ListMasters() above, but operates just
+  // based on local state.
+  Status GetMasterHostPorts(std::vector<HostPortPB>* hostports) const;
+
   bool IsShutdown() const {
     return state_ == kStopped;
   }

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/master/master.proto
----------------------------------------------------------------------
diff --git a/src/kudu/master/master.proto b/src/kudu/master/master.proto
index 68891cb..4ec6dd1 100644
--- a/src/kudu/master/master.proto
+++ b/src/kudu/master/master.proto
@@ -609,6 +609,18 @@ message ConnectToMasterResponsePB {
   // If the client requested an authentication token, and security is
   // enabled on the cluster, the master returns a signed authn token.
   optional security.SignedTokenPB authn_token = 4;
+
+  // The hosts and ports of the masters in this cluster.
+  //
+  // NOTE: Added in Kudu 1.6.
+  //
+  // NOTE: it is likely, but not guaranteed that the hostnames advertised here
+  // will be usable by all clients. Client implementations should not use this
+  // field for "discovery" of other masters, since then it's likely that
+  // users will configure applications to only talk to one the masters in
+  // an HA setup. If that master then fails, the applications would go
+  // offline.
+  repeated HostPortPB master_addrs = 5;
 }
 
 // ============================================================================

http://git-wip-us.apache.org/repos/asf/kudu/blob/3e86797e/src/kudu/master/master_service.cc
----------------------------------------------------------------------
diff --git a/src/kudu/master/master_service.cc b/src/kudu/master/master_service.cc
index 190e994..0a8e82a 100644
--- a/src/kudu/master/master_service.cc
+++ b/src/kudu/master/master_service.cc
@@ -20,11 +20,13 @@
 #include <memory>
 #include <ostream>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
+#include "kudu/common/common.pb.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/common/wire_protocol.pb.h"
 #include "kudu/gutil/strings/substitute.h"
@@ -418,6 +420,18 @@ void MasterServiceImpl::ConnectToMaster(const ConnectToMasterRequestPB*
/*req*/,
   auto role = server_->catalog_manager()->Role();
   resp->set_role(role);
 
+  // Set the info about the other masters, so that the client can verify
+  // it has the full set of info.
+  {
+    vector<HostPortPB> hostports;
+    WARN_NOT_OK(server_->GetMasterHostPorts(&hostports),
+                "unable to get HostPorts for masters");
+    resp->mutable_master_addrs()->Reserve(hostports.size());
+    for (auto& hp : hostports) {
+      *resp->add_master_addrs() = std::move(hp);
+    }
+  }
+
   if (l.leader_status().ok()) {
     // TODO(KUDU-1924): it seems there is some window when 'role' is LEADER but
     // in fact we aren't done initializing (and we don't have a CA cert).


Mime
View raw message