Skip to content

Commit a4a0add

Browse files
Sergiusz UrbaniakAndrew Or
authored andcommitted
[SPARK-13492][MESOS] Configurable Mesos framework webui URL.
## What changes were proposed in this pull request? Previously the Mesos framework webui URL was being derived only from the Spark UI address leaving no possibility to configure it. This commit makes it configurable. If unset it falls back to the previous behavior. Motivation: This change is necessary in order to be able to install Spark on DCOS and to be able to give it a custom service link. The configured `webui_url` is configured to point to a reverse proxy in the DCOS environment. ## How was this patch tested? Locally, using unit tests and on DCOS testing and stable revision. Author: Sergiusz Urbaniak <[email protected]> Closes #11369 from s-urbaniak/sur-webui-url.
1 parent 5f7dbdb commit a4a0add

File tree

9 files changed

+93
-10
lines changed

9 files changed

+93
-10
lines changed

core/src/main/resources/org/apache/spark/ui/static/historypage-template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<td class="rowGroupColumn"><span title="{{id}}"><a href="{{url}}">{{id}}</a></span></td>
6868
<td class="rowGroupColumn">{{name}}</td>
6969
{{#attempts}}
70-
<td class="attemptIDSpan"><a href="/history/{{id}}/{{attemptId}}/">{{attemptId}}</a></td>
70+
<td class="attemptIDSpan"><a href="history/{{id}}/{{attemptId}}/">{{attemptId}}</a></td>
7171
<td>{{startTime}}</td>
7272
<td>{{endTime}}</td>
7373
<td><span title="{{duration}}" class="durationClass">{{duration}}</span></td>

core/src/main/resources/org/apache/spark/ui/static/historypage.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ $(document).ready(function() {
110110
requestedIncomplete = getParameterByName("showIncomplete", searchString);
111111
requestedIncomplete = (requestedIncomplete == "true" ? true : false);
112112

113-
$.getJSON("/api/v1/applications", function(response,status,jqXHR) {
113+
$.getJSON("api/v1/applications", function(response,status,jqXHR) {
114114
var array = [];
115115
var hasMultipleAttempts = false;
116116
for (i in response) {
@@ -139,9 +139,9 @@ $(document).ready(function() {
139139

140140
var url = null
141141
if (maxAttemptId == null) {
142-
url = "/history/" + id + "/"
142+
url = "history/" + id + "/"
143143
} else {
144-
url = "/history/" + id + "/" + maxAttemptId + "/"
144+
url = "history/" + id + "/" + maxAttemptId + "/"
145145
}
146146

147147
var app_clone = {"id" : id, "name" : name, "url" : url, "attempts" : [attempt]};
@@ -150,7 +150,7 @@ $(document).ready(function() {
150150
}
151151

152152
var data = {"applications": array}
153-
$.get("/static/historypage-template.html", function(template) {
153+
$.get("static/historypage-template.html", function(template) {
154154
historySummary.append(Mustache.render($(template).filter("#history-summary-template").html(),data));
155155
var selector = "#history-summary-table";
156156
var conf = {

core/src/main/scala/org/apache/spark/deploy/mesos/MesosClusterDispatcher.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private[mesos] class MesosClusterDispatcher(
7373

7474
def start(): Unit = {
7575
webUi.bind()
76-
scheduler.frameworkUrl = webUi.activeWebUiUrl
76+
scheduler.frameworkUrl = conf.get("spark.mesos.dispatcher.webui.url", webUi.activeWebUiUrl)
7777
scheduler.start()
7878
server.start()
7979
}

core/src/main/scala/org/apache/spark/deploy/mesos/MesosClusterDispatcherArguments.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private[mesos] class MesosClusterDispatcherArguments(args: Array[String], conf:
4747
port = value
4848
parse(tail)
4949

50-
case ("--webui-port" | "-p") :: IntParam(value) :: tail =>
50+
case ("--webui-port") :: IntParam(value) :: tail =>
5151
webUiPort = value
5252
parse(tail)
5353

core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/CoarseMesosSchedulerBackend.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ private[spark] class CoarseMesosSchedulerBackend(
149149
sc.sparkUser,
150150
sc.appName,
151151
sc.conf,
152-
sc.ui.map(_.appUIAddress))
152+
sc.conf.getOption("spark.mesos.driver.webui.url").orElse(sc.ui.map(_.appUIAddress))
153+
)
153154
startScheduler(driver)
154155
}
155156

core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackend.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ private[spark] class MesosSchedulerBackend(
7878
sc.sparkUser,
7979
sc.appName,
8080
sc.conf,
81-
sc.ui.map(_.appUIAddress))
81+
sc.conf.getOption("spark.mesos.driver.webui.url").orElse(sc.ui.map(_.appUIAddress))
82+
)
8283
startScheduler(driver)
8384
}
8485

core/src/test/scala/org/apache/spark/scheduler/cluster/mesos/CoarseMesosSchedulerBackendSuite.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,35 @@ class CoarseMesosSchedulerBackendSuite extends SparkFunSuite
208208
verify(driver, times(1)).killTask(createTaskId("0"))
209209
}
210210

211+
test("weburi is set in created scheduler driver") {
212+
setBackend()
213+
val taskScheduler = mock[TaskSchedulerImpl]
214+
when(taskScheduler.sc).thenReturn(sc)
215+
val driver = mock[SchedulerDriver]
216+
when(driver.start()).thenReturn(Protos.Status.DRIVER_RUNNING)
217+
val securityManager = mock[SecurityManager]
218+
219+
val backend = new CoarseMesosSchedulerBackend(taskScheduler, sc, "master", securityManager) {
220+
override protected def createSchedulerDriver(
221+
masterUrl: String,
222+
scheduler: Scheduler,
223+
sparkUser: String,
224+
appName: String,
225+
conf: SparkConf,
226+
webuiUrl: Option[String] = None,
227+
checkpoint: Option[Boolean] = None,
228+
failoverTimeout: Option[Double] = None,
229+
frameworkId: Option[String] = None): SchedulerDriver = {
230+
markRegistered()
231+
assert(webuiUrl.isDefined)
232+
assert(webuiUrl.get.equals("http://webui"))
233+
driver
234+
}
235+
}
236+
237+
backend.start()
238+
}
239+
211240
private def verifyDeclinedOffer(driver: SchedulerDriver,
212241
offerId: OfferID,
213242
filter: Boolean = false): Unit = {
@@ -316,6 +345,7 @@ class CoarseMesosSchedulerBackendSuite extends SparkFunSuite
316345
.setMaster("local[*]")
317346
.setAppName("test-mesos-dynamic-alloc")
318347
.setSparkHome("/path")
348+
.set("spark.mesos.driver.webui.url", "http://webui")
319349

320350
if (sparkConfVars != null) {
321351
for (attr <- sparkConfVars) {

core/src/test/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackendSuite.scala

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import scala.collection.JavaConverters._
2626
import scala.collection.mutable
2727
import scala.collection.mutable.ArrayBuffer
2828

29+
import org.apache.mesos.{Protos, Scheduler, SchedulerDriver}
2930
import org.apache.mesos.Protos._
3031
import org.apache.mesos.Protos.Value.Scalar
31-
import org.apache.mesos.SchedulerDriver
3232
import org.mockito.{ArgumentCaptor, Matchers}
3333
import org.mockito.Matchers._
3434
import org.mockito.Mockito._
@@ -42,6 +42,41 @@ import org.apache.spark.scheduler.cluster.ExecutorInfo
4242

4343
class MesosSchedulerBackendSuite extends SparkFunSuite with LocalSparkContext with MockitoSugar {
4444

45+
test("weburi is set in created scheduler driver") {
46+
val conf = new SparkConf
47+
conf.set("spark.mesos.driver.webui.url", "http://webui")
48+
conf.set("spark.app.name", "name1")
49+
50+
val sc = mock[SparkContext]
51+
when(sc.conf).thenReturn(conf)
52+
when(sc.sparkUser).thenReturn("sparkUser1")
53+
when(sc.appName).thenReturn("appName1")
54+
55+
val taskScheduler = mock[TaskSchedulerImpl]
56+
val driver = mock[SchedulerDriver]
57+
when(driver.start()).thenReturn(Protos.Status.DRIVER_RUNNING)
58+
59+
val backend = new MesosSchedulerBackend(taskScheduler, sc, "master") {
60+
override protected def createSchedulerDriver(
61+
masterUrl: String,
62+
scheduler: Scheduler,
63+
sparkUser: String,
64+
appName: String,
65+
conf: SparkConf,
66+
webuiUrl: Option[String] = None,
67+
checkpoint: Option[Boolean] = None,
68+
failoverTimeout: Option[Double] = None,
69+
frameworkId: Option[String] = None): SchedulerDriver = {
70+
markRegistered()
71+
assert(webuiUrl.isDefined)
72+
assert(webuiUrl.get.equals("http://webui"))
73+
driver
74+
}
75+
}
76+
77+
backend.start()
78+
}
79+
4580
test("Use configured mesosExecutor.cores for ExecutorInfo") {
4681
val mesosExecutorCores = 3
4782
val conf = new SparkConf

docs/running-on-mesos.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,22 @@ See the [configuration page](configuration.html) for information on Spark config
390390
</ul>
391391
</td>
392392
</tr>
393+
<tr>
394+
<td><code>spark.mesos.driver.webui.url</code></td>
395+
<td><code>(none)</code></td>
396+
<td>
397+
Set the Spark Mesos driver webui_url for interacting with the framework.
398+
If unset it will point to Spark's internal web UI.
399+
</td>
400+
</tr>
401+
<tr>
402+
<td><code>spark.mesos.dispatcher.webui.url</code></td>
403+
<td><code>(none)</code></td>
404+
<td>
405+
Set the Spark Mesos dispatcher webui_url for interacting with the framework.
406+
If unset it will point to Spark's internal web UI.
407+
</td>
408+
</tr>
393409
</table>
394410

395411
# Troubleshooting and Debugging

0 commit comments

Comments
 (0)