diff --git a/core/src/main/resources/org/apache/spark/ui/static/historypage-template.html b/core/src/main/resources/org/apache/spark/ui/static/historypage-template.html
index 1fd6ef4a7125..42e2d9abdeb5 100644
--- a/core/src/main/resources/org/apache/spark/ui/static/historypage-template.html
+++ b/core/src/main/resources/org/apache/spark/ui/static/historypage-template.html
@@ -68,16 +68,16 @@
{{#applications}}
- | {{id}} |
+ {{id}} |
{{name}} |
{{#attempts}}
- {{attemptId}} |
+ {{attemptId}} |
{{startTime}} |
{{endTime}} |
{{duration}} |
{{sparkUser}} |
{{lastUpdated}} |
- Download |
+ Download |
{{/attempts}}
{{/applications}}
diff --git a/core/src/main/resources/org/apache/spark/ui/static/historypage.js b/core/src/main/resources/org/apache/spark/ui/static/historypage.js
index 2a32e18672a2..6c0ec8d5fce5 100644
--- a/core/src/main/resources/org/apache/spark/ui/static/historypage.js
+++ b/core/src/main/resources/org/apache/spark/ui/static/historypage.js
@@ -119,7 +119,11 @@ $(document).ready(function() {
}
}
- var data = {"applications": array}
+ var data = {
+ "uiroot": uiRoot,
+ "applications": array
+ }
+
$.get("static/historypage-template.html", function(template) {
historySummary.append(Mustache.render($(template).filter("#history-summary-template").html(),data));
var selector = "#history-summary-table";
diff --git a/core/src/main/resources/org/apache/spark/ui/static/webui.js b/core/src/main/resources/org/apache/spark/ui/static/webui.js
index e37307aa1f70..0fa1fcf25f8b 100644
--- a/core/src/main/resources/org/apache/spark/ui/static/webui.js
+++ b/core/src/main/resources/org/apache/spark/ui/static/webui.js
@@ -15,6 +15,12 @@
* limitations under the License.
*/
+var uiRoot = "";
+
+function setUIRoot(val) {
+ uiRoot = val;
+}
+
function collapseTablePageLoad(name, table){
if (window.localStorage.getItem(name) == "true") {
// Set it to false so that the click function can revert it
diff --git a/core/src/main/scala/org/apache/spark/ui/UIUtils.scala b/core/src/main/scala/org/apache/spark/ui/UIUtils.scala
index 66b097aa8166..57f6f2f0a9be 100644
--- a/core/src/main/scala/org/apache/spark/ui/UIUtils.scala
+++ b/core/src/main/scala/org/apache/spark/ui/UIUtils.scala
@@ -171,6 +171,7 @@ private[spark] object UIUtils extends Logging {
+
}
def vizHeaderNodes: Seq[Node] = {
diff --git a/core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala b/core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala
index a595bc174a31..715811a46f42 100644
--- a/core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala
+++ b/core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala
@@ -29,6 +29,8 @@ import com.codahale.metrics.Counter
import com.google.common.io.{ByteStreams, Files}
import org.apache.commons.io.{FileUtils, IOUtils}
import org.apache.hadoop.fs.{FileStatus, FileSystem, Path}
+import org.eclipse.jetty.proxy.ProxyServlet
+import org.eclipse.jetty.servlet.{ServletContextHandler, ServletHolder}
import org.json4s.JsonAST._
import org.json4s.jackson.JsonMethods
import org.json4s.jackson.JsonMethods._
@@ -258,8 +260,7 @@ class HistoryServerSuite extends SparkFunSuite with BeforeAndAfter with Matchers
getContentAndCode("foobar")._1 should be (HttpServletResponse.SC_NOT_FOUND)
}
- test("relative links are prefixed with uiRoot (spark.ui.proxyBase)") {
- val proxyBaseBeforeTest = System.getProperty("spark.ui.proxyBase")
+ test("static relative links are prefixed with uiRoot (spark.ui.proxyBase)") {
val uiRoot = Option(System.getenv("APPLICATION_WEB_PROXY_BASE")).getOrElse("/testwebproxybase")
val page = new HistoryPage(server)
val request = mock[HttpServletRequest]
@@ -267,7 +268,6 @@ class HistoryServerSuite extends SparkFunSuite with BeforeAndAfter with Matchers
// when
System.setProperty("spark.ui.proxyBase", uiRoot)
val response = page.render(request)
- System.setProperty("spark.ui.proxyBase", Option(proxyBaseBeforeTest).getOrElse(""))
// then
val urls = response \\ "@href" map (_.toString)
@@ -275,6 +275,80 @@ class HistoryServerSuite extends SparkFunSuite with BeforeAndAfter with Matchers
all (siteRelativeLinks) should startWith (uiRoot)
}
+ test("ajax rendered relative links are prefixed with uiRoot (spark.ui.proxyBase)") {
+ val uiRoot = "/testwebproxybase"
+ System.setProperty("spark.ui.proxyBase", uiRoot)
+
+ server.stop()
+
+ val conf = new SparkConf()
+ .set("spark.history.fs.logDirectory", logDir)
+ .set("spark.history.fs.update.interval", "0")
+ .set("spark.testing", "true")
+
+ provider = new FsHistoryProvider(conf)
+ provider.checkForLogs()
+ val securityManager = new SecurityManager(conf)
+
+ server = new HistoryServer(conf, provider, securityManager, 18080)
+ server.initialize()
+ server.bind()
+
+ val port = server.boundPort
+
+ val servlet = new ProxyServlet {
+ override def rewriteTarget(request: HttpServletRequest): String = {
+ // servlet acts like a proxy that redirects calls made on
+ // spark.ui.proxyBase context path to the normal servlet handlers operating off "/"
+ val sb = request.getRequestURL()
+
+ if (request.getQueryString() != null) {
+ sb.append(s"?${request.getQueryString()}")
+ }
+
+ val proxyidx = sb.indexOf(uiRoot)
+ sb.delete(proxyidx, proxyidx + uiRoot.length).toString
+ }
+ }
+
+ val contextHandler = new ServletContextHandler
+ val holder = new ServletHolder(servlet)
+ contextHandler.setContextPath(uiRoot)
+ contextHandler.addServlet(holder, "/")
+ server.attachHandler(contextHandler)
+
+ implicit val webDriver: WebDriver = new HtmlUnitDriver(true) {
+ getWebClient.getOptions.setThrowExceptionOnScriptError(false)
+ }
+
+ try {
+ val url = s"http://localhost:$port"
+
+ go to s"$url$uiRoot"
+
+ // expect the ajax call to finish in 5 seconds
+ implicitlyWait(org.scalatest.time.Span(5, org.scalatest.time.Seconds))
+
+ // once this findAll call returns, we know the ajax load of the table completed
+ findAll(ClassNameQuery("odd"))
+
+ val links = findAll(TagNameQuery("a"))
+ .map(_.attribute("href"))
+ .filter(_.isDefined)
+ .map(_.get)
+ .filter(_.startsWith(url)).toList
+
+ // there are atleast some URL links that were generated via javascript,
+ // and they all contain the spark.ui.proxyBase (uiRoot)
+ links.length should be > 4
+ all(links) should startWith(url + uiRoot)
+ } finally {
+ contextHandler.stop()
+ quit()
+ }
+
+ }
+
test("incomplete apps get refreshed") {
implicit val webDriver: WebDriver = new HtmlUnitDriver