LIVY-342. Create Livy UI: Create Web UI Servlet and All Sessions Page (#319)
* squash of original ui poc code * Initial All Sessions Page code * finished all-sessions page and cleaned up code * Moved metrics and added ui redirect, added no sessions message * added conf to template, cleaned up missed code from last commit * UI enable/disable no long configureable, always on * nit * Address review and fixed some html/css errors * Fixed ITs and added a redirect to metrics when ui is disabled Project: http://git-wip-us.apache.org/repos/asf/incubator-livy/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-livy/commit/61b206e0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-livy/tree/61b206e0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-livy/diff/61b206e0 Branch: refs/heads/master Commit: 61b206e0adc0b3efa52ef91283238c85cbe117fd Parents: 0ddcaf6 Author: Alex Bozarth <ajboz...@us.ibm.com> Authored: Tue May 9 14:02:22 2017 -0700 Committer: Jeff Zhang <zjf...@gmail.com> Committed: Tue May 9 14:02:22 2017 -0700 ---------------------------------------------------------------------- conf/livy.conf.template | 3 + .../livy/test/framework/MiniCluster.scala | 2 +- server/pom.xml | 3 + .../livy/server/ui/static/all-sessions.js | 79 +++++++++++++++++++ .../livy/server/ui/static/batches-table.html | 37 +++++++++ .../livy/server/ui/static/bootstrap.min.css | 14 ++++ .../livy/server/ui/static/bootstrap.min.js | 7 ++ .../livy/server/ui/static/jquery-3.2.1.min.js | 4 + .../livy/server/ui/static/livy-mini-logo.png | Bin 0 -> 1121 bytes .../cloudera/livy/server/ui/static/livy-ui.css | 21 +++++ .../livy/server/ui/static/sessions-table.html | 53 +++++++++++++ .../main/scala/com/cloudera/livy/LivyConf.scala | 2 + .../com/cloudera/livy/server/LivyServer.scala | 27 ++++++- .../com/cloudera/livy/server/ui/UIServlet.scala | 76 ++++++++++++++++++ 14 files changed, 326 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/conf/livy.conf.template ---------------------------------------------------------------------- diff --git a/conf/livy.conf.template b/conf/livy.conf.template index dd2f054..8bef995 100644 --- a/conf/livy.conf.template +++ b/conf/livy.conf.template @@ -97,3 +97,6 @@ # # Days to keep Livy server request logs. # livy.server.request-log-retain.days = 5 + +# If the Livy Web UI should be included in the Livy Server. Enabled by default. +# livy.ui.enabled = true http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/integration-test/src/main/scala/com/cloudera/livy/test/framework/MiniCluster.scala ---------------------------------------------------------------------- diff --git a/integration-test/src/main/scala/com/cloudera/livy/test/framework/MiniCluster.scala b/integration-test/src/main/scala/com/cloudera/livy/test/framework/MiniCluster.scala index 6aa02f1..973d7d7 100644 --- a/integration-test/src/main/scala/com/cloudera/livy/test/framework/MiniCluster.scala +++ b/integration-test/src/main/scala/com/cloudera/livy/test/framework/MiniCluster.scala @@ -302,7 +302,7 @@ class MiniCluster(config: Map[String, String]) extends Cluster with MiniClusterU // Wait until Livy server responds. val httpClient = new AsyncHttpClient() eventually(timeout(30 seconds), interval(1 second)) { - val res = httpClient.prepareGet(livyUrl).execute().get() + val res = httpClient.prepareGet(livyUrl + "/metrics").execute().get() assert(res.getStatusCode() == HttpServletResponse.SC_OK) } http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/pom.xml ---------------------------------------------------------------------- diff --git a/server/pom.xml b/server/pom.xml index 6846be9..3bca3fd 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -219,6 +219,9 @@ <build> <resources> <resource> + <directory>${project.basedir}/src/main/resources</directory> + </resource> + <resource> <!-- Include the properties file to provide the build information. --> <directory>${project.build.directory}/extra-resources</directory> <filtering>true</filtering> http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/resources/com/cloudera/livy/server/ui/static/all-sessions.js ---------------------------------------------------------------------- diff --git a/server/src/main/resources/com/cloudera/livy/server/ui/static/all-sessions.js b/server/src/main/resources/com/cloudera/livy/server/ui/static/all-sessions.js new file mode 100644 index 0000000..b0c6904 --- /dev/null +++ b/server/src/main/resources/com/cloudera/livy/server/ui/static/all-sessions.js @@ -0,0 +1,79 @@ +/* + * Licensed to Cloudera, Inc. under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Cloudera, Inc. 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. + */ + +function tdWrap(str) { + return "<td>" + str + "</td>"; +} + +function loadSessionsTable(sessions) { + $.each(sessions, function(index, session) { + $("#interactive-sessions .sessions-table-body").append( + "<tr>" + + tdWrap(session.id) + + tdWrap(session.appId) + + tdWrap(session.owner) + + tdWrap(session.proxyUser) + + tdWrap(session.kind) + + tdWrap(session.state) + + "</tr>" + ); + }); +} + +function loadBatchesTable(sessions) { + $.each(sessions, function(index, session) { + $("#batches .sessions-table-body").append( + "<tr>" + + tdWrap(session.id) + + tdWrap(session.appId) + + tdWrap(session.state) + + "</tr>" + ); + }); +} + +var numSessions = 0; +var numBatches = 0; + +$(document).ready(function () { + var sessionsReq = $.getJSON(location.origin + "/sessions", function(response) { + if (response && response.total > 0) { + $("#interactive-sessions").load("/static/sessions-table.html .sessions-template", function() { + loadSessionsTable(response.sessions); + $('#interactive-sessions [data-toggle="tooltip"]').tooltip(); + }); + } + numSessions = response.total; + }); + + var batchesReq = $.getJSON(location.origin + "/batches", function(response) { + if (response && response.total > 0) { + $("#batches").load("/static/batches-table.html .sessions-template", function() { + loadBatchesTable(response.sessions); + $('#batches [data-toggle="tooltip"]').tooltip(); + }); + } + numBatches = response.total; + }); + + $.when(sessionsReq, batchesReq).done(function () { + if (numSessions + numBatches == 0) { + $("#all-sessions").append('<h4>No Sessions or Batches have been created yet.</h4>'); + } + }); +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/resources/com/cloudera/livy/server/ui/static/batches-table.html ---------------------------------------------------------------------- diff --git a/server/src/main/resources/com/cloudera/livy/server/ui/static/batches-table.html b/server/src/main/resources/com/cloudera/livy/server/ui/static/batches-table.html new file mode 100644 index 0000000..45efbd6 --- /dev/null +++ b/server/src/main/resources/com/cloudera/livy/server/ui/static/batches-table.html @@ -0,0 +1,37 @@ +<!-- + Licensed to Cloudera, Inc. under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. Cloudera, Inc. 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. +--> + +<h4 id="batches-header" class="sessions-template">Batch Sessions</h4> + +<table class="table table-striped sessions-table sessions-template"> + <thead class="sessions-table-head"> + <tr> + <th>Batch Id</th> + <th>Application Id</th> + <th> + <span data-toggle="tooltip" + title="Session State (not_started, starting, idle, busy, + shutting_down, error, dead, success)"> + State + </span> + </th> + </tr> + </thead> + <tbody class="sessions-table-body"> + </tbody> +</table> \ No newline at end of file