You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@livy.apache.org by js...@apache.org on 2017/06/27 06:39:22 UTC
[41/50] [abbrv] incubator-livy git commit: LIVY-342. Create Livy UI:
Create Web UI Servlet and All Sessions Page (#319)
http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/resources/com/cloudera/livy/server/ui/static/sessions-table.html
----------------------------------------------------------------------
diff --git a/server/src/main/resources/com/cloudera/livy/server/ui/static/sessions-table.html b/server/src/main/resources/com/cloudera/livy/server/ui/static/sessions-table.html
new file mode 100644
index 0000000..3452b4c
--- /dev/null
+++ b/server/src/main/resources/com/cloudera/livy/server/ui/static/sessions-table.html
@@ -0,0 +1,53 @@
+<!--
+ 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="interactive-sessions-header" class="sessions-template">Interactive Sessions</h4>
+
+<table class="table table-striped sessions-table sessions-template">
+ <thead class="sessions-table-head">
+ <tr>
+ <th>Session Id</th>
+ <th>Application Id</th>
+ <th>
+ <span data-toggle="tooltip" title="Remote user who submitted this session">
+ Owner
+ </span>
+ </th>
+ <th>
+ <span data-toggle="tooltip" title="User to impersonate when running">
+ Proxy User
+ </span>
+ </th>
+ <th>
+ <span data-toggle="tooltip"
+ title="Session kind (spark, pyspark, pyspark3, or sparkr)">
+ Session Kind
+ </span>
+ </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
http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/scala/com/cloudera/livy/LivyConf.scala
----------------------------------------------------------------------
diff --git a/server/src/main/scala/com/cloudera/livy/LivyConf.scala b/server/src/main/scala/com/cloudera/livy/LivyConf.scala
index 8fc4777..233aa63 100644
--- a/server/src/main/scala/com/cloudera/livy/LivyConf.scala
+++ b/server/src/main/scala/com/cloudera/livy/LivyConf.scala
@@ -64,6 +64,8 @@ object LivyConf {
val SERVER_PORT = Entry("livy.server.port", 8998)
val CSRF_PROTECTION = LivyConf.Entry("livy.server.csrf-protection.enabled", false)
+ val UI_ENABLED = Entry("livy.ui.enabled", true)
+
val IMPERSONATION_ENABLED = Entry("livy.impersonation.enabled", false)
val SUPERUSERS = Entry("livy.superusers", null)
http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/scala/com/cloudera/livy/server/LivyServer.scala
----------------------------------------------------------------------
diff --git a/server/src/main/scala/com/cloudera/livy/server/LivyServer.scala b/server/src/main/scala/com/cloudera/livy/server/LivyServer.scala
index 4bd5635..7bfe9ce 100644
--- a/server/src/main/scala/com/cloudera/livy/server/LivyServer.scala
+++ b/server/src/main/scala/com/cloudera/livy/server/LivyServer.scala
@@ -30,12 +30,14 @@ import org.apache.hadoop.security.authentication.server._
import org.eclipse.jetty.servlet.FilterHolder
import org.scalatra.metrics.MetricsBootstrap
import org.scalatra.metrics.MetricsSupportExtensions._
+import org.scalatra.ScalatraServlet
import org.scalatra.servlet.{MultipartConfig, ServletApiImplicits}
import com.cloudera.livy._
import com.cloudera.livy.server.batch.BatchSessionServlet
import com.cloudera.livy.server.interactive.InteractiveSessionServlet
import com.cloudera.livy.server.recovery.{SessionStore, StateStore}
+import com.cloudera.livy.server.ui.UIServlet
import com.cloudera.livy.sessions.{BatchSessionManager, InteractiveSessionManager}
import com.cloudera.livy.sessions.SessionManager.SESSION_RECOVERY_MODE_OFF
import com.cloudera.livy.utils.LivySparkUtils._
@@ -142,6 +144,20 @@ class LivyServer extends Logging {
}
}
+ // Servlet for hosting static files such as html, css, and js
+ // Necessary since Jetty cannot set it's resource base inside a jar
+ val staticResourceServlet = new ScalatraServlet {
+ get("/*") {
+ getClass.getResourceAsStream("ui/static/" + params("splat"))
+ }
+ }
+
+ def uiRedirectServlet(path: String) = new ScalatraServlet {
+ get("/") {
+ redirect(path)
+ }
+ }
+
server.context.addEventListener(
new ServletContextListener() with MetricsBootstrap with ServletApiImplicits {
@@ -167,7 +183,16 @@ class LivyServer extends Logging {
val batchServlet = new BatchSessionServlet(batchSessionManager, sessionStore, livyConf)
mount(context, batchServlet, "/batches/*")
- context.mountMetricsAdminServlet("/")
+ if (livyConf.getBoolean(UI_ENABLED)) {
+ val uiServlet = new UIServlet
+ mount(context, uiServlet, "/ui/*")
+ mount(context, staticResourceServlet, "/static/*")
+ mount(context, uiRedirectServlet("/ui/"), "/*")
+ } else {
+ mount(context, uiRedirectServlet("/metrics"), "/*")
+ }
+
+ context.mountMetricsAdminServlet("/metrics")
mount(context, livyVersionServlet, "/version/*")
} catch {
http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/61b206e0/server/src/main/scala/com/cloudera/livy/server/ui/UIServlet.scala
----------------------------------------------------------------------
diff --git a/server/src/main/scala/com/cloudera/livy/server/ui/UIServlet.scala b/server/src/main/scala/com/cloudera/livy/server/ui/UIServlet.scala
new file mode 100644
index 0000000..ca2d4a1
--- /dev/null
+++ b/server/src/main/scala/com/cloudera/livy/server/ui/UIServlet.scala
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package com.cloudera.livy.server.ui
+
+import scala.xml.Node
+
+import org.scalatra.ScalatraServlet
+
+import com.cloudera.livy.LivyConf
+
+class UIServlet extends ScalatraServlet {
+ before() { contentType = "text/html" }
+
+ def getHeader(title: String): Seq[Node] =
+ <head>
+ <link rel="stylesheet" href="/static/bootstrap.min.css" type="text/css"/>
+ <link rel="stylesheet" href="/static/livy-ui.css" type="text/css"/>
+ <script src="/static/jquery-3.2.1.min.js"></script>
+ <script src="/static/bootstrap.min.js"></script>
+ <script src="/static/all-sessions.js"></script>
+ <title>{title}</title>
+ </head>
+
+ def navBar(pageName: String): Seq[Node] =
+ <nav class="navbar navbar-default">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <a class="navbar-brand" href="#">
+ <img alt="Livy" src="/static/livy-mini-logo.png"/>
+ </a>
+ </div>
+ <div class="collapse navbar-collapse">
+ <ul class="nav navbar-nav">
+ <li><a href="#">{pageName}</a></li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+
+ def createPage(pageName: String, pageContents: Seq[Node]): Seq[Node] =
+ <html>
+ {getHeader("Livy - " + pageName)}
+ <body>
+ <div class="container">
+ {navBar(pageName)}
+ {pageContents}
+ </div>
+ </body>
+ </html>
+
+ get("/") {
+ val content =
+ <div id="all-sessions">
+ <div id="interactive-sessions"></div>
+ <div id="batches"></div>
+ </div>
+
+ createPage("Sessions", content)
+ }
+}