Repository: kudu Updated Branches: refs/heads/master 9ad90eebe -> 36187ef62
[webui] Convert /tablet and its offshoots to mustache This patch converts the following pages to mustache templates: * /tablet * /tablet-consensus-status * /tablet-rowsetlayout-svg * /log-anchors It does the conversion as simply as possible and makes no changes to the content exposed, except it linkifies the tablet id in a couple of cases. Follow-ups will make improvements and add more information. Change-Id: Iea14f5504b9665b9c349efc9b3b13fc3fe19d8b2 Reviewed-on: http://gerrit.cloudera.org:8080/11288 Reviewed-by: Alexey Serbin <aser...@cloudera.com> Tested-by: Will Berkeley <wdberke...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/a6baa721 Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/a6baa721 Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/a6baa721 Branch: refs/heads/master Commit: a6baa721076f9e7a91d0f108ef5b4a443c731f7c Parents: 9ad90ee Author: Will Berkeley <wdberke...@gmail.org> Authored: Tue Aug 21 10:39:40 2018 -0700 Committer: Will Berkeley <wdberke...@gmail.com> Committed: Wed Aug 22 22:12:25 2018 +0000 ---------------------------------------------------------------------- src/kudu/server/webui_util.cc | 41 ------- src/kudu/tserver/tserver_path_handlers.cc | 141 ++++++++++--------------- src/kudu/tserver/tserver_path_handlers.h | 8 +- www/log-anchors.mustache | 25 +++++ www/tablet-consensus-status.mustache | 24 +++++ www/tablet-rowsetlayout-svg.mustache | 25 +++++ www/tablet.mustache | 66 ++++++++++++ 7 files changed, 201 insertions(+), 129 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/src/kudu/server/webui_util.cc ---------------------------------------------------------------------- diff --git a/src/kudu/server/webui_util.cc b/src/kudu/server/webui_util.cc index cd73042..590080f 100644 --- a/src/kudu/server/webui_util.cc +++ b/src/kudu/server/webui_util.cc @@ -17,7 +17,6 @@ #include "kudu/server/webui_util.h" -#include <sstream> #include <string> #include "kudu/common/common.pb.h" @@ -29,7 +28,6 @@ #include "kudu/util/compression/compression.pb.h" #include "kudu/util/easy_json.h" #include "kudu/util/monotime.h" -#include "kudu/util/url-coding.h" using std::string; using strings::Substitute; @@ -55,45 +53,6 @@ void SchemaToJson(const Schema& schema, EasyJson* output) { } } -void HtmlOutputSchemaTable(const Schema& schema, - std::ostringstream* output) { - *output << "<table class='table table-striped'>\n"; - *output << " <thead><tr>" - << "<th>Column</th><th>ID</th><th>Type</th>" - << "<th>Encoding</th><th>Compression</th>" - << "<th>Read default</th><th>Write default</th>" - << "</tr></thead>\n"; - *output << "<tbody>"; - for (int i = 0; i < schema.num_columns(); i++) { - const ColumnSchema& col = schema.column(i); - const string& html_escaped_col_name = EscapeForHtmlToString(col.name()); - const string& col_name = schema.is_key_column(i) ? - Substitute("<u>$0</u>", html_escaped_col_name) : - html_escaped_col_name; - string read_default = "-"; - if (col.has_read_default()) { - read_default = col.Stringify(col.read_default_value()); - } - string write_default = "-"; - if (col.has_write_default()) { - write_default = col.Stringify(col.write_default_value()); - } - const ColumnStorageAttributes& attrs = col.attributes(); - const string& encoding = EncodingType_Name(attrs.encoding); - const string& compression = CompressionType_Name(attrs.compression); - *output << Substitute("<tr><th>$0</th><td>$1</td><td>$2</td><td>$3</td>" - "<td>$4</td><td>$5</td><td>$6</td></tr>\n", - col_name, - schema.column_id(i), - col.TypeToString(), - EscapeForHtmlToString(encoding), - EscapeForHtmlToString(compression), - EscapeForHtmlToString(read_default), - EscapeForHtmlToString(write_default)); - } - *output << "</tbody></table>\n"; -} - void TaskListToJson(const std::vector<scoped_refptr<MonitoredTask> >& tasks, EasyJson* output) { EasyJson tasks_json = output->Set("tasks", EasyJson::kArray); for (const scoped_refptr<MonitoredTask>& task : tasks) { http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/src/kudu/tserver/tserver_path_handlers.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tserver/tserver_path_handlers.cc b/src/kudu/tserver/tserver_path_handlers.cc index b8071ed..ddaa3c1 100644 --- a/src/kudu/tserver/tserver_path_handlers.cc +++ b/src/kudu/tserver/tserver_path_handlers.cc @@ -101,6 +101,16 @@ bool CompareByMemberType(const RaftPeerPB& a, const RaftPeerPB& b) { return a.member_type() < b.member_type(); } +string TabletLink(const string& id) { + return Substitute("<a href=\"/tablet?id=$0\">$1</a>", + UrlEncodeToString(id), + EscapeForHtmlToString(id)); +} + +bool IsTombstoned(const scoped_refptr<TabletReplica>& replica) { + return replica->data_state() == tablet::TABLET_DATA_TOMBSTONED; +} + string ConsensusStatePBToHtml(const ConsensusStatePB& cstate, const string& local_uuid) { ostringstream html; @@ -132,31 +142,36 @@ string ConsensusStatePBToHtml(const ConsensusStatePB& cstate, bool GetTabletID(const Webserver::WebRequest& req, string* id, - Webserver::PrerenderedWebResponse* resp) { + Webserver::WebResponse* resp) { if (!FindCopy(req.parsed_args, "id", id)) { resp->status_code = HttpStatusCode::BadRequest; - *resp->output << "Tablet missing 'id' argument"; + resp->output->Set("error", "Request missing 'id' argument"); return false; } return true; } -bool GetTabletReplica(TabletServer* tserver, const Webserver::WebRequest& /*req*/, - scoped_refptr<TabletReplica>* replica, const string& tablet_id, - Webserver::PrerenderedWebResponse* resp) { +bool GetTabletReplica(TabletServer* tserver, + const Webserver::WebRequest& /*req*/, + scoped_refptr<TabletReplica>* replica, + const string& tablet_id, + Webserver::WebResponse* resp) { if (!tserver->tablet_manager()->LookupTablet(tablet_id, replica)) { resp->status_code = HttpStatusCode::NotFound; - *resp->output << "Tablet " << EscapeForHtmlToString(tablet_id) << " not found"; + resp->output->Set("error", + Substitute("Tablet $0 not found", tablet_id)); return false; } return true; } -bool TabletBootstrapping(const scoped_refptr<TabletReplica>& replica, const string& tablet_id, - Webserver::PrerenderedWebResponse* resp) { +bool TabletBootstrapping(const scoped_refptr<TabletReplica>& replica, + const string& tablet_id, + Webserver::WebResponse* resp) { if (replica->state() == tablet::BOOTSTRAPPING) { resp->status_code = HttpStatusCode::ServiceUnavailable; - *resp->output << "Tablet " << EscapeForHtmlToString(tablet_id) << " is still bootstrapping"; + resp->output->Set("error", + Substitute("Tablet $0 is still bootstrapping", tablet_id)); return true; } return false; @@ -167,7 +182,7 @@ bool TabletBootstrapping(const scoped_refptr<TabletReplica>& replica, const stri bool LoadTablet(TabletServer* tserver, const Webserver::WebRequest& req, string* tablet_id, scoped_refptr<TabletReplica>* replica, - Webserver::PrerenderedWebResponse* resp) { + Webserver::WebResponse* resp) { return GetTabletID(req, tablet_id, resp) && GetTabletReplica(tserver, req, replica, *tablet_id, resp) && !TabletBootstrapping(*replica, *tablet_id, resp); @@ -187,7 +202,7 @@ Status TabletServerPathHandlers::Register(Webserver* server) { "/tablets", "Tablets", boost::bind(&TabletServerPathHandlers::HandleTabletsPage, this, _1, _2), true /* styled */, true /* is_on_nav_bar */); - server->RegisterPrerenderedPathHandler( + server->RegisterPathHandler( "/tablet", "", boost::bind(&TabletServerPathHandlers::HandleTabletPage, this, _1, _2), true /* styled */, false /* is_on_nav_bar */); @@ -195,15 +210,15 @@ Status TabletServerPathHandlers::Register(Webserver* server) { "/transactions", "", boost::bind(&TabletServerPathHandlers::HandleTransactionsPage, this, _1, _2), true /* styled */, false /* is_on_nav_bar */); - server->RegisterPrerenderedPathHandler( + server->RegisterPathHandler( "/tablet-rowsetlayout-svg", "", boost::bind(&TabletServerPathHandlers::HandleTabletSVGPage, this, _1, _2), true /* styled */, false /* is_on_nav_bar */); - server->RegisterPrerenderedPathHandler( + server->RegisterPathHandler( "/tablet-consensus-status", "", boost::bind(&TabletServerPathHandlers::HandleConsensusStatusPage, this, _1, _2), true /* styled */, false /* is_on_nav_bar */); - server->RegisterPrerenderedPathHandler( + server->RegisterPathHandler( "/log-anchors", "", boost::bind(&TabletServerPathHandlers::HandleLogAnchorsPage, this, _1, _2), true /* styled */, false /* is_on_nav_bar */); @@ -282,19 +297,6 @@ void TabletServerPathHandlers::HandleTransactionsPage(const Webserver::WebReques } } -namespace { -string TabletLink(const string& id) { - return Substitute("<a href=\"/tablet?id=$0\">$1</a>", - UrlEncodeToString(id), - EscapeForHtmlToString(id)); -} - -bool IsTombstoned(const scoped_refptr<TabletReplica>& replica) { - return replica->data_state() == tablet::TABLET_DATA_TOMBSTONED; -} - -} // anonymous namespace - void TabletServerPathHandlers::HandleTabletsPage(const Webserver::WebRequest& /*req*/, Webserver::WebResponse* resp) { EasyJson* output = resp->output; @@ -392,8 +394,7 @@ void TabletServerPathHandlers::HandleTabletsPage(const Webserver::WebRequest& /* } void TabletServerPathHandlers::HandleTabletPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp) { - ostringstream* output = resp->output; + Webserver::WebResponse* resp) { string tablet_id; scoped_refptr<TabletReplica> replica; if (!LoadTablet(tserver_, req, &tablet_id, &replica, resp)) return; @@ -405,87 +406,59 @@ void TabletServerPathHandlers::HandleTabletPage(const Webserver::WebRequest& req role = consensus->role(); } - *output << "<h1>Tablet " << EscapeForHtmlToString(tablet_id) - << " (" << replica->HumanReadableState() - << "/" << RaftPeerPB::Role_Name(role) << ")</h1>\n"; - *output << "<h3>Table " << EscapeForHtmlToString(table_name) << "</h3>"; + EasyJson* output = resp->output; + output->Set("tablet_id", tablet_id); + output->Set("state", replica->HumanReadableState()); + output->Set("role", RaftPeerPB::Role_Name(role)); + output->Set("table_name", table_name); - // Output schema in tabular format. - *output << "<h2>Schema</h2>\n"; const Schema& schema = replica->tablet_metadata()->schema(); - HtmlOutputSchemaTable(schema, output); - - *output << "<h2>Other Tablet Info Pages</h2>" << endl; - - // List of links to various tablet-specific info pages - *output << "<ul>"; - - // Link to output svg of current DiskRowSet layout over keyspace. - *output << "<li>" << Substitute("<a href=\"/tablet-rowsetlayout-svg?id=$0\">$1</a>", - UrlEncodeToString(tablet_id), - "Rowset Layout Diagram") - << "</li>" << endl; - - // Link to consensus status page. - *output << "<li>" << Substitute("<a href=\"/tablet-consensus-status?id=$0\">$1</a>", - UrlEncodeToString(tablet_id), - "Consensus Status") - << "</li>" << endl; - - // Log anchors info page. - *output << "<li>" << Substitute("<a href=\"/log-anchors?id=$0\">$1</a>", - UrlEncodeToString(tablet_id), - "Tablet Log Anchors") - << "</li>" << endl; - - // End list - *output << "</ul>\n"; + SchemaToJson(schema, output); } void TabletServerPathHandlers::HandleTabletSVGPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp) { - ostringstream* output = resp->output; - string id; + Webserver::WebResponse* resp) { + string tablet_id; scoped_refptr<TabletReplica> replica; - if (!LoadTablet(tserver_, req, &id, &replica, resp)) return; + if (!LoadTablet(tserver_, req, &tablet_id, &replica, resp)) return; shared_ptr<Tablet> tablet = replica->shared_tablet(); + auto* output = resp->output; if (!tablet) { - *output << "Tablet " << EscapeForHtmlToString(id) << " not running"; + output->Set("error", Substitute("Tablet $0 is not running", tablet_id)); return; } - *output << "<h1>Rowset Layout Diagram for Tablet " - << TabletLink(id) << "</h1>\n"; - tablet->PrintRSLayout(output); - + output->Set("tablet_id", tablet_id); + ostringstream oss; + tablet->PrintRSLayout(&oss); + output->Set("rowset_layout", oss.str()); } void TabletServerPathHandlers::HandleLogAnchorsPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp) { - ostringstream* output = resp->output; + Webserver::WebResponse* resp) { string tablet_id; scoped_refptr<TabletReplica> replica; if (!LoadTablet(tserver_, req, &tablet_id, &replica, resp)) return; - *output << "<h1>Log Anchors for Tablet " << EscapeForHtmlToString(tablet_id) << "</h1>" - << std::endl; - - string dump = replica->log_anchor_registry()->DumpAnchorInfo(); - *output << "<pre>" << EscapeForHtmlToString(dump) << "</pre>" << std::endl; + auto* output = resp->output; + output->Set("tablet_id", tablet_id); + output->Set("log_anchors", replica->log_anchor_registry()->DumpAnchorInfo()); } void TabletServerPathHandlers::HandleConsensusStatusPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp) { - ostringstream* output = resp->output; - string id; + Webserver::WebResponse* resp) { + string tablet_id; scoped_refptr<TabletReplica> replica; - if (!LoadTablet(tserver_, req, &id, &replica, resp)) return; + if (!LoadTablet(tserver_, req, &tablet_id, &replica, resp)) return; shared_ptr<consensus::RaftConsensus> consensus = replica->shared_consensus(); + auto* output = resp->output; if (!consensus) { - *output << "Tablet " << EscapeForHtmlToString(id) << " not initialized"; + output->Set("error", Substitute("Tablet $0 not initialized", tablet_id)); return; } - consensus->DumpStatusHtml(*output); + ostringstream oss; + consensus->DumpStatusHtml(oss); + output->Set("consensus_status", oss.str()); } namespace { http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/src/kudu/tserver/tserver_path_handlers.h ---------------------------------------------------------------------- diff --git a/src/kudu/tserver/tserver_path_handlers.h b/src/kudu/tserver/tserver_path_handlers.h index bd9124e..7b7beed 100644 --- a/src/kudu/tserver/tserver_path_handlers.h +++ b/src/kudu/tserver/tserver_path_handlers.h @@ -44,15 +44,15 @@ class TabletServerPathHandlers { void HandleTabletsPage(const Webserver::WebRequest& req, Webserver::WebResponse* resp); void HandleTabletPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp); + Webserver::WebResponse* resp); void HandleTransactionsPage(const Webserver::WebRequest& req, Webserver::PrerenderedWebResponse* resp); void HandleTabletSVGPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp); + Webserver::WebResponse* resp); void HandleLogAnchorsPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp); + Webserver::WebResponse* resp); void HandleConsensusStatusPage(const Webserver::WebRequest& req, - Webserver::PrerenderedWebResponse* resp); + Webserver::WebResponse* resp); void HandleDashboardsPage(const Webserver::WebRequest& req, Webserver::PrerenderedWebResponse* resp); void HandleMaintenanceManagerPage(const Webserver::WebRequest& req, http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/www/log-anchors.mustache ---------------------------------------------------------------------- diff --git a/www/log-anchors.mustache b/www/log-anchors.mustache new file mode 100644 index 0000000..a70ce0e --- /dev/null +++ b/www/log-anchors.mustache @@ -0,0 +1,25 @@ +{{! +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. +}} +{{#error}} + <div class="text-error">{{.}}</div> +{{/error}} +{{^error}} + <h1>Log Anchors for Tablet <a href="/tablet?id={{tablet_id}}">{{tablet_id}}</a></h1> + <pre>{{log_anchors}}</pre> +{{/error}} http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/www/tablet-consensus-status.mustache ---------------------------------------------------------------------- diff --git a/www/tablet-consensus-status.mustache b/www/tablet-consensus-status.mustache new file mode 100644 index 0000000..4d598e9 --- /dev/null +++ b/www/tablet-consensus-status.mustache @@ -0,0 +1,24 @@ +{{! +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. +}} +{{#error}} + <div class="text-error">{{.}}</div> +{{/error}} +{{^error}} + {{{consensus_status}}} +{{/error}} http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/www/tablet-rowsetlayout-svg.mustache ---------------------------------------------------------------------- diff --git a/www/tablet-rowsetlayout-svg.mustache b/www/tablet-rowsetlayout-svg.mustache new file mode 100644 index 0000000..dc81f11 --- /dev/null +++ b/www/tablet-rowsetlayout-svg.mustache @@ -0,0 +1,25 @@ +{{! +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. +}} +{{#error}} + <div class="text-error">{{.}}</div> +{{/error}} +{{^error}} + <h1>Rowset Layout Diagram for Tablet <a href="/tablet?id={{tablet_id}}">{{tablet_id}}</a></h1> + {{{rowset_layout}}} +{{/error}} http://git-wip-us.apache.org/repos/asf/kudu/blob/a6baa721/www/tablet.mustache ---------------------------------------------------------------------- diff --git a/www/tablet.mustache b/www/tablet.mustache new file mode 100644 index 0000000..8f80581 --- /dev/null +++ b/www/tablet.mustache @@ -0,0 +1,66 @@ +{{! +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. +}} +{{#error}} + <div class="text-error">{{.}}</div> +{{/error}} +{{^error}} + <h1>Tablet {{tablet_id}} ({{state}}/{{role}})</h1> + <h3>Table {{table_name}}</h3> + + <h2>Schema</h2> + <table class='table table-striped'> + <thead><tr> + <th>Column</th> + <th>ID</th> + <th>Type</th> + <th>Encoding</th> + <th>Compression</th> + <th>Read default</th> + <th>Write default</th> + </tr></thead> + <tbody> + {{#columns}} + <tr> + <th>{{#is_key}}<u>{{/is_key}} + {{name}} + {{#is_key}}</u>{{/is_key}}</th> + <td>{{id}}</a></td> + <td>{{type}}</td> + <td>{{encoding}}</td> + <td>{{compression}}</td> + <td>{{read_default}}</td> + <td>{{write_default}}</td> + </tr> + {{/columns}} + </tbody> + </table> + + <h2>Other Tablet Info Pages</h2> + <ul> + <li> + <a href="tablet-rowsetlayout-svg?id={{tablet_id}}">Rowset Layout Diagram</a> + </li> + <li> + <a href="tablet-consensus-status?id={{tablet_id}}">Consensus Status</a> + </li> + <li> + <a href="log-anchors?id={{tablet_id}}">Tablet Log Anchors</a> + </li> + </ul> +{{/error}}