You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by da...@apache.org on 2017/09/21 20:15:44 UTC
[2/3] kudu git commit: KUDU-501 Redirect to leader master web UI
KUDU-501 Redirect to leader master web UI
The /table and /tables page of the master web UI only work
on the leader master. Previously, we just showed a gross error when the
user tried to access these pages on a non-leader. This adds a nice
redirect instead (or an error about why a redirect wasn't possible).
Change-Id: If31543b7899976ec02704111e9e789035c44dfe1
Reviewed-on: http://gerrit.cloudera.org:8080/8068
Tested-by: Kudu Jenkins
Reviewed-by: Will Berkeley <wd...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/4daa3ce8
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/4daa3ce8
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/4daa3ce8
Branch: refs/heads/master
Commit: 4daa3ce8742280495c7b6f9a9b2a828e3572ea2c
Parents: e66fb10
Author: Will Berkeley <wd...@apache.org>
Authored: Wed Sep 13 23:59:36 2017 -0700
Committer: Will Berkeley <wd...@gmail.com>
Committed: Thu Sep 21 20:05:23 2017 +0000
----------------------------------------------------------------------
src/kudu/integration-tests/CMakeLists.txt | 2 +-
.../integration-tests/webserver-stress-itest.cc | 6 +-
src/kudu/master/master-path-handlers.cc | 87 ++++++++++++++++++--
src/kudu/master/master-path-handlers.h | 8 ++
www/table.mustache | 7 ++
www/tables.mustache | 6 ++
6 files changed, 107 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/src/kudu/integration-tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/CMakeLists.txt b/src/kudu/integration-tests/CMakeLists.txt
index 43582d1..8c36fdc 100644
--- a/src/kudu/integration-tests/CMakeLists.txt
+++ b/src/kudu/integration-tests/CMakeLists.txt
@@ -104,7 +104,7 @@ ADD_KUDU_TEST(token_signer-itest RESOURCE_LOCK "master-rpc-ports")
ADD_KUDU_TEST(ts_recovery-itest)
ADD_KUDU_TEST(ts_tablet_manager-itest)
ADD_KUDU_TEST(update_scan_delta_compact-test RUN_SERIAL true)
-ADD_KUDU_TEST(webserver-stress-itest)
+ADD_KUDU_TEST(webserver-stress-itest RESOURCE_LOCK "master-rpc-ports")
ADD_KUDU_TEST(write_throttling-itest)
if (NOT APPLE)
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/src/kudu/integration-tests/webserver-stress-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/webserver-stress-itest.cc b/src/kudu/integration-tests/webserver-stress-itest.cc
index 8c6cd92..b9503de 100644
--- a/src/kudu/integration-tests/webserver-stress-itest.cc
+++ b/src/kudu/integration-tests/webserver-stress-itest.cc
@@ -44,7 +44,11 @@ TEST_F(KuduTest, TestWebUIDoesNotCrashCluster) {
#endif
const int kNumTablets = 50;
- ExternalMiniCluster cluster;
+ ExternalMiniClusterOptions opts;
+ opts.master_rpc_ports = { 11010, 11011, 11012 };
+ opts.num_masters = opts.master_rpc_ports.size();
+
+ ExternalMiniCluster cluster(opts);
ASSERT_OK(cluster.Start());
// Start pounding the master and tserver's web UIs.
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/src/kudu/master/master-path-handlers.cc
----------------------------------------------------------------------
diff --git a/src/kudu/master/master-path-handlers.cc b/src/kudu/master/master-path-handlers.cc
index ebd42f2..bf3d12d 100644
--- a/src/kudu/master/master-path-handlers.cc
+++ b/src/kudu/master/master-path-handlers.cc
@@ -43,6 +43,7 @@
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/stringprintf.h"
#include "kudu/gutil/strings/join.h"
+#include "kudu/gutil/strings/numbers.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/master/catalog_manager.h"
#include "kudu/master/master.h"
@@ -140,11 +141,33 @@ void MasterPathHandlers::HandleTabletServers(const Webserver::WebRequest& req,
generate_table(dead_tserver_rows, "Dead Tablet Servers", output);
}
-void MasterPathHandlers::HandleCatalogManager(const Webserver::WebRequest& req,
- EasyJson* output) {
+namespace {
+
+// Extracts the value of the 'redirects' parameter from 'req'; returns 0 if the
+// parameter doesn't exist or couldn't be parsed.
+int ExtractRedirectsFromRequest(const Webserver::WebRequest& req) {
+ string redirects_str;
+ int redirects = 0;
+ if (FindCopy(req.parsed_args, "redirects", &redirects_str)) {
+ if (!safe_strto32(redirects_str, &redirects)) {
+ return 0;
+ }
+ }
+ return redirects;
+}
+
+} // anonymous namespace
+
+void MasterPathHandlers::HandleCatalogManager(const Webserver::WebRequest& req, EasyJson* output) {
CatalogManager::ScopedLeaderSharedLock l(master_->catalog_manager());
- if (!l.first_failed_status().ok()) {
- (*output)["error"] = Substitute("Master is not ready: $0", l.first_failed_status().ToString());
+ if (!l.catalog_status().ok()) {
+ (*output)["error"] = Substitute("Master is not ready: $0", l.catalog_status().ToString());
+ return;
+ }
+ if (!l.leader_status().ok()) {
+ // Track redirects to prevent a redirect loop.
+ int redirects = ExtractRedirectsFromRequest(req);
+ SetupLeaderMasterRedirect("tables?", redirects, output);
return;
}
@@ -206,15 +229,21 @@ void MasterPathHandlers::HandleTablePage(const Webserver::WebRequest& req,
}
CatalogManager::ScopedLeaderSharedLock l(master_->catalog_manager());
- if (!l.first_failed_status().ok()) {
- (*output)["error"] = Substitute("Master is not ready: ", l.first_failed_status().ToString());
+ if (!l.catalog_status().ok()) {
+ (*output)["error"] = Substitute("Master is not ready: $0", l.catalog_status().ToString());
+ return;
+ }
+ if (!l.leader_status().ok()) {
+ // Track redirects to prevent a redirect loop.
+ int redirects = ExtractRedirectsFromRequest(req);
+ SetupLeaderMasterRedirect(Substitute("table?id=$0", table_id), redirects, output);
return;
}
scoped_refptr<TableInfo> table;
Status s = master_->catalog_manager()->GetTableInfo(table_id, &table);
if (!s.ok()) {
- (*output)["error"] = Substitute("Master is not ready: ", s.ToString());
+ (*output)["error"] = Substitute("Master is not ready: $0", s.ToString());
return;
}
@@ -635,5 +664,49 @@ string MasterPathHandlers::MasterAddrsToCsv() const {
return addr.ToString();
}
+Status MasterPathHandlers::GetLeaderMasterHttpAddr(string* leader_http_addr) const {
+ vector<ServerEntryPB> masters;
+ RETURN_NOT_OK_PREPEND(master_->ListMasters(&masters), "unable to list masters");
+ for (const auto& master : masters) {
+ if (master.has_error()) {
+ continue;
+ }
+ if (master.role() != RaftPeerPB::LEADER) {
+ continue;
+ }
+ const ServerRegistrationPB& reg = master.registration();
+ if (reg.http_addresses().empty()) {
+ return Status::NotFound("leader master has no http address");
+ }
+ *leader_http_addr = Substitute("$0://$1:$2",
+ reg.https_enabled() ? "https" : "http",
+ reg.http_addresses(0).host(),
+ reg.http_addresses(0).port());
+ return Status::OK();
+ }
+ return Status::NotFound("no leader master known to this master");
+}
+
+void MasterPathHandlers::SetupLeaderMasterRedirect(const string& path,
+ int redirects,
+ EasyJson* output) const {
+ // Allow 3 redirects.
+ const int max_redirects = 3;
+ (*output)["error"] = "Master is not the leader.";
+ if (redirects >= max_redirects) {
+ (*output)["redirect_error"] = "Too many redirects attempting to find the leader master.";
+ return;
+ }
+ string leader_http_addr;
+ Status s = GetLeaderMasterHttpAddr(&leader_http_addr);
+ if (!s.ok()) {
+ (*output)["redirect_error"] = Substitute("Unable to redirect to leader master: $0",
+ s.ToString());
+ return;
+ }
+ (*output)["leader_redirect"] = Substitute("$0/$1&redirects=$2",
+ leader_http_addr, path, redirects + 1);
+}
+
} // namespace master
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/src/kudu/master/master-path-handlers.h
----------------------------------------------------------------------
diff --git a/src/kudu/master/master-path-handlers.h b/src/kudu/master/master-path-handlers.h
index 9bd05c7..6195a74 100644
--- a/src/kudu/master/master-path-handlers.h
+++ b/src/kudu/master/master-path-handlers.h
@@ -73,6 +73,14 @@ class MasterPathHandlers {
// Return a CSV of master addresses suitable for display.
std::string MasterAddrsToCsv() const;
+ // If a leader master is known and has an http address, place it in leader_http_addr.
+ Status GetLeaderMasterHttpAddr(std::string* leader_http_addr) const;
+
+ // Adds the necessary properties to 'output' to set up a redirect to the leader master, or
+ // provide an error message if no redirect is possible.
+ // The redirect will link to <master web UI url>/path&redirects=(redirects + 1).
+ void SetupLeaderMasterRedirect(const std::string& path, int redirects, EasyJson* output) const;
+
Master* master_;
DISALLOW_COPY_AND_ASSIGN(MasterPathHandlers);
};
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/www/table.mustache
----------------------------------------------------------------------
diff --git a/www/table.mustache b/www/table.mustache
index 624edb3..575d3fc 100644
--- a/www/table.mustache
+++ b/www/table.mustache
@@ -19,6 +19,12 @@ under the License.
{{#error}}
<div class="text-error">{{.}}</div>
{{/error}}
+{{#redirect_error}}
+ <div class="text-error">{{.}}</div>
+{{/redirect_error}}
+{{#leader_redirect}}
+ <div>You can find this page on the <a href="{{{.}}}">leader master's web UI</a>.</div>
+{{/leader_redirect}}
{{^error}}
<h2>Table: {{name}} ({{id}})</h2>
<table class="table table-striped">
@@ -27,6 +33,7 @@ under the License.
<tr><td>State:</td><td>{{state}} {{#state_msg}}({{.}}){{/state_msg}}</td></tr>
</tbody>
</table>
+
<h3>Schema</h3>
<table class='table table-striped'>
<thead><tr>
http://git-wip-us.apache.org/repos/asf/kudu/blob/4daa3ce8/www/tables.mustache
----------------------------------------------------------------------
diff --git a/www/tables.mustache b/www/tables.mustache
index 670b4b8..e50fd8c 100644
--- a/www/tables.mustache
+++ b/www/tables.mustache
@@ -20,6 +20,12 @@ under the License.
{{#error}}
<div class="text-error">{{.}}</div>
{{/error}}
+{{#redirect_error}}
+ <div class="text-error">{{.}}</div>
+{{/redirect_error}}
+{{#leader_redirect}}
+ <div>You can find this page on the <a href="{{{.}}}">leader master's web UI</a>.</div>
+{{/leader_redirect}}
{{^error}}
There are {{num_tables}} tables
<table class="table table-striped">