Skip to content

Commit 168fe86

Browse files
committed
Merge pull request #2 from andrewor14/ui-refactor
Refactor UI interface to allow dynamically adding tabs
2 parents 61358e3 + c78c92d commit 168fe86

29 files changed

+737
-576
lines changed

core/src/main/scala/org/apache/spark/SparkContext.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ class SparkContext(
158158

159159
// Initialize the Spark UI, registering all associated listeners
160160
private[spark] val ui = new SparkUI(this)
161-
ui.bind()
162161
ui.start()
162+
ui.bind()
163163

164164
// Optionally log Spark events
165165
private[spark] val eventLogger: Option[EventLoggingListener] = {

core/src/main/scala/org/apache/spark/deploy/master/Master.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ private[spark] class Master(
115115
logInfo("Starting Spark master at " + masterUrl)
116116
// Listen for remote client disconnection events, since they don't go through Akka's watch()
117117
context.system.eventStream.subscribe(self, classOf[RemotingLifecycleEvent])
118+
webUi.start()
118119
webUi.bind()
119120
masterWebUiUrl = "http://" + masterPublicAddress + ":" + webUi.boundPort
120121
context.system.scheduler.schedule(0 millis, WORKER_TIMEOUT millis, self, CheckForWorkerTimeOut)

core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,17 @@ import org.json4s.JValue
2828
import org.apache.spark.deploy.JsonProtocol
2929
import org.apache.spark.deploy.DeployMessages.{MasterStateResponse, RequestMasterState}
3030
import org.apache.spark.deploy.master.ExecutorInfo
31-
import org.apache.spark.ui.UIUtils
31+
import org.apache.spark.ui.{UIPage, UIUtils}
3232
import org.apache.spark.util.Utils
3333

34-
private[spark] class ApplicationPage(parent: MasterWebUI) {
35-
val master = parent.masterActorRef
36-
val timeout = parent.timeout
34+
private[spark] class ApplicationPage(parent: MasterWebUI)
35+
extends UIPage("app", includeJson = true) {
36+
37+
private val master = parent.masterActorRef
38+
private val timeout = parent.timeout
3739

3840
/** Executor details for a particular application */
39-
def renderJson(request: HttpServletRequest): JValue = {
41+
override def renderJson(request: HttpServletRequest): JValue = {
4042
val appId = request.getParameter("appId")
4143
val stateFuture = (master ? RequestMasterState)(timeout).mapTo[MasterStateResponse]
4244
val state = Await.result(stateFuture, timeout)
@@ -47,7 +49,7 @@ private[spark] class ApplicationPage(parent: MasterWebUI) {
4749
}
4850

4951
/** Executor details for a particular application */
50-
def render(request: HttpServletRequest): Seq[Node] = {
52+
override def render(request: HttpServletRequest): Seq[Node] = {
5153
val appId = request.getParameter("appId")
5254
val stateFuture = (master ? RequestMasterState)(timeout).mapTo[MasterStateResponse]
5355
val state = Await.result(stateFuture, timeout)
@@ -96,7 +98,7 @@ private[spark] class ApplicationPage(parent: MasterWebUI) {
9698
UIUtils.basicSparkPage(content, "Application: " + app.desc.name)
9799
}
98100

99-
def executorRow(executor: ExecutorInfo): Seq[Node] = {
101+
private def executorRow(executor: ExecutorInfo): Seq[Node] = {
100102
<tr>
101103
<td>{executor.id}</td>
102104
<td>

core/src/main/scala/org/apache/spark/deploy/master/ui/IndexPage.scala

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,24 @@ import scala.xml.Node
2525
import akka.pattern.ask
2626
import org.json4s.JValue
2727

28-
import org.apache.spark.deploy.{JsonProtocol}
28+
import org.apache.spark.deploy.JsonProtocol
2929
import org.apache.spark.deploy.DeployMessages.{MasterStateResponse, RequestMasterState}
3030
import org.apache.spark.deploy.master.{ApplicationInfo, DriverInfo, WorkerInfo}
31-
import org.apache.spark.ui.{WebUI, UIUtils}
31+
import org.apache.spark.ui.{UIPage, UIUtils}
3232
import org.apache.spark.util.Utils
3333

34-
private[spark] class IndexPage(parent: MasterWebUI) {
35-
val master = parent.masterActorRef
36-
val timeout = parent.timeout
34+
private[spark] class IndexPage(parent: MasterWebUI) extends UIPage("", includeJson = true) {
35+
private val master = parent.masterActorRef
36+
private val timeout = parent.timeout
3737

38-
def renderJson(request: HttpServletRequest): JValue = {
38+
override def renderJson(request: HttpServletRequest): JValue = {
3939
val stateFuture = (master ? RequestMasterState)(timeout).mapTo[MasterStateResponse]
4040
val state = Await.result(stateFuture, timeout)
4141
JsonProtocol.writeMasterState(state)
4242
}
4343

4444
/** Index view listing applications and executors */
45-
def render(request: HttpServletRequest): Seq[Node] = {
45+
override def render(request: HttpServletRequest): Seq[Node] = {
4646
val stateFuture = (master ? RequestMasterState)(timeout).mapTo[MasterStateResponse]
4747
val state = Await.result(stateFuture, timeout)
4848

@@ -139,7 +139,7 @@ private[spark] class IndexPage(parent: MasterWebUI) {
139139
UIUtils.basicSparkPage(content, "Spark Master at " + state.uri)
140140
}
141141

142-
def workerRow(worker: WorkerInfo): Seq[Node] = {
142+
private def workerRow(worker: WorkerInfo): Seq[Node] = {
143143
<tr>
144144
<td>
145145
<a href={worker.webUiAddress}>{worker.id}</a>
@@ -154,8 +154,7 @@ private[spark] class IndexPage(parent: MasterWebUI) {
154154
</tr>
155155
}
156156

157-
158-
def appRow(app: ApplicationInfo): Seq[Node] = {
157+
private def appRow(app: ApplicationInfo): Seq[Node] = {
159158
<tr>
160159
<td>
161160
<a href={"app?appId=" + app.id}>{app.id}</a>
@@ -169,14 +168,14 @@ private[spark] class IndexPage(parent: MasterWebUI) {
169168
<td sorttable_customkey={app.desc.memoryPerSlave.toString}>
170169
{Utils.megabytesToString(app.desc.memoryPerSlave)}
171170
</td>
172-
<td>{WebUI.formatDate(app.submitDate)}</td>
171+
<td>{UIUtils.formatDate(app.submitDate)}</td>
173172
<td>{app.desc.user}</td>
174173
<td>{app.state.toString}</td>
175-
<td>{WebUI.formatDuration(app.duration)}</td>
174+
<td>{UIUtils.formatDuration(app.duration)}</td>
176175
</tr>
177176
}
178177

179-
def driverRow(driver: DriverInfo): Seq[Node] = {
178+
private def driverRow(driver: DriverInfo): Seq[Node] = {
180179
<tr>
181180
<td>{driver.id} </td>
182181
<td>{driver.submitDate}</td>

core/src/main/scala/org/apache/spark/deploy/master/ui/MasterWebUI.scala

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,86 +17,55 @@
1717

1818
package org.apache.spark.deploy.master.ui
1919

20-
import javax.servlet.http.HttpServletRequest
21-
22-
import org.eclipse.jetty.servlet.ServletContextHandler
23-
2420
import org.apache.spark.Logging
2521
import org.apache.spark.deploy.master.Master
26-
import org.apache.spark.ui.{ServerInfo, SparkUI}
22+
import org.apache.spark.ui.{SparkUI, WebUI}
2723
import org.apache.spark.ui.JettyUtils._
2824
import org.apache.spark.util.{AkkaUtils, Utils}
2925

3026
/**
3127
* Web UI server for the standalone master.
3228
*/
3329
private[spark]
34-
class MasterWebUI(val master: Master, requestedPort: Int) extends Logging {
35-
val masterActorRef = master.self
36-
val timeout = AkkaUtils.askTimeout(master.conf)
30+
class MasterWebUI(val master: Master, requestedPort: Int)
31+
extends WebUI(master.securityMgr) with Logging {
3732

3833
private val host = Utils.localHostName()
3934
private val port = requestedPort
40-
private val applicationPage = new ApplicationPage(this)
41-
private val indexPage = new IndexPage(this)
42-
private var serverInfo: Option[ServerInfo] = None
35+
val masterActorRef = master.self
36+
val timeout = AkkaUtils.askTimeout(master.conf)
4337

44-
private val handlers: Seq[ServletContextHandler] = {
45-
master.masterMetricsSystem.getServletHandlers ++
46-
master.applicationMetricsSystem.getServletHandlers ++
47-
Seq[ServletContextHandler](
48-
createStaticHandler(MasterWebUI.STATIC_RESOURCE_DIR, "/static"),
49-
createServletHandler("/app/json",
50-
(request: HttpServletRequest) => applicationPage.renderJson(request), master.securityMgr),
51-
createServletHandler("/app",
52-
(request: HttpServletRequest) => applicationPage.render(request), master.securityMgr),
53-
createServletHandler("/json",
54-
(request: HttpServletRequest) => indexPage.renderJson(request), master.securityMgr),
55-
createServletHandler("/",
56-
(request: HttpServletRequest) => indexPage.render(request), master.securityMgr)
57-
)
38+
/** Initialize all components of the server. */
39+
def start() {
40+
attachPage(new ApplicationPage(this))
41+
attachPage(new IndexPage(this))
42+
attachHandler(createStaticHandler(MasterWebUI.STATIC_RESOURCE_DIR, "/static"))
43+
master.masterMetricsSystem.getServletHandlers.foreach(attachHandler)
44+
master.applicationMetricsSystem.getServletHandlers.foreach(attachHandler)
5845
}
5946

47+
/** Bind to the HTTP server behind this web interface. */
6048
def bind() {
6149
try {
6250
serverInfo = Some(startJettyServer(host, port, handlers, master.conf))
6351
logInfo("Started Master web UI at http://%s:%d".format(host, boundPort))
6452
} catch {
6553
case e: Exception =>
66-
logError("Failed to create Master JettyUtils", e)
54+
logError("Failed to create Master web UI", e)
6755
System.exit(1)
6856
}
6957
}
7058

71-
def boundPort: Int = serverInfo.map(_.boundPort).getOrElse(-1)
72-
7359
/** Attach a reconstructed UI to this Master UI. Only valid after bind(). */
7460
def attachUI(ui: SparkUI) {
7561
assert(serverInfo.isDefined, "Master UI must be bound to a server before attaching SparkUIs")
76-
val rootHandler = serverInfo.get.rootHandler
77-
for (handler <- ui.handlers) {
78-
rootHandler.addHandler(handler)
79-
if (!handler.isStarted) {
80-
handler.start()
81-
}
82-
}
62+
ui.getHandlers.foreach(attachHandler)
8363
}
8464

8565
/** Detach a reconstructed UI from this Master UI. Only valid after bind(). */
8666
def detachUI(ui: SparkUI) {
8767
assert(serverInfo.isDefined, "Master UI must be bound to a server before detaching SparkUIs")
88-
val rootHandler = serverInfo.get.rootHandler
89-
for (handler <- ui.handlers) {
90-
if (handler.isStarted) {
91-
handler.stop()
92-
}
93-
rootHandler.removeHandler(handler)
94-
}
95-
}
96-
97-
def stop() {
98-
assert(serverInfo.isDefined, "Attempted to stop a Master UI that was not bound to a server!")
99-
serverInfo.get.server.stop()
68+
ui.getHandlers.foreach(detachHandler)
10069
}
10170
}
10271

core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ private[spark] class Worker(
122122
host, port, cores, Utils.megabytesToString(memory)))
123123
logInfo("Spark home: " + sparkHome)
124124
createWorkDir()
125-
webUi = new WorkerWebUI(this, workDir, Some(webUiPort))
126125
context.system.eventStream.subscribe(self, classOf[RemotingLifecycleEvent])
126+
webUi = new WorkerWebUI(this, workDir, Some(webUiPort))
127+
webUi.start()
127128
webUi.bind()
128129
registerWithMaster()
129130

core/src/main/scala/org/apache/spark/deploy/worker/ui/IndexPage.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,21 @@ import org.apache.spark.deploy.JsonProtocol
2828
import org.apache.spark.deploy.DeployMessages.{RequestWorkerState, WorkerStateResponse}
2929
import org.apache.spark.deploy.master.DriverState
3030
import org.apache.spark.deploy.worker.{DriverRunner, ExecutorRunner}
31-
import org.apache.spark.ui.UIUtils
31+
import org.apache.spark.ui.{UIPage, UIUtils}
3232
import org.apache.spark.util.Utils
3333

34-
private[spark] class IndexPage(parent: WorkerWebUI) {
34+
private[spark] class IndexPage(parent: WorkerWebUI) extends UIPage("", includeJson = true) {
3535
val workerActor = parent.worker.self
3636
val worker = parent.worker
3737
val timeout = parent.timeout
3838

39-
def renderJson(request: HttpServletRequest): JValue = {
39+
override def renderJson(request: HttpServletRequest): JValue = {
4040
val stateFuture = (workerActor ? RequestWorkerState)(timeout).mapTo[WorkerStateResponse]
4141
val workerState = Await.result(stateFuture, timeout)
4242
JsonProtocol.writeWorkerState(workerState)
4343
}
4444

45-
def render(request: HttpServletRequest): Seq[Node] = {
45+
override def render(request: HttpServletRequest): Seq[Node] = {
4646
val stateFuture = (workerActor ? RequestWorkerState)(timeout).mapTo[WorkerStateResponse]
4747
val workerState = Await.result(stateFuture, timeout)
4848

0 commit comments

Comments
 (0)