diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index 9ec25ae..4281ef8 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -1455,6 +1455,17 @@ private static void addDeprecatedKeys() { public static final String TIMELINE_SERVICE_PREFIX = YARN_PREFIX + "timeline-service."; + /** Comma seperated list of names for UIs hosted in the timeline server (For pluggable UIs)*/ + public static final String TIMELINE_SERVICE_UI_NAMES = + TIMELINE_SERVICE_PREFIX + "ui-names"; + + /** Relative web path that will serve up this UI (For pluggable UIs)*/ + public static final String TIMELINE_SERVICE_UI_WEB_PATH_PREFIX = + TIMELINE_SERVICE_PREFIX + "ui-web-path."; + + /** Path to war file or static content directory for this UI (For pluggable UIs)*/ + public static final String TIMELINE_SERVICE_UI_ON_DISK_PATH_PREFIX = + TIMELINE_SERVICE_PREFIX + "ui-on-disk-path."; // mark app-history related configs @Private as application history is going // to be integrated into the timeline service diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java index bda24aa..3de4c44 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java @@ -166,7 +166,7 @@ return this; } - public WebApp start(WebApp webapp) { + public WebApp build(WebApp webapp) { if (webapp == null) { webapp = new WebApp() { @Override @@ -271,8 +271,7 @@ public void setup() { webapp.setConf(conf); webapp.setHttpServer(server); - server.start(); - LOG.info("Web app /"+ name +" started at "+ server.getConnectorAddress(0).getPort()); + } catch (ClassNotFoundException e) { throw new WebAppException("Error starting http server", e); } catch (IOException e) { @@ -300,6 +299,18 @@ public WebApp start() { return start(null); } + public WebApp start(WebApp webapp) { + WebApp webApp = build(webapp); + HttpServer2 httpServer = webApp.httpServer(); + try { + httpServer.start(); + LOG.info("Web app /"+ name +" started at "+ httpServer.getConnectorAddress(0).getPort()); + } catch (IOException e) { + throw new WebAppException("Error starting http server", e); + } + return webApp; + } + private String inferHostClass() { String thisClass = this.getClass().getName(); Throwable t = new Throwable(); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml index b76defb..175f356 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml @@ -1825,6 +1825,12 @@ + Comma separated list of UIs that will be hosted + yarn.timeline-service.ui-names + + + + Default maximum number of retires for timeline servive client and value -1 means no limit. diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java index 0ec27d7..fed167d 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.http.HttpServer2; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.source.JvmMetrics; import org.apache.hadoop.security.AuthenticationFilterInitializer; @@ -54,6 +55,8 @@ import org.apache.hadoop.yarn.webapp.WebApp; import org.apache.hadoop.yarn.webapp.WebApps; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; +import org.mortbay.jetty.servlet.FilterHolder; +import org.mortbay.jetty.webapp.WebAppContext; import com.google.common.annotations.VisibleForTesting; @@ -223,6 +226,7 @@ private TimelineDataManager createTimelineDataManager(Configuration conf) { timelineStore, new TimelineACLsManager(conf)); } + @SuppressWarnings("unchecked") private void startWebApp() { Configuration conf = getConfig(); TimelineAuthenticationFilter.setTimelineDelegationTokenSecretManager( @@ -277,12 +281,35 @@ private void startWebApp() { WebAppUtils.getAHSWebAppURLWithoutScheme(conf)); LOG.info("Instantiating AHSWebApp at " + bindAddress); try { + AHSWebApp ahsWebApp = new AHSWebApp(timelineDataManager, ahsClientService); webApp = WebApps .$for("applicationhistory", ApplicationHistoryClientService.class, ahsClientService, "ws") - .with(conf).at(bindAddress).start( - new AHSWebApp(timelineDataManager, ahsClientService)); + .with(conf).withAttribute(YarnConfiguration.TIMELINE_SERVICE_WEBAPP_ADDRESS, + conf.get(YarnConfiguration.TIMELINE_SERVICE_WEBAPP_ADDRESS)).at(bindAddress).build(ahsWebApp); + HttpServer2 httpServer = webApp.httpServer(); + + String[] names = conf.getTrimmedStrings(YarnConfiguration.TIMELINE_SERVICE_UI_NAMES); + WebAppContext webAppContext = httpServer.getWebAppContext(); + + for (String name : names) { + String webPath = conf.get(YarnConfiguration.TIMELINE_SERVICE_UI_WEB_PATH_PREFIX + name); + String onDiskPath = conf.get(YarnConfiguration.TIMELINE_SERVICE_UI_ON_DISK_PATH_PREFIX + name); + WebAppContext uiWebAppContext = new WebAppContext(); + uiWebAppContext.setContextPath(webPath); + uiWebAppContext.setWar(onDiskPath); + final String[] ALL_URLS = { "/*" }; + FilterHolder[] filterHolders = webAppContext.getServletHandler().getFilters(); + for (FilterHolder filterHolder: filterHolders) { + if (!"guice".equals(filterHolder.getName())) { + HttpServer2.defineFilter(uiWebAppContext, filterHolder.getName(), + filterHolder.getClassName(), filterHolder.getInitParameters(), ALL_URLS); + } + } + httpServer.addContext(uiWebAppContext, true); + } + httpServer.start(); } catch (Exception e) { String msg = "AHSWebApp failed to start."; LOG.error(msg, e); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/TimelineServer.md hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/TimelineServer.md index 72b813a..de45efa 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/TimelineServer.md +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/TimelineServer.md @@ -185,6 +185,14 @@ selected if this policy is either of `HTTPS_ONLY` or `HTTP_AND_HTTPS`. | `yarn.timeline-service.client.retry-interval-ms` | The interval in milliseconds between retries for the timeline service client. Defaults to `1000`. | | `yarn.timeline-service.generic-application-history.max-applications` | The max number of applications could be fetched by using REST API or application history protocol and shown in timeline server web ui. Defaults to `10000`. | +#### UI Hosting Configuration + +The timeline service can host multiple UIs if enabled. The service can support both static web sites hosted in a directory or war files bundled. The web UI is then hosted on the timeline service HTTP port under the path configured. +| Configuration Property | Description | +|:---- |:---- | +| `yarn.timeline-service.ui-names` | Comma separated list of UIs that will be hosted. Defaults to `none`. | +| `yarn.timeline-service.ui-on-disk-path.$name` | For each of the ui-names, an on disk path should be specified to the directory service static content or the location of a web archive (war file). | +| `yarn.timeline-service.ui-web-path.$name` | For each of the ui-names, the web path should be specified relative to the Timeline server root. Paths should begin with a starting slash. | #### Security Configuration